1038 lines
20 KiB
C++
1038 lines
20 KiB
C++
#include "StdAfx.h"
|
|
#include "ADMTScript.h"
|
|
#include "MigrationBase.h"
|
|
|
|
#include <LM.h>
|
|
|
|
#include "Error.h"
|
|
#include "VarSetAccounts.h"
|
|
#include "VarSetServers.h"
|
|
#include "FixHierarchy.h"
|
|
|
|
using namespace _com_util;
|
|
|
|
|
|
namespace MigrationBase
|
|
{
|
|
|
|
|
|
void GetNamesFromData(VARIANT& vntData, StringSet& setNames);
|
|
void GetNamesFromVariant(VARIANT* pvnt, StringSet& setNames);
|
|
void GetNamesFromString(BSTR bstr, StringSet& setNames);
|
|
void GetNamesFromStringArray(SAFEARRAY* psa, StringSet& setNames);
|
|
void GetNamesFromVariantArray(SAFEARRAY* psa, StringSet& setNames);
|
|
|
|
void GetNamesFromFile(VARIANT& vntData, StringSet& setNames);
|
|
void GetNamesFromFile(LPCTSTR pszFileName, StringSet& setNames);
|
|
void GetNamesFromStringA(LPCSTR pchString, DWORD cchString, StringSet& setNames);
|
|
void GetNamesFromStringW(LPCWSTR pchString, DWORD cchString, StringSet& setNames);
|
|
|
|
_bstr_t RemoveTrailingDollarSign(LPCTSTR pszName);
|
|
|
|
|
|
}
|
|
|
|
|
|
using namespace MigrationBase;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// MigrationBase Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CMigrationBase::CMigrationBase() :
|
|
m_nRecurseMaintain(0),
|
|
m_Mutex(ADMT_MUTEX)
|
|
{
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CMigrationBase::~CMigrationBase()
|
|
{
|
|
}
|
|
|
|
|
|
// InitSourceDomainAndContainer Method
|
|
|
|
void CMigrationBase::InitSourceDomainAndContainer()
|
|
{
|
|
m_SourceDomain.Initialize(m_spInternal->SourceDomain);
|
|
m_SourceContainer = m_SourceDomain.GetContainer(m_spInternal->SourceOu);
|
|
}
|
|
|
|
|
|
// InitTargetDomainAndContainer Method
|
|
|
|
void CMigrationBase::InitTargetDomainAndContainer()
|
|
{
|
|
m_TargetDomain.Initialize(m_spInternal->TargetDomain);
|
|
m_TargetContainer = m_TargetDomain.GetContainer(m_spInternal->TargetOu);
|
|
|
|
// verify target domain is in native mode
|
|
|
|
if (m_TargetDomain.NativeMode() == false)
|
|
{
|
|
AdmtThrowError(
|
|
GUID_NULL, GUID_NULL,
|
|
E_INVALIDARG, IDS_E_TARGET_DOMAIN_NOT_NATIVE_MODE,
|
|
(LPCTSTR)m_TargetDomain.Name()
|
|
);
|
|
}
|
|
|
|
VerifyTargetContainerPathLength();
|
|
}
|
|
|
|
|
|
// VerifyInterIntraForest Method
|
|
|
|
void CMigrationBase::VerifyInterIntraForest()
|
|
{
|
|
// if the source and target domains have the same forest name then they are intra-forest
|
|
|
|
bool bIntraForest = m_spInternal->IntraForest ? true : false;
|
|
|
|
if (m_SourceDomain.ForestName() == m_TargetDomain.ForestName())
|
|
{
|
|
// intra-forest must be set to true to match the domains
|
|
|
|
if (!bIntraForest)
|
|
{
|
|
AdmtThrowError(
|
|
GUID_NULL, GUID_NULL,
|
|
E_INVALIDARG, IDS_E_NOT_INTER_FOREST,
|
|
(LPCTSTR)m_SourceDomain.Name(), (LPCTSTR)m_TargetDomain.Name()
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// intra-forest must be set to false to match the domains
|
|
|
|
if (bIntraForest)
|
|
{
|
|
AdmtThrowError(
|
|
GUID_NULL, GUID_NULL,
|
|
E_INVALIDARG, IDS_E_NOT_INTRA_FOREST,
|
|
(LPCTSTR)m_SourceDomain.Name(), (LPCTSTR)m_TargetDomain.Name()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// DoOption Method
|
|
|
|
void CMigrationBase::DoOption(long lOptions, VARIANT& vntInclude, VARIANT& vntExclude)
|
|
{
|
|
m_setIncludeNames.clear();
|
|
m_setExcludeNames.clear();
|
|
|
|
InitRecurseMaintainOption(lOptions);
|
|
|
|
GetExcludeNames(vntExclude, m_setExcludeNames);
|
|
|
|
switch (lOptions & 0xFF)
|
|
{
|
|
case admtNone:
|
|
{
|
|
DoNone();
|
|
break;
|
|
}
|
|
case admtData:
|
|
{
|
|
GetNamesFromData(vntInclude, m_setIncludeNames);
|
|
DoNames();
|
|
break;
|
|
}
|
|
case admtFile:
|
|
{
|
|
GetNamesFromFile(vntInclude, m_setIncludeNames);
|
|
DoNames();
|
|
break;
|
|
}
|
|
case admtDomain:
|
|
{
|
|
m_setIncludeNames.clear();
|
|
DoDomain();
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_OPTION);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// DoNone Method
|
|
|
|
void CMigrationBase::DoNone()
|
|
{
|
|
}
|
|
|
|
|
|
// DoNames Method
|
|
|
|
void CMigrationBase::DoNames()
|
|
{
|
|
}
|
|
|
|
|
|
// DoDomain Method
|
|
|
|
void CMigrationBase::DoDomain()
|
|
{
|
|
}
|
|
|
|
|
|
// InitRecurseMaintainOption Method
|
|
|
|
void CMigrationBase::InitRecurseMaintainOption(long lOptions)
|
|
{
|
|
switch (lOptions & 0xFF)
|
|
{
|
|
case admtData:
|
|
case admtFile:
|
|
{
|
|
if (lOptions & 0xFF00)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_DATA_OPTION_FLAGS_NOT_ALLOWED);
|
|
}
|
|
|
|
m_nRecurseMaintain = 0;
|
|
break;
|
|
}
|
|
case admtDomain:
|
|
{
|
|
m_nRecurseMaintain = 0;
|
|
|
|
if (lOptions & admtRecurse)
|
|
{
|
|
++m_nRecurseMaintain;
|
|
|
|
if (lOptions & admtMaintainHierarchy)
|
|
{
|
|
++m_nRecurseMaintain;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
m_nRecurseMaintain = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetExcludeNames Method
|
|
|
|
void CMigrationBase::GetExcludeNames(VARIANT& vntExclude, StringSet& setExcludeNames)
|
|
{
|
|
try
|
|
{
|
|
switch (V_VT(&vntExclude))
|
|
{
|
|
case VT_EMPTY:
|
|
case VT_ERROR:
|
|
{
|
|
setExcludeNames.clear();
|
|
break;
|
|
}
|
|
case VT_BSTR:
|
|
{
|
|
GetNamesFromFile(V_BSTR(&vntExclude), setExcludeNames);
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_BYREF:
|
|
{
|
|
BSTR* pbstr = V_BSTRREF(&vntExclude);
|
|
|
|
if (pbstr)
|
|
{
|
|
GetNamesFromFile(*pbstr, setExcludeNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_ARRAY:
|
|
{
|
|
GetNamesFromStringArray(V_ARRAY(&vntExclude), setExcludeNames);
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_ARRAY|VT_BYREF:
|
|
{
|
|
SAFEARRAY** ppsa = V_ARRAYREF(&vntExclude);
|
|
|
|
if (ppsa)
|
|
{
|
|
GetNamesFromStringArray(*ppsa, setExcludeNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_BYREF:
|
|
{
|
|
VARIANT* pvnt = V_VARIANTREF(&vntExclude);
|
|
|
|
if (pvnt)
|
|
{
|
|
GetExcludeNames(*pvnt, setExcludeNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_ARRAY:
|
|
{
|
|
GetNamesFromVariantArray(V_ARRAY(&vntExclude), setExcludeNames);
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_ARRAY|VT_BYREF:
|
|
{
|
|
SAFEARRAY** ppsa = V_ARRAYREF(&vntExclude);
|
|
|
|
if (ppsa)
|
|
{
|
|
GetNamesFromVariantArray(*ppsa, setExcludeNames);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (_com_error& ce)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_INVALID_EXCLUDE_DATA_TYPE);
|
|
}
|
|
catch (...)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_INVALID_EXCLUDE_DATA_TYPE);
|
|
}
|
|
}
|
|
|
|
|
|
// FillInVarSetForUsers Method
|
|
|
|
void CMigrationBase::FillInVarSetForUsers(CDomainAccounts& rUsers, CVarSet& rVarSet)
|
|
{
|
|
CVarSetAccounts aAccounts(rVarSet);
|
|
|
|
for (CDomainAccounts::iterator it = rUsers.begin(); it != rUsers.end(); it++)
|
|
{
|
|
aAccounts.AddAccount(_T("User"), it->GetADsPath(), it->GetName(), it->GetUserPrincipalName());
|
|
}
|
|
}
|
|
|
|
|
|
// FillInVarSetForGroups Method
|
|
|
|
void CMigrationBase::FillInVarSetForGroups(CDomainAccounts& rGroups, CVarSet& rVarSet)
|
|
{
|
|
CVarSetAccounts aAccounts(rVarSet);
|
|
|
|
for (CDomainAccounts::iterator it = rGroups.begin(); it != rGroups.end(); it++)
|
|
{
|
|
aAccounts.AddAccount(_T("Group"), it->GetADsPath(), it->GetName());
|
|
}
|
|
}
|
|
|
|
|
|
// FillInVarSetForComputers Method
|
|
|
|
void CMigrationBase::FillInVarSetForComputers(CDomainAccounts& rComputers, bool bMigrateOnly, bool bMoveToTarget, bool bReboot, long lRebootDelay, CVarSet& rVarSet)
|
|
{
|
|
CVarSetAccounts aAccounts(rVarSet);
|
|
CVarSetServers aServers(rVarSet);
|
|
|
|
for (CDomainAccounts::iterator it = rComputers.begin(); it != rComputers.end(); it++)
|
|
{
|
|
// remove trailing '$'
|
|
// ADMT doesn't accept true SAM account name
|
|
|
|
_bstr_t strName = RemoveTrailingDollarSign(it->GetSamAccountName());
|
|
|
|
aAccounts.AddAccount(_T("Computer"), strName);
|
|
aServers.AddServer(strName, bMigrateOnly, bMoveToTarget, bReboot, lRebootDelay);
|
|
}
|
|
}
|
|
|
|
|
|
// VerifyRenameConflictPrefixSuffixValid Method
|
|
|
|
void CMigrationBase::VerifyRenameConflictPrefixSuffixValid()
|
|
{
|
|
int nTotalPrefixSuffixLength = 0;
|
|
|
|
long lRenameOption = m_spInternal->RenameOption;
|
|
|
|
if ((lRenameOption == admtRenameWithPrefix) || (lRenameOption == admtRenameWithSuffix))
|
|
{
|
|
_bstr_t strPrefixSuffix = m_spInternal->RenamePrefixOrSuffix;
|
|
|
|
nTotalPrefixSuffixLength += strPrefixSuffix.length();
|
|
}
|
|
|
|
long lConflictOption = m_spInternal->ConflictOptions & 0x0F;
|
|
|
|
if ((lConflictOption == admtRenameConflictingWithSuffix) || (lConflictOption == admtRenameConflictingWithPrefix))
|
|
{
|
|
_bstr_t strPrefixSuffix = m_spInternal->ConflictPrefixOrSuffix;
|
|
|
|
nTotalPrefixSuffixLength += strPrefixSuffix.length();
|
|
}
|
|
|
|
if (nTotalPrefixSuffixLength > MAXIMUM_PREFIX_SUFFIX_LENGTH)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_PREFIX_SUFFIX_TOO_LONG, MAXIMUM_PREFIX_SUFFIX_LENGTH);
|
|
}
|
|
}
|
|
|
|
|
|
// VerifyCanAddSidHistory Method
|
|
|
|
void CMigrationBase::VerifyCanAddSidHistory()
|
|
{
|
|
#define F_WORKS 0x00000000
|
|
#define F_WRONGOS 0x00000001
|
|
#define F_NO_REG_KEY 0x00000002
|
|
#define F_NO_AUDITING_SOURCE 0x00000004
|
|
#define F_NO_AUDITING_TARGET 0x00000008
|
|
#define F_NO_LOCAL_GROUP 0x00000010
|
|
|
|
try
|
|
{
|
|
long lErrorFlags = 0;
|
|
|
|
IAccessCheckerPtr spAccessChecker(__uuidof(AccessChecker));
|
|
|
|
spAccessChecker->CanUseAddSidHistory(m_SourceDomain.Name(), m_TargetDomain.Name(), &lErrorFlags);
|
|
|
|
if (lErrorFlags != 0)
|
|
{
|
|
_bstr_t strError;
|
|
|
|
CComBSTR str;
|
|
|
|
if (lErrorFlags & F_NO_AUDITING_SOURCE)
|
|
{
|
|
str.LoadString(IDS_E_NO_AUDITING_SOURCE);
|
|
strError += str.operator BSTR();
|
|
}
|
|
|
|
if (lErrorFlags & F_NO_AUDITING_TARGET)
|
|
{
|
|
str.LoadString(IDS_E_NO_AUDITING_TARGET);
|
|
strError += str.operator BSTR();
|
|
}
|
|
|
|
if (lErrorFlags & F_NO_LOCAL_GROUP)
|
|
{
|
|
str.LoadString(IDS_E_NO_SID_HISTORY_LOCAL_GROUP);
|
|
strError += str.operator BSTR();
|
|
}
|
|
|
|
if (lErrorFlags & F_NO_REG_KEY)
|
|
{
|
|
str.LoadString(IDS_E_NO_SID_HISTORY_REGISTRY_ENTRY);
|
|
strError += str.operator BSTR();
|
|
}
|
|
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_SID_HISTORY_CONFIGURATION, (LPCTSTR)strError);
|
|
}
|
|
}
|
|
catch (_com_error& ce)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, ce, IDS_E_CAN_ADD_SID_HISTORY);
|
|
}
|
|
catch (...)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_CAN_ADD_SID_HISTORY);
|
|
}
|
|
}
|
|
|
|
|
|
// VerifyTargetContainerPathLength Method
|
|
|
|
void CMigrationBase::VerifyTargetContainerPathLength()
|
|
{
|
|
_bstr_t strPath = GetTargetContainer().GetPath();
|
|
|
|
if (strPath.length() > 999)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_TARGET_CONTAINER_PATH_TOO_LONG);
|
|
}
|
|
}
|
|
|
|
|
|
// VerifyPasswordServer Method
|
|
|
|
void CMigrationBase::VerifyPasswordOption()
|
|
{
|
|
if (m_spInternal->PasswordOption == admtCopyPassword)
|
|
{
|
|
_bstr_t strServer = m_spInternal->PasswordServer;
|
|
|
|
// a password server must be specified for copy password option
|
|
|
|
if (strServer.length() == 0)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_PASSWORD_DC_NOT_SPECIFIED);
|
|
}
|
|
|
|
//
|
|
// verify that password server exists and is a domain controller
|
|
//
|
|
|
|
_bstr_t strPrefixedServer;
|
|
|
|
if (_tcsncmp(strServer, _T("\\\\"), 2) == 0)
|
|
{
|
|
strPrefixedServer = strServer;
|
|
}
|
|
else
|
|
{
|
|
strPrefixedServer = _T("\\\\") + strServer;
|
|
}
|
|
|
|
PSERVER_INFO_101 psiInfo;
|
|
|
|
NET_API_STATUS nasStatus = NetServerGetInfo(strPrefixedServer, 101, (LPBYTE*)&psiInfo);
|
|
|
|
if (nasStatus != NERR_Success)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, HRESULT_FROM_WIN32(nasStatus), IDS_E_PASSWORD_DC_NOT_FOUND, (LPCTSTR)strServer);
|
|
}
|
|
|
|
UINT uMsgId = 0;
|
|
|
|
if (psiInfo->sv101_platform_id != PLATFORM_ID_NT)
|
|
{
|
|
uMsgId = IDS_E_PASSWORD_DC_NOT_NT;
|
|
}
|
|
else if (!(psiInfo->sv101_type & SV_TYPE_DOMAIN_CTRL) && !(psiInfo->sv101_type & SV_TYPE_DOMAIN_BAKCTRL))
|
|
{
|
|
uMsgId = IDS_E_PASSWORD_DC_NOT_DC;
|
|
}
|
|
|
|
NetApiBufferFree(psiInfo);
|
|
|
|
if (uMsgId)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, uMsgId, (LPCTSTR)strServer);
|
|
}
|
|
|
|
//
|
|
// verify that password server is configured properly
|
|
//
|
|
|
|
IPasswordMigrationPtr spPasswordMigration(__uuidof(PasswordMigration));
|
|
|
|
spPasswordMigration->EstablishSession(strServer, m_TargetDomain.DomainControllerName());
|
|
}
|
|
}
|
|
|
|
|
|
// PerformMigration Method
|
|
|
|
void CMigrationBase::PerformMigration(CVarSet& rVarSet)
|
|
{
|
|
IPerformMigrationTaskPtr spMigrator(__uuidof(Migrator));
|
|
|
|
try
|
|
{
|
|
spMigrator->PerformMigrationTask(IUnknownPtr(rVarSet.GetInterface()), 0);
|
|
}
|
|
catch (_com_error& ce)
|
|
{
|
|
if (ce.Error() == MIGRATOR_E_PROCESSES_STILL_RUNNING)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_ADMT_PROCESS_RUNNING);
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// FixObjectsInHierarchy Method
|
|
|
|
void CMigrationBase::FixObjectsInHierarchy(LPCTSTR pszType)
|
|
{
|
|
CFixObjectsInHierarchy fix;
|
|
|
|
fix.SetObjectType(pszType);
|
|
|
|
long lOptions = m_spInternal->ConflictOptions;
|
|
long lOption = lOptions & 0x0F;
|
|
long lFlags = lOptions & 0xF0;
|
|
|
|
fix.SetFixReplaced((lOption == admtReplaceConflicting) && (lFlags & admtMoveReplacedAccounts));
|
|
|
|
fix.SetSourceContainerPath(m_SourceContainer.GetPath());
|
|
fix.SetTargetContainerPath(m_TargetContainer.GetPath());
|
|
|
|
fix.FixObjects();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
namespace MigrationBase
|
|
{
|
|
|
|
|
|
// GetNamesFromData Method
|
|
|
|
void GetNamesFromData(VARIANT& vntData, StringSet& setNames)
|
|
{
|
|
try
|
|
{
|
|
GetNamesFromVariant(&vntData, setNames);
|
|
}
|
|
catch (_com_error& ce)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_INVALID_DATA_OPTION_DATA_TYPE);
|
|
}
|
|
catch (...)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_INVALID_DATA_OPTION_DATA_TYPE);
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromVariant Method
|
|
|
|
void GetNamesFromVariant(VARIANT* pvntData, StringSet& setNames)
|
|
{
|
|
switch (V_VT(pvntData))
|
|
{
|
|
case VT_BSTR:
|
|
{
|
|
GetNamesFromString(V_BSTR(pvntData), setNames);
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_BYREF:
|
|
{
|
|
BSTR* pbstr = V_BSTRREF(pvntData);
|
|
|
|
if (pbstr)
|
|
{
|
|
GetNamesFromString(*pbstr, setNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_ARRAY:
|
|
{
|
|
GetNamesFromStringArray(V_ARRAY(pvntData), setNames);
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_ARRAY|VT_BYREF:
|
|
{
|
|
SAFEARRAY** ppsa = V_ARRAYREF(pvntData);
|
|
|
|
if (ppsa)
|
|
{
|
|
GetNamesFromStringArray(*ppsa, setNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_BYREF:
|
|
{
|
|
VARIANT* pvnt = V_VARIANTREF(pvntData);
|
|
|
|
if (pvnt)
|
|
{
|
|
GetNamesFromVariant(pvnt, setNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_ARRAY:
|
|
{
|
|
GetNamesFromVariantArray(V_ARRAY(pvntData), setNames);
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_ARRAY|VT_BYREF:
|
|
{
|
|
SAFEARRAY** ppsa = V_ARRAYREF(pvntData);
|
|
|
|
if (ppsa)
|
|
{
|
|
GetNamesFromVariantArray(*ppsa, setNames);
|
|
}
|
|
break;
|
|
}
|
|
case VT_EMPTY:
|
|
{
|
|
// ignore empty variants
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromString Method
|
|
|
|
void GetNamesFromString(BSTR bstr, StringSet& setNames)
|
|
{
|
|
if (bstr)
|
|
{
|
|
UINT cch = SysStringLen(bstr);
|
|
|
|
if (cch > 0)
|
|
{
|
|
GetNamesFromStringW(bstr, cch, setNames);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromStringArray Method
|
|
|
|
void GetNamesFromStringArray(SAFEARRAY* psa, StringSet& setNames)
|
|
{
|
|
BSTR* pbstr;
|
|
|
|
HRESULT hr = SafeArrayAccessData(psa, (void**)&pbstr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
try
|
|
{
|
|
UINT uDimensionCount = psa->cDims;
|
|
|
|
for (UINT uDimension = 0; uDimension < uDimensionCount; uDimension++)
|
|
{
|
|
UINT uElementCount = psa->rgsabound[uDimension].cElements;
|
|
|
|
for (UINT uElement = 0; uElement < uElementCount; uElement++)
|
|
{
|
|
setNames.insert(_bstr_t(*pbstr++));
|
|
}
|
|
}
|
|
|
|
SafeArrayUnaccessData(psa);
|
|
}
|
|
catch (...)
|
|
{
|
|
SafeArrayUnaccessData(psa);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromVariantArray Method
|
|
|
|
void GetNamesFromVariantArray(SAFEARRAY* psa, StringSet& setNames)
|
|
{
|
|
VARIANT* pvnt;
|
|
|
|
HRESULT hr = SafeArrayAccessData(psa, (void**)&pvnt);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
try
|
|
{
|
|
UINT uDimensionCount = psa->cDims;
|
|
|
|
for (UINT uDimension = 0; uDimension < uDimensionCount; uDimension++)
|
|
{
|
|
UINT uElementCount = psa->rgsabound[uDimension].cElements;
|
|
|
|
for (UINT uElement = 0; uElement < uElementCount; uElement++)
|
|
{
|
|
GetNamesFromVariant(pvnt++, setNames);
|
|
}
|
|
}
|
|
|
|
SafeArrayUnaccessData(psa);
|
|
}
|
|
catch (...)
|
|
{
|
|
SafeArrayUnaccessData(psa);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromFile Method
|
|
//
|
|
// - the maximum file size this implementation can handle is 4,294,967,295 bytes
|
|
|
|
void GetNamesFromFile(VARIANT& vntData, StringSet& setNames)
|
|
{
|
|
bool bInvalidArg = false;
|
|
|
|
switch (V_VT(&vntData))
|
|
{
|
|
case VT_BSTR:
|
|
{
|
|
BSTR bstr = V_BSTR(&vntData);
|
|
|
|
if (bstr)
|
|
{
|
|
GetNamesFromFile(bstr, setNames);
|
|
}
|
|
else
|
|
{
|
|
bInvalidArg = true;
|
|
}
|
|
break;
|
|
}
|
|
case VT_BSTR|VT_BYREF:
|
|
{
|
|
BSTR* pbstr = V_BSTRREF(&vntData);
|
|
|
|
if (pbstr && *pbstr)
|
|
{
|
|
GetNamesFromFile(*pbstr, setNames);
|
|
}
|
|
else
|
|
{
|
|
bInvalidArg = true;
|
|
}
|
|
break;
|
|
}
|
|
case VT_VARIANT|VT_BYREF:
|
|
{
|
|
VARIANT* pvnt = V_VARIANTREF(&vntData);
|
|
|
|
if (pvnt)
|
|
{
|
|
GetNamesFromFile(*pvnt, setNames);
|
|
}
|
|
else
|
|
{
|
|
bInvalidArg = true;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
bInvalidArg = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bInvalidArg)
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_FILE_OPTION_DATA_TYPE);
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromFile Method
|
|
//
|
|
// - the maximum file size this implementation can handle is 4,294,967,295 bytes
|
|
|
|
void GetNamesFromFile(LPCTSTR pszFileName, StringSet& setNames)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pszFileName)
|
|
{
|
|
HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwFileSize = GetFileSize(hFile, NULL);
|
|
|
|
if (dwFileSize > 0)
|
|
{
|
|
HANDLE hFileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if (hFileMappingObject != NULL)
|
|
{
|
|
LPVOID pvBase = MapViewOfFile(hFileMappingObject, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if (pvBase != NULL)
|
|
{
|
|
// if Unicode signature assume Unicode file
|
|
// otherwise it must be an ANSI file
|
|
|
|
LPCWSTR pwcs = (LPCWSTR)pvBase;
|
|
|
|
if ((dwFileSize >= 2) && (*pwcs == L'\xFEFF'))
|
|
{
|
|
GetNamesFromStringW(pwcs + 1, dwFileSize / sizeof(WCHAR) - 1, setNames);
|
|
}
|
|
else
|
|
{
|
|
GetNamesFromStringA((LPCSTR)pvBase, dwFileSize, setNames);
|
|
}
|
|
|
|
UnmapViewOfFile(pvBase);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
CloseHandle(hFileMappingObject);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
AdmtThrowError(GUID_NULL, GUID_NULL, hr, IDS_E_INCLUDE_NAMES_FILE, pszFileName);
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromStringA Method
|
|
|
|
void GetNamesFromStringA(LPCSTR pchString, DWORD cchString, StringSet& setNames)
|
|
{
|
|
static const CHAR chSeparators[] = "\t\n\r";
|
|
|
|
LPCSTR pchStringEnd = &pchString[cchString];
|
|
|
|
for (LPCSTR pch = pchString; pch < pchStringEnd; pch++)
|
|
{
|
|
// skip space characters
|
|
|
|
while ((pch < pchStringEnd) && (*pch == ' '))
|
|
{
|
|
++pch;
|
|
}
|
|
|
|
// beginning of name
|
|
|
|
LPCSTR pchBeg = pch;
|
|
|
|
// scan for separator saving pointer to last non-whitespace character
|
|
|
|
LPCSTR pchEnd = pch;
|
|
|
|
while ((pch < pchStringEnd) && (strchr(chSeparators, *pch) == NULL))
|
|
{
|
|
if (*pch++ != ' ')
|
|
{
|
|
pchEnd = pch;
|
|
}
|
|
}
|
|
|
|
// insert name which doesn't contain any leading or trailing whitespace characters
|
|
|
|
if (pchEnd > pchBeg)
|
|
{
|
|
size_t cchName = pchEnd - pchBeg;
|
|
LPSTR pszName = (LPSTR) _alloca((cchName + 1) * sizeof(CHAR));
|
|
strncpy(pszName, pchBeg, cchName);
|
|
pszName[cchName] = '\0';
|
|
|
|
setNames.insert(_bstr_t(pszName));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetNamesFromStringW Method
|
|
|
|
void GetNamesFromStringW(LPCWSTR pchString, DWORD cchString, StringSet& setNames)
|
|
{
|
|
static const WCHAR chSeparators[] = L"\t\n\r";
|
|
|
|
LPCWSTR pchStringEnd = &pchString[cchString];
|
|
|
|
for (LPCWSTR pch = pchString; pch < pchStringEnd; pch++)
|
|
{
|
|
// skip space characters
|
|
|
|
while ((pch < pchStringEnd) && (*pch == L' '))
|
|
{
|
|
++pch;
|
|
}
|
|
|
|
// beginning of name
|
|
|
|
LPCWSTR pchBeg = pch;
|
|
|
|
// scan for separator saving pointer to last non-whitespace character
|
|
|
|
LPCWSTR pchEnd = pch;
|
|
|
|
while ((pch < pchStringEnd) && (wcschr(chSeparators, *pch) == NULL))
|
|
{
|
|
if (*pch++ != L' ')
|
|
{
|
|
pchEnd = pch;
|
|
}
|
|
}
|
|
|
|
// insert name which doesn't contain any leading or trailing whitespace characters
|
|
|
|
if (pchEnd > pchBeg)
|
|
{
|
|
_bstr_t strName(SysAllocStringLen(pchBeg, pchEnd - pchBeg), false);
|
|
|
|
setNames.insert(strName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// RemoveTrailingDollarSign Method
|
|
|
|
_bstr_t RemoveTrailingDollarSign(LPCTSTR pszName)
|
|
{
|
|
LPTSTR psz = _T("");
|
|
|
|
if (pszName)
|
|
{
|
|
size_t cch = _tcslen(pszName);
|
|
|
|
if (cch > 0)
|
|
{
|
|
psz = reinterpret_cast<LPTSTR>(_alloca((cch + 1) * sizeof(_TCHAR)));
|
|
|
|
_tcscpy(psz, pszName);
|
|
|
|
LPTSTR p = &psz[cch - 1];
|
|
|
|
if (*p == _T('$'))
|
|
{
|
|
*p = _T('\0');
|
|
}
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
} // namespace
|