You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1565 lines
45 KiB
1565 lines
45 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 1998.
|
|
//
|
|
// File: op.cxx
|
|
//
|
|
// Contents: object picker entry point
|
|
//
|
|
// Classes: CObjectPicker
|
|
//
|
|
// History: 01-20-2000 davidmun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#include "headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CObjectPicker)
|
|
#define __THIS_FILE__ L"op"
|
|
|
|
|
|
ULONG
|
|
GetMachineNtVer(
|
|
PCWSTR pwzMachine);
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::CObjectPicker
|
|
//
|
|
// Synopsis: ctor
|
|
//
|
|
// History: 01-20-2000 davidmun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CObjectPicker::CObjectPicker():
|
|
m_cRefs(1),
|
|
m_hwndParent(NULL),
|
|
m_pExternalCustomizer(NULL),
|
|
m_mcTargetComputer(MC_UNKNOWN),
|
|
m_fTargetComputerIsLocal(FALSE),
|
|
m_mcPreviousTargetComputer(MC_UNKNOWN),
|
|
m_fPreviousTargetComputerIsLocal(FALSE),
|
|
m_flInitInfoOptions(0),
|
|
m_pScopeManager(NULL),
|
|
m_pQueryEngine(NULL),
|
|
m_pFilterManager(NULL),
|
|
m_pAttributeManager(NULL),
|
|
m_pAdminCustomizer(NULL),
|
|
m_pBaseDlg(NULL)
|
|
{
|
|
TRACE_CONSTRUCTOR(CObjectPicker);
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CObjectPicker);
|
|
|
|
// NTRAID#NTBUG9-548146-2002/02/20-lucios. Pending fix.
|
|
InitializeCriticalSection(&m_csOleFreeThreading);
|
|
|
|
//
|
|
// Initialize globals in a thread-safe way. Even though this DLL is
|
|
// apartment model only, that only means one thread can access each
|
|
// interface instance. It doesn't preclude the creation of multiple
|
|
// objects in different threads, each of which will try to init the
|
|
// globals.
|
|
//
|
|
|
|
CAutoCritSec Lock(&g_csGlobalVarsCreation);
|
|
|
|
if (g_pBinder)
|
|
{
|
|
ASSERT(g_pADsPath); // all globals created at once
|
|
|
|
g_pBinder->AddRef();
|
|
g_pADsPath->AddRef();
|
|
}
|
|
else
|
|
{
|
|
g_pBinder = new CBinder;
|
|
g_pADsPath = new CADsPathWrapper;
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::~CObjectPicker
|
|
//
|
|
// Synopsis: dtor
|
|
//
|
|
// History: 01-20-2000 davidmun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CObjectPicker::~CObjectPicker()
|
|
{
|
|
TRACE_DESTRUCTOR(CObjectPicker);
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CObjectPicker);
|
|
ASSERT(!m_pExternalCustomizer);
|
|
|
|
delete m_pScopeManager;
|
|
m_pScopeManager = NULL;
|
|
|
|
delete m_pQueryEngine;
|
|
m_pQueryEngine = NULL;
|
|
|
|
delete m_pFilterManager;
|
|
m_pFilterManager = NULL;
|
|
|
|
delete m_pAttributeManager;
|
|
m_pAttributeManager = NULL;
|
|
|
|
delete m_pAdminCustomizer;
|
|
m_pAdminCustomizer = NULL;
|
|
|
|
delete m_pBaseDlg;
|
|
m_pBaseDlg = NULL;
|
|
|
|
CAutoCritSec Lock(&g_csGlobalVarsCreation);
|
|
|
|
if (g_pBinder)
|
|
{
|
|
ASSERT(g_pADsPath); // all globals created at once
|
|
|
|
if (!g_pBinder->Release())
|
|
{
|
|
g_pBinder = NULL;
|
|
}
|
|
|
|
if (!g_pADsPath->Release())
|
|
{
|
|
g_pADsPath = NULL;
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection(&m_csOleFreeThreading);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::InitCopyFree
|
|
//
|
|
// Synopsis: Frees structure created by InitCopy
|
|
//
|
|
// Arguments: dest - pointer to structure to free
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: 05-23-2002 Lucios Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CObjectPicker::InitCopyFree
|
|
(
|
|
PDSOP_INIT_INFO *dest
|
|
)
|
|
{
|
|
if(*dest==NULL) return;
|
|
for(ULONG t=0;t<(*dest)->cDsScopeInfos;t++)
|
|
{
|
|
delete [] (*dest)->aDsScopeInfos[t].pwzADsPath;
|
|
delete [] (*dest)->aDsScopeInfos[t].pwzDcName;
|
|
}
|
|
delete [] (*dest)->aDsScopeInfos;
|
|
|
|
for(ULONG t=0;t<(*dest)->cAttributesToFetch;t++)
|
|
{
|
|
delete [] (*dest)->apwzAttributeNames[t];
|
|
}
|
|
|
|
delete [] (*dest)->apwzAttributeNames;
|
|
|
|
delete [] (*dest)->pwzTargetComputer;
|
|
|
|
delete *dest;
|
|
*dest=0;
|
|
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::InitCopy
|
|
//
|
|
// Synopsis: Copy dest into src to catch exceptions due to invalid args
|
|
//
|
|
// Arguments: dest - returned structure allocated with new that will
|
|
// receive a deep copy of src
|
|
// src - pointer to the structure to be copied
|
|
//
|
|
// Returns: S_OK or E_INVALIDARG
|
|
//
|
|
// History: 05-23-2002 Lucios Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CObjectPicker::InitCopy
|
|
(
|
|
PDSOP_INIT_INFO *dest,
|
|
PDSOP_INIT_INFO src
|
|
)
|
|
{
|
|
if(!src) return E_INVALIDARG;
|
|
|
|
__try
|
|
{
|
|
*dest=new DSOP_INIT_INFO;
|
|
**dest=*src;
|
|
|
|
// We will grow these as we succed in our alocations
|
|
// , so that we only free what we allocate
|
|
(*dest)->cDsScopeInfos=0;
|
|
(*dest)->cAttributesToFetch=0;
|
|
|
|
NewDupStr((PWSTR *)&(*dest)->pwzTargetComputer,src->pwzTargetComputer);
|
|
|
|
(*dest)->apwzAttributeNames=new
|
|
PCWSTR[src->cAttributesToFetch];
|
|
|
|
for(ULONG t=0;t<src->cAttributesToFetch;t++)
|
|
{
|
|
NewDupStr
|
|
(
|
|
(PWSTR *)&(*dest)->apwzAttributeNames[t],
|
|
src->apwzAttributeNames[t]
|
|
);
|
|
(*dest)->cAttributesToFetch++;
|
|
}
|
|
|
|
(*dest)->aDsScopeInfos=new
|
|
DSOP_SCOPE_INIT_INFO[src->cDsScopeInfos];
|
|
|
|
for(ULONG t=0;t<src->cDsScopeInfos;t++)
|
|
{
|
|
(*dest)->aDsScopeInfos[t]=src->aDsScopeInfos[t];
|
|
NewDupStr
|
|
(
|
|
(PWSTR *)&(*dest)->aDsScopeInfos[t].pwzADsPath,
|
|
src->aDsScopeInfos[t].pwzADsPath
|
|
);
|
|
NewDupStr
|
|
(
|
|
(PWSTR *)&(*dest)->aDsScopeInfos[t].pwzDcName,
|
|
src->aDsScopeInfos[t].pwzDcName
|
|
);
|
|
(*dest)->cDsScopeInfos++;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::Initialize
|
|
//
|
|
// Synopsis: Validate and copy the passed-in structure.
|
|
//
|
|
// Arguments: [pInitInfo] - initialization information
|
|
//
|
|
// Returns: S_OK, E_INVALIDARG, or E_OUTOFMEMORY
|
|
//
|
|
// History: 08-29-1998 DavidMun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
STDMETHODIMP
|
|
CObjectPicker::Initialize(
|
|
PDSOP_INIT_INFO pInitInfoArg)
|
|
{
|
|
TRACE_METHOD(CObjectPicker, Initialize);
|
|
PDSOP_INIT_INFO pInitInfo=NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
ULONG i;
|
|
|
|
CAutoCritSec Lock(&m_csOleFreeThreading);
|
|
|
|
try
|
|
{
|
|
do
|
|
{
|
|
|
|
hr=InitCopy(&pInitInfo,pInitInfoArg);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
|
|
//
|
|
// Create objects that manage various duties; if they already
|
|
// exist clear them of data from any previous initialization
|
|
// or use.
|
|
//
|
|
|
|
if (!m_pScopeManager)
|
|
{
|
|
m_pScopeManager = new CScopeManager(*this);
|
|
}
|
|
else
|
|
{
|
|
m_pScopeManager->Clear();
|
|
}
|
|
|
|
if (!m_pQueryEngine)
|
|
{
|
|
m_pQueryEngine = new CQueryEngine(*this);
|
|
m_pQueryEngine->Initialize();
|
|
}
|
|
else
|
|
{
|
|
m_pQueryEngine->Clear();
|
|
}
|
|
|
|
if (!m_pFilterManager)
|
|
{
|
|
m_pFilterManager = new CFilterManager(*this);
|
|
}
|
|
else
|
|
{
|
|
m_pFilterManager->Clear();
|
|
}
|
|
|
|
// note attribute manager is only cleared if target machine changes
|
|
if (!m_pAttributeManager)
|
|
{
|
|
m_pAttributeManager = new CAttributeManager(*this);
|
|
}
|
|
|
|
if (!m_pAdminCustomizer)
|
|
{
|
|
m_pAdminCustomizer = new CAdminCustomizer(*this);
|
|
}
|
|
else
|
|
{
|
|
m_pAdminCustomizer->Clear();
|
|
}
|
|
|
|
if (!m_pBaseDlg)
|
|
{
|
|
m_pBaseDlg = new CBaseDlg(*this);
|
|
}
|
|
else
|
|
{
|
|
m_pBaseDlg->Clear();
|
|
}
|
|
|
|
m_vstrAttributesToFetch.clear();
|
|
|
|
_ClearFlag(CDSOP_INIT_SUCCEEDED);
|
|
|
|
#if (DBG == 1)
|
|
_DumpInitInfo(pInitInfo);
|
|
#endif // (DBG == 1)
|
|
|
|
for (i = 0; i < pInitInfo->cAttributesToFetch; i++)
|
|
{
|
|
PCWSTR pwzAttrName = pInitInfo->apwzAttributeNames[i];
|
|
m_vstrAttributesToFetch.push_back(pwzAttrName);
|
|
}
|
|
|
|
m_flInitInfoOptions = pInitInfo->flOptions;
|
|
|
|
//
|
|
// If target machine is not the same as the previous call, or if
|
|
// this is the first call, determine the configuration
|
|
//
|
|
|
|
|
|
BOOL fLastTargetIsLocalMachine = m_fTargetComputerIsLocal;
|
|
m_fTargetComputerIsLocal =
|
|
IsLocalComputername(pInitInfo->pwzTargetComputer);
|
|
|
|
if ((m_mcTargetComputer == MC_UNKNOWN) ||
|
|
(m_fTargetComputerIsLocal && !fLastTargetIsLocalMachine) ||
|
|
(!m_fTargetComputerIsLocal && fLastTargetIsLocalMachine) ||
|
|
(!m_fTargetComputerIsLocal &&
|
|
!fLastTargetIsLocalMachine &&
|
|
m_strTargetComputer.icompare(pInitInfo->pwzTargetComputer)))
|
|
{
|
|
if (pInitInfo->pwzTargetComputer && *pInitInfo->pwzTargetComputer)
|
|
{
|
|
m_strPreviousTargetComputer = m_strTargetComputer;
|
|
m_strTargetComputer = pInitInfo->pwzTargetComputer;
|
|
m_strTargetComputer.strip(String::LEADING, L'\\');
|
|
Dbg(DEB_TRACE,
|
|
"Target computer is %s\n",
|
|
m_strTargetComputer.c_str());
|
|
}
|
|
else
|
|
{
|
|
WCHAR wzLocalComputer[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD cchSize = ARRAYLEN(wzLocalComputer);
|
|
|
|
// NTRAID#NTBUG9-550683-2002/02/20-lucios. Pending fix.
|
|
VERIFY(GetComputerName(wzLocalComputer, &cchSize));
|
|
m_fPreviousTargetComputerIsLocal = m_fTargetComputerIsLocal;
|
|
m_fTargetComputerIsLocal = TRUE;
|
|
m_strPreviousTargetComputer = m_strTargetComputer;
|
|
m_strTargetComputer = wzLocalComputer;
|
|
|
|
Dbg(DEB_TRACE,
|
|
"Target computer NULL, using '%s'\n",
|
|
m_strTargetComputer.c_str());
|
|
}
|
|
|
|
m_pAttributeManager->Clear();
|
|
|
|
hr = _InitializeMachineConfig();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DBG_OUT_HRESULT(hr);
|
|
|
|
if (m_strTargetComputer.length())
|
|
{
|
|
PopupMessage(GetForegroundWindow(),
|
|
IDS_INIT_FAILED_MACHINE_CONFIG,
|
|
m_strTargetComputer.c_str());
|
|
}
|
|
else
|
|
{
|
|
PopupMessage(GetForegroundWindow(),
|
|
IDS_INIT_FAILED_LOCAL_MACHINE_CONFIG);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (m_mcTargetComputer == MC_JOINED_NT5 ||
|
|
m_mcTargetComputer == MC_NT5_DC)
|
|
{
|
|
m_RootDSE.Init(m_strTargetDomainDns.c_str(),
|
|
m_strTargetForest.c_str());
|
|
}
|
|
}
|
|
|
|
hr = m_pScopeManager->Initialize(pInitInfo);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
|
|
_SetFlag(CDSOP_INIT_SUCCEEDED);
|
|
} while (0);
|
|
}
|
|
catch (const exception &e)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
Dbg(DEB_ERROR, "Caught %s\n", e.what());
|
|
}
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DBG_OUT_HRESULT(hr);
|
|
}
|
|
|
|
InitCopyFree(&pInitInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
#if (DBG == 1)
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: _DumpInOptForm
|
|
//
|
|
// Synopsis: Dump to the debugger the scope flags in a form that can be
|
|
// copied and pasted into a text file that the unit test can
|
|
// read.
|
|
//
|
|
// History: 06-22-2000 DavidMun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void
|
|
_DumpInOptForm(
|
|
PDSOP_SCOPE_INIT_INFO pCur,
|
|
ULONG flScope)
|
|
{
|
|
if (pCur->flType & flScope)
|
|
{
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "%#x\n", flScope);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "%#x\n", pCur->flScope);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, L"%#x\n", pCur->FilterFlags.Uplevel.flBothModes);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, L"%#x\n", pCur->FilterFlags.Uplevel.flMixedModeOnly);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, L"%#x\n", pCur->FilterFlags.Uplevel.flNativeModeOnly);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, L"%#x\n", pCur->FilterFlags.flDownlevel);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "\"%ws\"\n", pCur->pwzDcName);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "\"%ws\"\n", pCur->pwzADsPath);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::_DumpInitInfo
|
|
//
|
|
// Synopsis: Dump initialization structure caller supplied to the debugger
|
|
//
|
|
// History: 06-22-2000 DavidMun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void
|
|
CObjectPicker::_DumpInitInfo(
|
|
PCDSOP_INIT_INFO pInitInfo)
|
|
{
|
|
Dbg(DEB_TRACE, "\n");
|
|
|
|
String strDateTime;
|
|
WCHAR wzDateTime[12];
|
|
|
|
int iRet = GetDateFormat(NULL,
|
|
0,
|
|
NULL,
|
|
L"MM'/'dd'/'yyyy",
|
|
wzDateTime,
|
|
ARRAYLEN(wzDateTime));
|
|
|
|
if (iRet)
|
|
{
|
|
strDateTime = wzDateTime;
|
|
}
|
|
|
|
iRet = GetTimeFormat(NULL,
|
|
0,
|
|
NULL,
|
|
L"HH':'mm':'ss",
|
|
wzDateTime,
|
|
ARRAYLEN(wzDateTime));
|
|
|
|
if (iRet)
|
|
{
|
|
if (!strDateTime.empty())
|
|
{
|
|
strDateTime += L" ";
|
|
}
|
|
strDateTime += wzDateTime;
|
|
}
|
|
|
|
Dbg(DEB_TRACE, " %ws\n", strDateTime.c_str());
|
|
|
|
WCHAR wzLocalComputerNB[LM20_CNLEN + 1] = L"";
|
|
ULONG cchLocalComputerNB = ARRAYLEN(wzLocalComputerNB);
|
|
//REVIEWED-2002-02-21-lucios.
|
|
BOOL fOk = GetComputerName(wzLocalComputerNB, &cchLocalComputerNB);
|
|
|
|
if (fOk)
|
|
{
|
|
Dbg(DEB_TRACE, " Local Computer '%ws'\n", wzLocalComputerNB);
|
|
}
|
|
else
|
|
{
|
|
DBG_OUT_LASTERROR;
|
|
}
|
|
|
|
OSVERSIONINFOEX VerInfo;
|
|
//REVIEWED-2002-02-21-lucios.
|
|
ZeroMemory(&VerInfo, sizeof VerInfo);
|
|
VerInfo.dwOSVersionInfoSize = sizeof VerInfo;
|
|
|
|
fOk = GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&VerInfo));
|
|
|
|
if (fOk)
|
|
{
|
|
PCWSTR pwzProductType;
|
|
|
|
switch (VerInfo.wProductType)
|
|
{
|
|
case VER_NT_WORKSTATION:
|
|
pwzProductType = L"Workstation";
|
|
break;
|
|
|
|
case VER_NT_DOMAIN_CONTROLLER:
|
|
pwzProductType = L"Domain Controller";
|
|
break;
|
|
|
|
case VER_NT_SERVER:
|
|
pwzProductType = L"Server";
|
|
break;
|
|
|
|
default:
|
|
pwzProductType = L"(unknown product type)";
|
|
break;
|
|
}
|
|
|
|
if (VerInfo.szCSDVersion && *VerInfo.szCSDVersion)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
" Windows %ws %u.%u build %u %ws SP version %u.%u\n",
|
|
pwzProductType,
|
|
VerInfo.dwMajorVersion,
|
|
VerInfo.dwMinorVersion,
|
|
VerInfo.dwBuildNumber,
|
|
VerInfo.szCSDVersion,
|
|
VerInfo.wServicePackMajor,
|
|
VerInfo.wServicePackMinor);
|
|
}
|
|
else
|
|
{
|
|
Dbg(DEB_TRACE, " Windows %ws version %u.%u build %u\n",
|
|
pwzProductType,
|
|
VerInfo.dwMajorVersion,
|
|
VerInfo.dwMinorVersion,
|
|
VerInfo.dwBuildNumber);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_OUT_LASTERROR;
|
|
}
|
|
|
|
WCHAR wzUserName[LM20_DNLEN + 1 + LM20_UNLEN + 1] = L""; // +1 for \ +1 for NUL
|
|
ULONG cchUserName = ARRAYLEN(wzUserName);
|
|
//REVIEWED-2002-02-21-lucios.
|
|
fOk = GetUserNameEx(NameSamCompatible, wzUserName, &cchUserName);
|
|
|
|
if (fOk)
|
|
{
|
|
Dbg(DEB_TRACE, " Logged on as '%ws'\n", wzUserName);
|
|
}
|
|
else
|
|
{
|
|
DBG_OUT_LASTERROR;
|
|
}
|
|
|
|
Dbg(DEB_TRACE,
|
|
" Target Computer '%ws'\n",
|
|
CHECK_NULL(pInitInfo->pwzTargetComputer));
|
|
|
|
DumpOptionFlags(pInitInfo->flOptions);
|
|
|
|
ULONG i;
|
|
for (i = 0; i < pInitInfo->cDsScopeInfos; i++)
|
|
{
|
|
PDSOP_SCOPE_INIT_INFO pCur = &pInitInfo->aDsScopeInfos[i];
|
|
Dbg(DEB_TRACE, "\n");
|
|
DumpScopeType(pCur->flType);
|
|
DumpScopeFlags(pCur->flScope);
|
|
DumpFilterFlags(pCur->FilterFlags);
|
|
|
|
if (pCur->pwzDcName)
|
|
{
|
|
Dbg(DEB_TRACE, " DC Name '%ws'\n", pCur->pwzDcName);
|
|
}
|
|
if (pCur->pwzADsPath)
|
|
{
|
|
Dbg(DEB_TRACE, " ADsPath '%ws'\n", pCur->pwzADsPath);
|
|
}
|
|
}
|
|
|
|
// dump in format opt.exe can read
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "\"%ws\"\n", pInitInfo->pwzTargetComputer);
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "%#x\n", pInitInfo->flOptions);
|
|
|
|
String strAttr(L"\"");
|
|
|
|
for (i = 0; i < pInitInfo->cAttributesToFetch; i++)
|
|
{
|
|
strAttr += pInitInfo->apwzAttributeNames[i];
|
|
|
|
if (i < pInitInfo->cAttributesToFetch - 1)
|
|
{
|
|
strAttr += L"; ";
|
|
}
|
|
}
|
|
strAttr += L"\"";
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "%ws\n", strAttr.c_str());
|
|
ULONG cIndividualScopes = 0;
|
|
|
|
for (i = 0; i < pInitInfo->cDsScopeInfos; i++)
|
|
{
|
|
PDSOP_SCOPE_INIT_INFO pCur = &pInitInfo->aDsScopeInfos[i];
|
|
|
|
if (pCur->flType & ST_TARGET_COMPUTER)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_UPLEVEL_JOINED_DOMAIN)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_DOWNLEVEL_JOINED_DOMAIN)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_ENTERPRISE_DOMAIN)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_GLOBAL_CATALOG)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_EXTERNAL_UPLEVEL_DOMAIN)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_EXTERNAL_DOWNLEVEL_DOMAIN)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_WORKGROUP)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_USER_ENTERED_UPLEVEL_SCOPE)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
if (pCur->flType & ST_USER_ENTERED_DOWNLEVEL_SCOPE)
|
|
{
|
|
cIndividualScopes++;
|
|
}
|
|
}
|
|
Dbg(DEB_TRACE | DEB_NOCOMPNAME, "%u\n", cIndividualScopes);
|
|
|
|
for (i = 0; i < pInitInfo->cDsScopeInfos; i++)
|
|
{
|
|
PDSOP_SCOPE_INIT_INFO pCur = &pInitInfo->aDsScopeInfos[i];
|
|
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_TARGET_COMPUTER );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_GLOBAL_CATALOG );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_WORKGROUP );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE );
|
|
_DumpInOptForm(pCur, DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE);
|
|
}
|
|
}
|
|
#endif // (DBG == 1)
|
|
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::_InitializeMachineConfig
|
|
//
|
|
// Synopsis: Determine the configuration of the target computer.
|
|
//
|
|
// History: 06-22-2000 DavidMun Created
|
|
//
|
|
// Notes: Configuration in this sense means whether the target
|
|
// computer is joined to an NT4 domain, an NT5 domain, in a
|
|
// workgroup, etc.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CObjectPicker::_InitializeMachineConfig()
|
|
{
|
|
TRACE_METHOD(CObjectPicker, _InitializeMachineConfig);
|
|
|
|
HRESULT hr = S_OK;
|
|
ULONG ulResult;
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
|
|
PDOMAIN_CONTROLLER_INFO pdci = NULL;
|
|
RpIADs rpADs;
|
|
|
|
do
|
|
{
|
|
m_mcPreviousTargetComputer = m_mcTargetComputer;
|
|
m_mcTargetComputer = MC_UNKNOWN;
|
|
PCWSTR pwzMachine;
|
|
|
|
if (m_fTargetComputerIsLocal)
|
|
{
|
|
pwzMachine = NULL;
|
|
}
|
|
else
|
|
{
|
|
pwzMachine = m_strTargetComputer.c_str();
|
|
ASSERT(*pwzMachine);
|
|
}
|
|
|
|
{
|
|
TIMER("DsRoleGetPrimaryDomainInformation(%ws)",
|
|
CHECK_NULL(pwzMachine));
|
|
|
|
ulResult = DsRoleGetPrimaryDomainInformation(pwzMachine,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *)&pDsRole);
|
|
}
|
|
if (pwzMachine && ulResult == ERROR_ACCESS_DENIED)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"DsRoleGetPrimaryDomainInformation returned ERROR_ACCESS_DENIED, establishing connection\n");
|
|
|
|
//
|
|
// Establish a connection with remote machine using WinNT provider,
|
|
// and try again.
|
|
//
|
|
|
|
WCHAR wzComputerAdsPath[MAX_PATH];
|
|
|
|
// NTRAID#NTBUG9-548039-2002/02/20-lucios. Pending fix.
|
|
wsprintf(wzComputerAdsPath, L"WinNT://%ws,Computer", pwzMachine);
|
|
|
|
hr = g_pBinder->BindToObject(GetForegroundWindow(),
|
|
wzComputerAdsPath,
|
|
IID_IADs,
|
|
(void **) &rpADs);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
|
|
TIMER("DsRoleGetPrimaryDomainInformation2");
|
|
|
|
ulResult =
|
|
DsRoleGetPrimaryDomainInformation(pwzMachine,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *)&pDsRole);
|
|
}
|
|
|
|
if (ulResult != NO_ERROR)
|
|
{
|
|
DBG_OUT_LRESULT(ulResult);
|
|
hr = HRESULT_FROM_WIN32(ulResult);
|
|
break;
|
|
}
|
|
else if(NULL == pDsRole)
|
|
{
|
|
DBG_OUT_LRESULT(ERROR_UNEXP_NET_ERR);
|
|
Dbg(DEB_TRACE,"Network issue found in WinSE Raid 21714, Whistler Raid 476297");
|
|
hr = HRESULT_FROM_WIN32(ERROR_UNEXP_NET_ERR);
|
|
break;
|
|
}
|
|
|
|
|
|
ASSERT(pDsRole);
|
|
|
|
Dbg(DEB_TRACE, "DsRoleGetPrimaryDomainInformation returned:\n");
|
|
Dbg(DEB_TRACE, " DomainNameFlat: %ws\n", CHECK_NULL(pDsRole->DomainNameFlat));
|
|
Dbg(DEB_TRACE, " DomainNameDns: %ws\n", CHECK_NULL(pDsRole->DomainNameDns));
|
|
Dbg(DEB_TRACE, " DomainForestName: %ws\n", CHECK_NULL(pDsRole->DomainForestName));
|
|
|
|
//
|
|
// If machine is in a workgroup, we're done.
|
|
//
|
|
|
|
if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
|
|
pDsRole->MachineRole == DsRole_RoleStandaloneServer)
|
|
{
|
|
Dbg(DEB_TRACE, "Target machine is not joined to a domain\n");
|
|
|
|
m_mcTargetComputer = MC_IN_WORKGROUP;
|
|
break;
|
|
}
|
|
|
|
if (pDsRole->DomainNameFlat)
|
|
{
|
|
m_strTargetDomainFlat = pDsRole->DomainNameFlat;
|
|
}
|
|
|
|
//
|
|
// Target machine is joined to a domain. Find out if it's joined
|
|
// to an NT4 or an NT5 domain by getting the name of a DC, and
|
|
// requesting that we get one which supports DS.
|
|
//
|
|
|
|
PWSTR pwzDomainNameForDsGetDc;
|
|
ULONG flDsGetDc = DS_DIRECTORY_SERVICE_PREFERRED;
|
|
|
|
if (pDsRole->DomainNameDns)
|
|
{
|
|
pwzDomainNameForDsGetDc = pDsRole->DomainNameDns;
|
|
flDsGetDc |= DS_IS_DNS_NAME;
|
|
Dbg(DEB_TRACE,
|
|
"DsGetDcName(Domain=%ws, flags=DS_IS_DNS_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n",
|
|
CHECK_NULL(pwzDomainNameForDsGetDc));
|
|
}
|
|
else
|
|
{
|
|
pwzDomainNameForDsGetDc = pDsRole->DomainNameFlat;
|
|
flDsGetDc |= DS_IS_FLAT_NAME;
|
|
Dbg(DEB_TRACE,
|
|
"DsGetDcName(Domain=%ws, flags=DS_IS_FLAT_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n",
|
|
CHECK_NULL(pwzDomainNameForDsGetDc));
|
|
}
|
|
|
|
ulResult = DsGetDcName(NULL, // per CliffV this should ALWAYS be NULL
|
|
pwzDomainNameForDsGetDc,
|
|
NULL,
|
|
NULL,
|
|
flDsGetDc,
|
|
&pdci);
|
|
|
|
if (ulResult != NO_ERROR)
|
|
{
|
|
m_mcTargetComputer = MC_NO_NETWORK;
|
|
Dbg(DEB_ERROR,
|
|
"DsGetDcName for domain %ws returned %#x, treating target machine as no-net\n",
|
|
pwzDomainNameForDsGetDc,
|
|
ulResult);
|
|
break;
|
|
}
|
|
|
|
if (pdci->Flags & DS_DS_FLAG)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"DsGetDcName returned DS DC for domain %ws, asking for DNS name\n",
|
|
pwzDomainNameForDsGetDc);
|
|
|
|
PDOMAIN_CONTROLLER_INFO pdci2 = NULL;
|
|
|
|
ulResult = DsGetDcName(NULL,
|
|
pwzDomainNameForDsGetDc,
|
|
NULL,
|
|
NULL,
|
|
flDsGetDc | DS_RETURN_DNS_NAME,
|
|
&pdci2);
|
|
|
|
|
|
if (ulResult == NO_ERROR)
|
|
{
|
|
NetApiBufferFree(pdci);
|
|
pdci = pdci2;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(!pdci2);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If TCP/IP is not installed on local machine then DsGetDcName for
|
|
// DNS name will fail. Also, no LDAP or GC scopes may be used.
|
|
// Pretend we're joined to an NT4 domain so WinNT provider will be
|
|
// used for domain scopes.
|
|
//
|
|
|
|
if (ulResult == ERROR_NO_SUCH_DOMAIN)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Attempting to get DNS name for DS DC %ws failed, treating target machine as joined to NT4 domain\n",
|
|
pwzDomainNameForDsGetDc);
|
|
|
|
m_mcTargetComputer = MC_JOINED_NT4;
|
|
break;
|
|
}
|
|
|
|
if (ulResult != NO_ERROR)
|
|
{
|
|
Dbg(DEB_ERROR,
|
|
"DsGetDcName for domain %ws (call for DNS name) returned %uL\n",
|
|
pwzDomainNameForDsGetDc,
|
|
ulResult);
|
|
hr = HRESULT_FROM_WIN32(ulResult);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the target machine is an NT4 BDC in an NT5 mixed-mode domain,
|
|
// treat it as an NT4 DC.
|
|
//
|
|
|
|
if (pDsRole->MachineRole == DsRole_RoleBackupDomainController
|
|
&& GetMachineNtVer(pwzMachine) < 5)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Target machine is an NT4 DC in NT5 mixed mode domain %ws\n",
|
|
m_strTargetDomainDns.empty()
|
|
? m_strTargetDomainFlat.c_str()
|
|
: m_strTargetDomainDns.c_str());
|
|
|
|
m_mcTargetComputer = MC_NT4_DC;
|
|
ASSERT(pwzMachine); // we can't be running on NT4
|
|
m_strTargetDomainDc = pwzMachine;
|
|
break;
|
|
}
|
|
|
|
m_strTargetDomainDc = pdci->DomainControllerName;
|
|
|
|
if (pDsRole->DomainNameDns)
|
|
{
|
|
m_strTargetDomainDns = pDsRole->DomainNameDns;
|
|
}
|
|
else if (pdci->DomainName)
|
|
{
|
|
m_strTargetDomainDns = pdci->DomainName;
|
|
}
|
|
|
|
m_strTargetDomainDns.strip(String::TRAILING, L'.');
|
|
|
|
if (pdci->Flags & DS_DS_FLAG)
|
|
{
|
|
m_strTargetForest = pdci->DnsForestName;
|
|
m_strTargetForest.strip(String::TRAILING, L'.');
|
|
|
|
if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
|
|
pDsRole->MachineRole == DsRole_RoleBackupDomainController)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Target machine is an NT5 DC for NT5 domain %ws in forest %ws\n",
|
|
m_strTargetDomainDns.empty()
|
|
? m_strTargetDomainFlat.c_str()
|
|
: m_strTargetDomainDns.c_str(),
|
|
m_strTargetForest.c_str());
|
|
|
|
m_mcTargetComputer = MC_NT5_DC;
|
|
}
|
|
else
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Target machine is joined to NT5 domain %ws (DC is %ws) in forest %ws\n",
|
|
m_strTargetDomainDns.empty()
|
|
? m_strTargetDomainFlat.c_str()
|
|
: m_strTargetDomainDns.c_str(),
|
|
m_strTargetDomainDc.c_str(),
|
|
m_strTargetForest.c_str());
|
|
|
|
m_mcTargetComputer = MC_JOINED_NT5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
|
|
pDsRole->MachineRole == DsRole_RoleBackupDomainController)
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Target machine is an NT4 DC for domain %ws\n",
|
|
m_strTargetDomainFlat.c_str());
|
|
m_mcTargetComputer = MC_NT4_DC;
|
|
}
|
|
else
|
|
{
|
|
Dbg(DEB_TRACE,
|
|
"Target machine is joined to NT4 domain %ws\n",
|
|
m_strTargetDomainFlat.c_str());
|
|
|
|
m_mcTargetComputer = MC_JOINED_NT4;
|
|
}
|
|
}
|
|
|
|
} while (0);
|
|
|
|
if (pdci)
|
|
{
|
|
NetApiBufferFree(pdci);
|
|
}
|
|
|
|
if (pDsRole)
|
|
{
|
|
DsRoleFreeMemory(pDsRole);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
#define NT_VERSION_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
|
|
#define NT_VERSION_VALUE L"CurrentVersion"
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: GetMachineNtVer
|
|
//
|
|
// Synopsis: Return the major NT version number on machine [pwzMachine]
|
|
// as an unsigned integer, or 0 on error.
|
|
//
|
|
// Arguments: [pwzMachine] - machine from which to read version; NULL
|
|
// for local machine
|
|
//
|
|
// History: 09-01-1999 davidmun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
ULONG
|
|
GetMachineNtVer(
|
|
PCWSTR pwzMachine)
|
|
{
|
|
TRACE_FUNCTION(GetMachineNtVer);
|
|
|
|
ULONG ulVer = 0;
|
|
HRESULT hr = S_OK;
|
|
CSafeReg reg;
|
|
WCHAR wzBuf[20] = L"";
|
|
NET_API_STATUS Status = NERR_Success;
|
|
WKSTA_INFO_100 *pinfo100 = NULL;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Try to get the nt version using NetWkstaGetInfo first
|
|
//
|
|
|
|
String strServer;
|
|
|
|
if (pwzMachine)
|
|
{
|
|
ASSERT(*pwzMachine);
|
|
strServer = String(L"\\\\") + pwzMachine;
|
|
|
|
Status = NetWkstaGetInfo(const_cast<PWSTR>(strServer.c_str()),
|
|
100,
|
|
reinterpret_cast<LPBYTE *>(&pinfo100));
|
|
}
|
|
else
|
|
{
|
|
Status = NetWkstaGetInfo(NULL,
|
|
100,
|
|
reinterpret_cast<LPBYTE *>(&pinfo100));
|
|
}
|
|
|
|
if (Status == NERR_Success)
|
|
{
|
|
ulVer = pinfo100->wki100_ver_major;
|
|
Dbg(DEB_TRACE,
|
|
"NetWkstaGetInfo returns %u.%u\n",
|
|
pinfo100->wki100_ver_major,
|
|
pinfo100->wki100_ver_minor);
|
|
break;
|
|
}
|
|
|
|
Dbg(DEB_ERROR, "NetWkstaGetInfo error %u\n", Status);
|
|
|
|
//
|
|
// NetWkstaGetInfo failed. Try to get the version number from
|
|
// the registry.
|
|
//
|
|
|
|
if (pwzMachine)
|
|
{
|
|
CSafeReg regRemote;
|
|
|
|
hr = regRemote.Connect(pwzMachine, HKEY_LOCAL_MACHINE);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
|
|
hr = reg.Open(regRemote,
|
|
NT_VERSION_KEY,
|
|
STANDARD_RIGHTS_READ | KEY_QUERY_VALUE);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
}
|
|
else
|
|
{
|
|
hr = reg.Open(HKEY_LOCAL_MACHINE,
|
|
NT_VERSION_KEY,
|
|
STANDARD_RIGHTS_READ | KEY_QUERY_VALUE);
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
}
|
|
|
|
hr = reg.QueryStr(NT_VERSION_VALUE, wzBuf, ARRAYLEN(wzBuf));
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
|
|
ulVer = wcstoul(wzBuf, NULL, 10);
|
|
} while (0);
|
|
|
|
if (pinfo100)
|
|
{
|
|
NetApiBufferFree(pinfo100);
|
|
}
|
|
|
|
Dbg(DEB_TRACE,
|
|
"%ws NT version is %ws (%u)\n",
|
|
pwzMachine ? pwzMachine : L"Local machine",
|
|
wzBuf,
|
|
ulVer);
|
|
|
|
return ulVer;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::InvokeDialog
|
|
//
|
|
// Synopsis: Once Initialize has been called successfully, this method
|
|
// may be called to invoke the modal object picker dialog.
|
|
//
|
|
// Arguments: [hwndParent] - parent window
|
|
// [ppdoSelections] - filled with selected objects
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: 01-20-2000 davidmun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CObjectPicker::InvokeDialog(
|
|
HWND hwndParent,
|
|
IDataObject **ppdoSelections)
|
|
{
|
|
return InvokeDialogEx(hwndParent, NULL, ppdoSelections);
|
|
}
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::InvokeDialogEx
|
|
//
|
|
// Synopsis: Invoke the modal object picker dialog.
|
|
//
|
|
// Arguments: [hwndParent] - parent window of dialog
|
|
// [pCustomizer] - callback methods
|
|
// [ppdoSelections] - filled with data object containing user's
|
|
// selections on success
|
|
//
|
|
// Returns: S_FALSE - user cancelled dialog, *ppdoSelections == NULL
|
|
// E_* - error occurred, *ppdoSelections == NULL
|
|
// S_OK - *ppdoSelections is valid
|
|
//
|
|
// Modifies: *[ppdoSelections]
|
|
//
|
|
// History: 10-07-1998 DavidMun Created
|
|
// 01-20-2000 davidmun rewritten
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CObjectPicker::InvokeDialogEx(
|
|
HWND hwndParent,
|
|
ICustomizeDsBrowser *pCustomizer,
|
|
IDataObject **ppdoSelections)
|
|
{
|
|
TRACE_METHOD(CObjectPicker, InvokeDialogEx);
|
|
HRESULT hr = S_OK;
|
|
|
|
CAutoCritSec Lock(&m_csOleFreeThreading);
|
|
|
|
try
|
|
{
|
|
*ppdoSelections = NULL;
|
|
|
|
do
|
|
{
|
|
if (!_IsFlagSet(CDSOP_INIT_SUCCEEDED))
|
|
{
|
|
PopupMessage(hwndParent, IDS_CANNOT_INVOKE);
|
|
hr = E_UNEXPECTED;
|
|
DBG_OUT_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
m_hwndParent = hwndParent;
|
|
m_pExternalCustomizer = pCustomizer;
|
|
|
|
//
|
|
// If init succeeded we should know what the machine config is
|
|
//
|
|
|
|
ASSERT(m_mcTargetComputer != MC_UNKNOWN);
|
|
|
|
//
|
|
// Put up the dialog
|
|
//
|
|
LinkWindow_RegisterClass();
|
|
hr = m_pBaseDlg->DoModal(ppdoSelections);
|
|
LinkWindow_UnregisterClass(g_hinst);
|
|
|
|
BREAK_ON_FAIL_HRESULT(hr);
|
|
} while (0);
|
|
|
|
m_hwndParent = NULL;
|
|
m_pExternalCustomizer = NULL;
|
|
}
|
|
STANDARD_CATCH_BLOCK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::ProcessNames
|
|
//
|
|
// Synopsis: Process the user-entered text and any objects in the
|
|
// rich edit control.
|
|
//
|
|
// Arguments: [hwndRichEdit] - edit control containing text and
|
|
// objects to process
|
|
// [pEdsoGdiProvider] - points to instance of object which
|
|
// will provide GDI objects needed
|
|
// to draw in the richedit.
|
|
// [fForceSingleSelect] - if TRUE then the contents of the
|
|
// rich edit are treated as a single
|
|
// name, even if the
|
|
// DSOP_FLAG_MULTISELECT flag was set
|
|
// by the caller.
|
|
//
|
|
// Returns: TRUE if all text and every object processed successfully
|
|
//
|
|
// History: 06-22-2000 DavidMun Created
|
|
//
|
|
// Notes: When user-entered text is processed it is removed and
|
|
// replaced with zero or more CEmbeddedDsObjects. Each of these
|
|
// objects is processed by requesting it to perform the
|
|
// caller-specified name translation and attribute fetches, if
|
|
// any.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CObjectPicker::ProcessNames(
|
|
HWND hwndRichEdit,
|
|
const CEdsoGdiProvider *pEdsoGdiProvider,
|
|
BOOL fForceSingleSelect) const
|
|
{
|
|
TRACE_METHOD(CObjectPicker, ProcessNames);
|
|
|
|
enum PARSE_STATE
|
|
{
|
|
EAT_LEADING,
|
|
EAT_TRAILING,
|
|
EAT_DELIM
|
|
};
|
|
|
|
CWaitCursor Hourglass;
|
|
PARSE_STATE ParseState = EAT_LEADING;
|
|
NAME_PROCESS_RESULT npr = NPR_SUCCESS;
|
|
ULONG idxNextObjectToProcess = 0;
|
|
IRichEditOle *pRichEditOle = NULL;
|
|
|
|
LRESULT lResult = SendMessage(hwndRichEdit,
|
|
EM_GETOLEINTERFACE,
|
|
0,
|
|
(LPARAM) &pRichEditOle);
|
|
if (!lResult)
|
|
{
|
|
DBG_OUT_LASTERROR;
|
|
PopupMessage(hwndRichEdit,
|
|
IDS_CANNOT_READ_RICHEDIT,
|
|
lResult);
|
|
return FALSE;
|
|
}
|
|
|
|
CRichEditHelper re(*this,
|
|
hwndRichEdit,
|
|
pEdsoGdiProvider,
|
|
pRichEditOle,
|
|
fForceSingleSelect);
|
|
CRichEditHelper::iterator itCur = re.begin();
|
|
|
|
while (!NAME_PROCESSING_FAILED(npr) && itCur != re.end())
|
|
{
|
|
switch (ParseState)
|
|
{
|
|
case EAT_LEADING:
|
|
re.Consume(itCur, L" \r\t;");
|
|
|
|
if (itCur == re.end())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// if itCur is an object, advance past and eat trailing
|
|
|
|
if (re.IsObject(itCur))
|
|
{
|
|
npr = re.ProcessObject(itCur, idxNextObjectToProcess);
|
|
|
|
if (!NAME_PROCESSING_FAILED(npr))
|
|
{
|
|
itCur++;
|
|
idxNextObjectToProcess++;
|
|
ParseState = EAT_TRAILING;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// itCur is at start of some text. convert it to object(s) or
|
|
// delete it.
|
|
//
|
|
|
|
npr = re.MakeObject(itCur);
|
|
break;
|
|
|
|
case EAT_TRAILING:
|
|
re.Consume(itCur, L" \t");
|
|
|
|
// exit switch if nothing to the right of itCur
|
|
|
|
if (itCur == re.end())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (re.ReadChar(itCur) == L'\r')
|
|
{
|
|
re.ReplaceChar(itCur, L';');
|
|
}
|
|
|
|
if (re.ReadChar(itCur) == L';')
|
|
{
|
|
itCur++;
|
|
ParseState = EAT_DELIM;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// itCur is at text or object. since we're eating trailing spaces
|
|
// that means there's an object to the left of itCur. insert
|
|
// a delimiter, move past it, and switch to eating leading spaces.
|
|
//
|
|
|
|
re.Insert(itCur, L"; ");
|
|
itCur += 2;
|
|
ParseState = EAT_LEADING;
|
|
break;
|
|
|
|
case EAT_DELIM:
|
|
re.Consume(itCur, L";\r");
|
|
|
|
if (itCur == re.end())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (iswspace(re.ReadChar(itCur)))
|
|
{
|
|
itCur++;
|
|
ParseState = EAT_LEADING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// itCur is at non-whitespace text or object which is folloinwg
|
|
// directly after a semicolon. add a space and move past it, then
|
|
// switch to eating leading.
|
|
//
|
|
|
|
re.Insert(itCur, L" ");
|
|
itCur++;
|
|
ParseState = EAT_LEADING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SAFE_RELEASE(pRichEditOle);
|
|
|
|
if (NAME_PROCESSING_FAILED(npr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
re.TrimTrailing(L"; \t");
|
|
return re.begin() != re.end();
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::AddRef
|
|
//
|
|
// Synopsis: Standard OLE
|
|
//
|
|
// History: 12-04-96 DavidMun Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CObjectPicker::AddRef()
|
|
{
|
|
ULONG ul = InterlockedIncrement((LONG *) &m_cRefs);
|
|
//Dbg(DEB_TRACE, "AddRef new refcount is %d\n", ul);
|
|
return ul;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::Release
|
|
//
|
|
// Synopsis: Standard OLE
|
|
//
|
|
// History: 12-04-96 DavidMun Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CObjectPicker::Release()
|
|
{
|
|
ULONG cRefsTemp = InterlockedDecrement((LONG *)&m_cRefs);
|
|
|
|
//Dbg(DEB_TRACE, "Release new refcount is %d\n", cRefsTemp);
|
|
|
|
if (0 == cRefsTemp)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRefsTemp;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CObjectPicker::QueryInterface
|
|
//
|
|
// Synopsis: Standard OLE
|
|
//
|
|
// History: 12-05-1996 DavidMun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CObjectPicker::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppvObj)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
if (NULL == ppvObj)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DBG_OUT_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (IUnknown *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IDsObjectPicker))
|
|
{
|
|
*ppvObj = (IUnknown *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IDsObjectPickerEx))
|
|
{
|
|
*ppvObj = (IUnknown *)this;
|
|
}
|
|
else
|
|
{
|
|
DBG_OUT_NO_INTERFACE("CObjectPicker", riid);
|
|
hr = E_NOINTERFACE;
|
|
*ppvObj = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we got this far we are handing out a new interface pointer on
|
|
// this object, so addref it.
|
|
//
|
|
|
|
AddRef();
|
|
} while (0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|