1751 lines
44 KiB
C++
1751 lines
44 KiB
C++
|
|
#include "headers.hxx"
|
|
#include "global.hpp"
|
|
|
|
|
|
#include "Analisys.hpp"
|
|
#include "AnalisysResults.hpp"
|
|
#include "CSVDSReader.hpp"
|
|
#include "resource.h"
|
|
#include "AdsiHelpers.hpp"
|
|
#include "constants.hpp"
|
|
#include "dspecup.hpp"
|
|
|
|
|
|
|
|
|
|
Analisys::Analisys
|
|
(
|
|
const CSVDSReader& csvReader409_,
|
|
const CSVDSReader& csvReaderIntl_,
|
|
const String& ldapPrefix_,
|
|
const String& rootContainerDn_,
|
|
AnalisysResults &res,
|
|
const String &reportName_,//=L"",
|
|
void *caleeStruct_,//=NULL,
|
|
progressFunction stepIt_,//=NULL,
|
|
progressFunction totalSteps_//=NULL,
|
|
)
|
|
:
|
|
csvReader409(csvReader409_),
|
|
csvReaderIntl(csvReaderIntl_),
|
|
ldapPrefix(ldapPrefix_),
|
|
rootContainerDn(rootContainerDn_),
|
|
results(res),
|
|
reportName(reportName_),
|
|
caleeStruct(caleeStruct_),
|
|
stepIt(stepIt_),
|
|
totalSteps(totalSteps_)
|
|
{
|
|
LOG_CTOR(Analisys);
|
|
ASSERT(!ldapPrefix.empty());
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
};
|
|
|
|
|
|
// Analisys entry point
|
|
HRESULT
|
|
Analisys::run()
|
|
{
|
|
LOG_FUNCTION(Analisys::run);
|
|
|
|
setReplaceW2KStrs();
|
|
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
LongList locales;
|
|
for(long t=0;LOCALEIDS[t]!=0;t++)
|
|
{
|
|
locales.push_back(LOCALEIDS[t]);
|
|
}
|
|
locales.push_back(LOCALE409[0]);
|
|
|
|
if(totalSteps!=NULL)
|
|
{
|
|
// The cast bellow is for IA64 compilation since we know
|
|
// that locales.size() will fit in a long.
|
|
totalSteps(static_cast<long>(locales.size()),caleeStruct);
|
|
}
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
LongList::iterator begin=locales.begin();
|
|
LongList::iterator end=locales.end();
|
|
|
|
|
|
while(begin!=end)
|
|
{
|
|
long locale=*begin;
|
|
bool isPresent;
|
|
|
|
hr=dealWithContainer(locale,isPresent);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (isPresent)
|
|
{
|
|
hr=dealWithXPObjects(locale);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=dealWithW2KObjects(locale);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
|
|
if(stepIt!=NULL)
|
|
{
|
|
stepIt(1,caleeStruct);
|
|
}
|
|
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(!reportName.empty())
|
|
{
|
|
hr=createReport(reportName);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// add entry to result.createContainers if container is not present
|
|
// also returns flag isPresent
|
|
HRESULT
|
|
Analisys::dealWithContainer(
|
|
const long locale,
|
|
bool &isPresent)
|
|
{
|
|
LOG_FUNCTION(Analisys::dealWithContainer);
|
|
|
|
ASSERT(locale > 0);
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
do
|
|
{
|
|
String container = String::format(L"CN=%1!3x!,", locale);
|
|
String childContainerDn =ldapPrefix + container + rootContainerDn;
|
|
|
|
// Attempt to bind to the container.
|
|
|
|
SmartInterface<IADs> iads(0);
|
|
hr = AdsiOpenObject<IADs>(childContainerDn, iads);
|
|
if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
|
|
{
|
|
// The container object does not exist. This is possible because
|
|
// the user has manually removed the container, or because it
|
|
// was never created due to an aboted post-dcpromo import of the
|
|
// display specifiers when the forest root dc was first promoted.
|
|
|
|
results.createContainers.push_back(locale);
|
|
|
|
isPresent=false;
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
else if (FAILED(hr))
|
|
{
|
|
error=String::format(IDS_ERROR_BINDING_TO_CONTAINER,
|
|
childContainerDn.c_str());
|
|
break;
|
|
}
|
|
|
|
|
|
// At this point, the bind succeeded, so the child container exists.
|
|
// So now we want to examine objects in that container.
|
|
|
|
isPresent=true;
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// add entries to results.conflictingXPObjects or
|
|
// results.createXPObject as necessary
|
|
HRESULT
|
|
Analisys::dealWithXPObjects(const long locale)
|
|
{
|
|
LOG_FUNCTION(Analisys::dealWithXPObjects);
|
|
|
|
ASSERT(locale > 0);
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
for (
|
|
int i = 0;
|
|
*NEW_XP_OBJECTS[i]!=0;
|
|
++i
|
|
)
|
|
{
|
|
String objectName = NEW_XP_OBJECTS[i];
|
|
|
|
String objectPath =
|
|
ldapPrefix + L"CN=" + objectName + L"," +
|
|
String::format(L"CN=%1!3x!,", locale) + rootContainerDn;
|
|
|
|
SmartInterface<IADs> iads(0);
|
|
hr = AdsiOpenObject<IADs>(objectPath, iads);
|
|
if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
|
|
{
|
|
// The object does not exist. This is what we expect. We want
|
|
// to add the object in the repair phase.
|
|
ObjectId tempObj(locale,objectName);
|
|
results.createXPObjects.push_back(tempObj);
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
// The object already exists. We have a conflict.
|
|
ObjectId tempObj(locale,objectName);
|
|
results.conflictingXPObjects.push_back(tempObj);
|
|
}
|
|
else
|
|
{
|
|
|
|
error=String::format(
|
|
IDS_ERROR_BINDING_TO_OBJECT,
|
|
objectName.c_str(),
|
|
objectPath.c_str());
|
|
|
|
break;
|
|
}
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add entries to results.createW2KObjects
|
|
// and results.objectActions as necessary
|
|
HRESULT
|
|
Analisys::dealWithW2KObjects(const long locale)
|
|
{
|
|
LOG_FUNCTION(Analisys::dealWithW2KObjects);
|
|
ASSERT(locale >0);
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
for(
|
|
long i = 0;
|
|
*(CHANGE_LIST[i].object)!=0;
|
|
++i
|
|
)
|
|
{
|
|
String objectName = CHANGE_LIST[i].object;
|
|
String objectPath =
|
|
ldapPrefix + L"CN=" + objectName + L"," +
|
|
String::format(L"CN=%1!3x!,", locale) + rootContainerDn;
|
|
|
|
SmartInterface<IADs> iads(0);
|
|
hr = AdsiOpenObject<IADs>(objectPath, iads);
|
|
if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
|
|
{
|
|
// The object does not exist.
|
|
ObjectId tempObj(locale,objectName);
|
|
results.createW2KObjects.push_back(tempObj);
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
// At this point, the display specifier object exists. Determine if
|
|
// if has been touched since its creation.
|
|
|
|
SmartInterface<IDirectoryObject> iDirObj;
|
|
|
|
hr=iDirObj.AcquireViaQueryInterface(iads);
|
|
// hr = iads->QueryInterface(IID_IDirectoryObject,(void **)iDirObj);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr = checkChanges(locale,CHANGE_LIST[i],iDirObj);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
}
|
|
else
|
|
{
|
|
error=String::format(
|
|
IDS_ERROR_BINDING_TO_OBJECT,
|
|
objectName.c_str(),
|
|
objectPath.c_str());
|
|
|
|
break;
|
|
}
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
Analisys::checkChanges(
|
|
const long locale,
|
|
const sChangeList& changes,
|
|
IDirectoryObject *iDirObj)
|
|
{
|
|
LOG_FUNCTION(Analisys::checkChanges);
|
|
|
|
wchar_t *object=changes.object;
|
|
HRESULT hr=S_OK;
|
|
for(
|
|
long i = 0;
|
|
*(changes.changes[i].property)!=0;
|
|
++i)
|
|
{
|
|
struct sChange change=changes.changes[i];
|
|
switch(change.type)
|
|
{
|
|
case ADD_ALL_CSV_VALUES:
|
|
|
|
hr = addAllCsvValues
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case ADD_VALUE:
|
|
|
|
hr = addValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property,
|
|
change.value
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case REPLACE_W2K_MULTIPLE_VALUE:
|
|
|
|
hr = replaceW2KMultipleValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property,
|
|
change.value
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case REPLACE_W2K_SINGLE_VALUE:
|
|
|
|
hr = replaceW2KSingleValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property,
|
|
change.value
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case ADD_GUID:
|
|
|
|
hr = addGuid
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property,
|
|
change.value
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case REMOVE_GUID:
|
|
|
|
hr = removeGuid
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
change.property,
|
|
change.value
|
|
);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
}
|
|
|
|
LOG_HRESULT(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// adds ordAndGuid to the property if Guid is not already there.
|
|
HRESULT
|
|
Analisys::addGuid(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *ordAndGuid)
|
|
{
|
|
LOG_FUNCTION(Analisys::addGuid);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
String propertStr(property);
|
|
String ordAndGuidStr(ordAndGuid);
|
|
|
|
do
|
|
{
|
|
String guidFound;
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
propertStr,
|
|
ordAndGuidStr,
|
|
guidFound
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(ordAndGuidStr);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// adds all csv values still not on the property
|
|
HRESULT
|
|
Analisys::addAllCsvValues(
|
|
IDirectoryObject *iDirObj,
|
|
const long locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property)
|
|
{
|
|
LOG_FUNCTION(Analisys::addAllCsvValues);
|
|
|
|
HRESULT hr = S_OK;
|
|
const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
|
|
|
|
do
|
|
{
|
|
StringList values;
|
|
hr=csvReader.getCsvValues(locale,object,property,values);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (values.size()==0)
|
|
{
|
|
error=String::format(IDS_NO_CSV_VALUE,locale,object);
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
StringList::iterator begin=values.begin();
|
|
StringList::iterator end=values.end();
|
|
while(begin!=end)
|
|
{
|
|
hr=addValue(iDirObj,locale,object,property,begin->c_str());
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// adds value to the property if it is not already there.
|
|
HRESULT
|
|
Analisys::addValue(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *value)
|
|
{
|
|
LOG_FUNCTION(Analisys::addValue);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
String valueStr(value);
|
|
String propertyStr(property);
|
|
|
|
do
|
|
{
|
|
hr=isADValuePresent (
|
|
iDirObj,
|
|
propertyStr,
|
|
valueStr
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(value);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//Auxiliary function for replaceW2KSingleValue
|
|
// retrieves csvValue
|
|
HRESULT
|
|
Analisys::getCsvSingleValue
|
|
(
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
String &csvValue
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::getCsvReplacementValue);
|
|
|
|
const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
|
|
StringList XPCsvValues;
|
|
hr=csvReader.getCsvValues(locale,object,property,XPCsvValues);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
// we should have only one value in the csv
|
|
// since we can't distinguish the
|
|
// value we want to replace from others as
|
|
// in REPLACE_W2K_MULTIPLE_VALE
|
|
if(XPCsvValues.size() != 1)
|
|
{
|
|
error=String::format
|
|
(
|
|
IDS_NOT_ONE_CSV_VALUE,
|
|
XPCsvValues.size(),
|
|
csvReader.getFileName().c_str(),
|
|
locale,
|
|
object,
|
|
property
|
|
);
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
|
|
csvValue = *XPCsvValues.begin();
|
|
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// The idea of replaceW2KValue is replacing the W2K value
|
|
// for the Whistler. We also make sure we don't extraneous values.
|
|
HRESULT
|
|
Analisys::replaceW2KSingleValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::replaceW2KValue);
|
|
|
|
long index = *value;
|
|
String objectStr(object);
|
|
String propertyStr(property);
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
String XPCsvValue;
|
|
|
|
hr=getCsvSingleValue
|
|
(
|
|
locale,
|
|
object,
|
|
property,
|
|
XPCsvValue
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
// Retrieve W2KCsvValue from replaceW2KStrs
|
|
pair<long,long> tmpIndxLoc;
|
|
tmpIndxLoc.first=index;
|
|
tmpIndxLoc.second=locale;
|
|
String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc];
|
|
|
|
// There is nothing to do if the Whistler csv value
|
|
// is the same as it was in W2K
|
|
if (XPCsvValue.icompare(W2KCsvValue)==0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Now we might have a replacement to do since the value
|
|
// changed from W2K to Whistler
|
|
|
|
hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The Whistler value is already there
|
|
{
|
|
// We will remove any other value than the Whistler
|
|
hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,XPCsvValue);
|
|
break;
|
|
}
|
|
|
|
// Now we know that the Whistler value is not present
|
|
// and therefore we will add it if the W2K value is present
|
|
|
|
hr=isADValuePresent(iDirObj,propertyStr,W2KCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The W2K value is there.
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(XPCsvValue);
|
|
act.delValues.push_back(W2KCsvValue);
|
|
|
|
// remove all but the W2K that we removed in the previous line
|
|
hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,W2KCsvValue);
|
|
break;
|
|
}
|
|
|
|
// Now we know that neither Whistler nor W2K values are present
|
|
// If we have a value we will log that it is a custom value
|
|
|
|
String ADValue;
|
|
hr=getADFirstValue(iDirObj,propertyStr,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // We have a value
|
|
{
|
|
SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will remove any other value than the one we found
|
|
hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,ADValue);
|
|
break;
|
|
}
|
|
|
|
// Now we know that we don't have any values at all.
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(XPCsvValue);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
//Auxiliary function for replaceW2KMultipleValue
|
|
// retrieves csvValue and XPStart
|
|
HRESULT
|
|
Analisys::getCsvMultipleValue
|
|
(
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *value,
|
|
String &csvValue,
|
|
String &XPstart
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::getCsvReplacementValue);
|
|
|
|
const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
String sW2KXP(value+2); // +2 for index and semicollon
|
|
StringList lW2KXP;
|
|
size_t cnt=sW2KXP.tokenize(back_inserter(lW2KXP),L";");
|
|
XPstart=lW2KXP.back();
|
|
|
|
// We have the W2K and the XP start
|
|
ASSERT(cnt==2);
|
|
|
|
// Search the csv for the value starting with the XP string
|
|
hr=csvReader.getCsvValue(
|
|
locale,
|
|
object,
|
|
property,
|
|
XPstart.c_str(),
|
|
csvValue
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
// We should always find a csv value
|
|
if(hr == S_FALSE)
|
|
{
|
|
error=String::format(
|
|
IDS_VALUE_NOT_IN_CSV,
|
|
XPstart.c_str(),
|
|
locale,
|
|
object,
|
|
property,
|
|
csvReader.getFileName().c_str()
|
|
);
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// The idea of replaceW2KValue is replacing the W2K value
|
|
// for the Whistler. We also make sure we don't extraneous values.
|
|
HRESULT
|
|
Analisys::replaceW2KMultipleValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::replaceW2KValue);
|
|
|
|
long index = *value;
|
|
String objectStr(object);
|
|
String propertyStr(property);
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
String XPCsvValue,XPStart;
|
|
|
|
// Get the Whistler csv value and the start of the Whistler value
|
|
hr=getCsvMultipleValue
|
|
(
|
|
locale,
|
|
object,
|
|
property,
|
|
value,
|
|
XPCsvValue,
|
|
XPStart
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
// Retrieve W2KCsvValue from replaceW2KStrs
|
|
pair<long,long> tmpIndxLoc;
|
|
tmpIndxLoc.first=index;
|
|
tmpIndxLoc.second=locale;
|
|
String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc];
|
|
|
|
// There is nothing to do if the Whistler csv value
|
|
// is the same as it was in W2K
|
|
if (XPCsvValue.icompare(W2KCsvValue)==0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Now we might have a replacement to do since the value
|
|
// changed from W2K to Whistler
|
|
|
|
// First we should get the beginning of the W2K string
|
|
// for use in removeExtraneous calls
|
|
size_t pos=W2KCsvValue.find(L',');
|
|
String W2KStart;
|
|
// We only need to assert since the W2KStrs tool would
|
|
// detect any REPLACE_W2K_MULTIPLE_VALUE without a comma
|
|
ASSERT(pos != String::npos);
|
|
W2KStart=W2KCsvValue.substr(0,pos+1);
|
|
|
|
|
|
|
|
hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The Whistler value is already there
|
|
{
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
objectStr,
|
|
propertyStr,
|
|
XPCsvValue,
|
|
XPStart,
|
|
W2KStart
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
break;
|
|
}
|
|
|
|
// Now we know that the Whistler value is not present
|
|
// and therefore we will add it if the W2K value is present
|
|
|
|
hr=isADValuePresent(iDirObj,propertyStr,W2KCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The W2K value is there.
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(XPCsvValue);
|
|
act.delValues.push_back(W2KCsvValue);
|
|
|
|
// remove all but the W2K that we removed in the previous line
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
objectStr,
|
|
propertyStr,
|
|
W2KCsvValue,
|
|
XPStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Now we know that neither Whistler nor W2K values are present
|
|
// If we have a value starting like the W2K we will log that it
|
|
// is a custom value
|
|
|
|
|
|
String ADValue;
|
|
|
|
hr=isADStartValuePresent(iDirObj,propertyStr,W2KStart,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr==S_OK) // Something starts like the W2K csv value
|
|
{
|
|
SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will keep only the first custom value
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
objectStr,
|
|
propertyStr,
|
|
ADValue,
|
|
XPStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
|
|
|
|
// Now neither Whistler, W2K or W2KStart are present
|
|
if ( XPStart.icompare(W2KStart) != 0 )
|
|
{
|
|
// We have to check the XPStart as well
|
|
|
|
hr=isADStartValuePresent(iDirObj,propertyStr,XPStart,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // Something starts like the Whistler csv value
|
|
{
|
|
SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will keep only the first custom value
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
objectStr,
|
|
propertyStr,
|
|
ADValue,
|
|
XPStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now we know that there are no values starting like
|
|
// the Whistler or W2K csv values so we have to add
|
|
// the Whistler value
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(XPCsvValue);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// removes ordAndGuid from the property if Guid is there.
|
|
HRESULT
|
|
Analisys::removeGuid(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const wchar_t *object,
|
|
const wchar_t *property,
|
|
const wchar_t *ordAndGuid)
|
|
{
|
|
|
|
LOG_FUNCTION(Analisys::removeGuid);
|
|
|
|
HRESULT hr = S_OK;
|
|
String propertStr(property);
|
|
String ordAndGuidStr(ordAndGuid);
|
|
|
|
do
|
|
{
|
|
String guidFound;
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
propertStr,
|
|
ordAndGuidStr,
|
|
guidFound
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.delValues.push_back(guidFound);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//called from RwplaceW2KMultipleValue to remove all values
|
|
// starting with start1 or start2 other than keeper
|
|
HRESULT
|
|
Analisys::removeExtraneous
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &keeper,
|
|
const String &start1,
|
|
const String &start2
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::removeExtraneous);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
for (
|
|
long val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++, pAttrInfo->pADsValues++
|
|
)
|
|
{
|
|
wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString;
|
|
|
|
if ( _wcsicmp(valueAD,keeper.c_str())!=0 &&
|
|
(
|
|
_wcsnicmp(valueAD,start1.c_str(),start1.size())==0 ||
|
|
_wcsnicmp(valueAD,start2.c_str(),start2.size())==0
|
|
)
|
|
)
|
|
{
|
|
String value=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.extraneousValues[tempObj][property];
|
|
act.delValues.push_back(value);
|
|
}
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// called from RwplaceW2KSingleValue to remove all values
|
|
// other than keeper
|
|
HRESULT
|
|
Analisys::removeExtraneous
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &keeper
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::removeExtraneous);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
for (
|
|
long val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++, pAttrInfo->pADsValues++
|
|
)
|
|
{
|
|
wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString;
|
|
|
|
if ( _wcsicmp(valueAD,keeper.c_str())!=0 )
|
|
{
|
|
String value=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.extraneousValues[tempObj][property];
|
|
act.delValues.push_back(value);
|
|
}
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// if any value exists in the AD with the same guid as guidValue
|
|
// it is returned in guidFound, otherwise S_FALSE is returned
|
|
HRESULT
|
|
Analisys::getADGuid
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &guidValue,
|
|
String &guidFound
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::getADGuid);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
size_t pos=guidValue.find(L',');
|
|
ASSERT(pos!=String::npos);
|
|
|
|
String guid=guidValue.substr(pos+1);
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
// If there are no values we finish the search
|
|
hr=S_FALSE;
|
|
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
for (
|
|
long val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++, pAttrInfo->pADsValues++
|
|
)
|
|
{
|
|
|
|
wchar_t *guidAD=wcschr(pAttrInfo->pADsValues->CaseIgnoreString,L',');
|
|
if(guidAD != NULL)
|
|
{
|
|
guidAD++;
|
|
|
|
if (_wcsicmp(guid.c_str(),guidAD)==0)
|
|
{
|
|
guidFound=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// returns S_OK if value is present or S_FALSE otherwise
|
|
HRESULT
|
|
Analisys::isADValuePresent
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::isADValuePresent);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
hr=S_FALSE;
|
|
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (
|
|
long val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++, pAttrInfo->pADsValues++
|
|
)
|
|
{
|
|
wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
if (_wcsicmp(value.c_str(),valueAD)==0)
|
|
{
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// retrieves the first value starting with valueStart
|
|
// from the Active Directory
|
|
// If no value is found S_FALSE is returned.
|
|
HRESULT
|
|
Analisys::isADStartValuePresent
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &valueStart,
|
|
String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::isADStartValuePresent);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
value.erase();
|
|
|
|
hr = S_FALSE;
|
|
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
|
|
}
|
|
|
|
for (
|
|
long val=0;
|
|
(val < pAttrInfo->dwNumValues);
|
|
val++, pAttrInfo->pADsValues++
|
|
)
|
|
{
|
|
wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
if (_wcsnicmp(valueStart.c_str(),valueAD,valueStart.size())==0)
|
|
{
|
|
value=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// retrieves the first value starting with valueStart
|
|
// from the Active Directory
|
|
// If no value is found S_FALSE is returned.
|
|
HRESULT
|
|
Analisys::getADFirstValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::getADFirstValue);
|
|
|
|
DWORD dwReturn;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
value=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate an ObjectIdList
|
|
HRESULT
|
|
Analisys::reportObjects
|
|
(
|
|
HANDLE file,
|
|
const ObjectIdList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::reportObjects);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
ObjectIdList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_OBJECT_FORMAT,
|
|
begin->object.c_str(),
|
|
begin->locale
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate a LongList
|
|
HRESULT
|
|
Analisys::reportContainers
|
|
(
|
|
HANDLE file,
|
|
const LongList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::reportContainers);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
LongList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_CONTAINER_FORMAT,
|
|
*begin
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate a SingleValueList
|
|
HRESULT
|
|
Analisys::reportValues
|
|
(
|
|
HANDLE file,
|
|
const SingleValueList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::reportContainers);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
SingleValueList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_VALUE_FORMAT,
|
|
begin->value.c_str(),
|
|
begin->locale,
|
|
begin->object.c_str(),
|
|
begin->property.c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate ObjectActions
|
|
HRESULT
|
|
Analisys::reportActions
|
|
(
|
|
HANDLE file,
|
|
const ObjectActions &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analisys::reportActions);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
ObjectActions::const_iterator beginObj=list.begin();
|
|
ObjectActions::const_iterator endObj=list.end();
|
|
|
|
while(beginObj!=endObj)
|
|
{
|
|
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_OBJECT_FORMAT,
|
|
beginObj->first.object.c_str(),
|
|
beginObj->first.locale
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
PropertyActions::iterator beginAct=beginObj->second.begin();
|
|
PropertyActions::iterator endAct=beginObj->second.end();
|
|
|
|
while(beginAct!=endAct)
|
|
{
|
|
|
|
StringList::iterator
|
|
beginDel = beginAct->second.delValues.begin();
|
|
StringList::iterator
|
|
endDel = beginAct->second.delValues.end();
|
|
while(beginDel!=endDel)
|
|
{
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_DEL_VALUE_FORMAT,
|
|
beginAct->first.c_str(),
|
|
beginDel->c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginDel++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
|
|
|
|
|
|
StringList::iterator
|
|
beginAdd = beginAct->second.addValues.begin();
|
|
StringList::iterator
|
|
endAdd = beginAct->second.addValues.end();
|
|
while(beginAdd!=endAdd)
|
|
{
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_ADD_VALUE_FORMAT,
|
|
beginAct->first.c_str(),
|
|
beginAdd->c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginAdd++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
|
|
|
|
beginAct++;
|
|
} // while(beginAct!=endAct)
|
|
BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
|
|
|
|
beginObj++;
|
|
} // while(beginObj!=endObj)
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Create the report from the AnalisysResults
|
|
HRESULT
|
|
Analisys::createReport(const String& reportName)
|
|
{
|
|
LOG_FUNCTION(Analisys::createReport);
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
hr=FS::CreateFile(reportName,
|
|
file,
|
|
GENERIC_WRITE);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
error=String::format(IDS_COULD_NOT_CREATE_FILE,reportName.c_str());
|
|
break;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
hr=FS::WriteLine(file,String::load(IDS_RPT_HEADER));
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
hr=reportActions (
|
|
file,
|
|
results.extraneousValues,
|
|
String::load(IDS_RPT_EXTRANEOUS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
|
|
hr=reportValues (
|
|
file,
|
|
results.customizedValues,
|
|
String::load(IDS_RPT_CUSTOMIZED)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects (
|
|
file,
|
|
results.conflictingXPObjects,
|
|
String::load(IDS_RPT_CONFLICTINGXP)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportActions (
|
|
file,
|
|
results.objectActions,
|
|
String::load(IDS_RPT_ACTIONS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects (
|
|
file,
|
|
results.createW2KObjects,
|
|
String::load(IDS_RPT_CREATEW2K)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects (
|
|
file,
|
|
results.createXPObjects,
|
|
String::load(IDS_RPT_CREATEXP)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportContainers(
|
|
file,
|
|
results.createContainers,
|
|
String::load(IDS_RPT_CONTAINERS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
} while(0);
|
|
|
|
CloseHandle(file);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|