615 lines
17 KiB
C++
615 lines
17 KiB
C++
|
#include "oleds.hxx"
|
||
|
#include "bindercf.hxx"
|
||
|
#include "atlbase.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
||
|
//
|
||
|
// File: libmain.cxx
|
||
|
//
|
||
|
// Contents: LibMain for ADs.dll
|
||
|
//
|
||
|
// Functions: LibMain, DllGetClassObject
|
||
|
//
|
||
|
// History: 25-Oct-94 KrishnaG Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HINSTANCE g_hInst = NULL;
|
||
|
PROUTER_ENTRY g_pRouterHead = NULL;
|
||
|
CRITICAL_SECTION g_csRouterHeadCritSect;
|
||
|
//
|
||
|
// Dll's we load dynamically.
|
||
|
//
|
||
|
extern HANDLE g_hDllAdvapi32;
|
||
|
|
||
|
extern const GUID DBGUID_ROOTBINDER =
|
||
|
{0xFF151822, 0xB0BF, 0x11D1, {0xA8, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// ADs debug print, mem leak and object tracking-related stuff
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
DECLARE_INFOLEVEL(ADs)
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ShutDown
|
||
|
//
|
||
|
// Synopsis: Function to handle printing out heap debugging display
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
inline VOID ShutDown()
|
||
|
{
|
||
|
#if DBG==1
|
||
|
#ifndef MSVC
|
||
|
DUMP_TRACKING_INFO_DELETE();
|
||
|
AllocArenaDump( NULL );
|
||
|
DeleteCriticalSection(&g_csOT);
|
||
|
#endif // ifndef MSVC
|
||
|
DeleteCriticalSection(&g_csDP);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
extern "C" DWORD heapInfoLevel;
|
||
|
extern "C" DWORD OtInfoLevel;
|
||
|
extern "C" DWORD ADsInfoLevel;
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetINIHeapInfoLevel
|
||
|
//
|
||
|
// Synopsis: Gets various infolevel values from win.ini
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
inline VOID GetINIHeapInfoLevel()
|
||
|
{
|
||
|
#if DBG==1
|
||
|
const INT MAXINFOLEN=11;
|
||
|
WCHAR awcs[MAXINFOLEN];
|
||
|
|
||
|
#ifndef MSVC
|
||
|
if (GetProfileString(L"ADs",L"heapInfoLevel", L"00000003", awcs,MAXINFOLEN))
|
||
|
heapInfoLevel = wcstoul(awcs, NULL, 16);
|
||
|
|
||
|
if (GetProfileString(L"ADs",L"Ot", L"00000003", awcs, MAXINFOLEN))
|
||
|
OtInfoLevel = wcstoul(awcs, NULL, 16);
|
||
|
|
||
|
#endif // MSVC
|
||
|
|
||
|
if (GetProfileString(L"ADs",L"ADsInfoLevel", L"00000003", awcs,MAXINFOLEN))
|
||
|
ADsInfoLevel = wcstoul(awcs, NULL, 16);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Globals
|
||
|
|
||
|
|
||
|
ULONG g_ulObjCount = 0; // Number of objects alivein ADs.dll
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Macro that calculates the number of elements in a statically-defined
|
||
|
// array.
|
||
|
//
|
||
|
// Note - I swiped this from formsary.cxx - A type-safe array class. Remember
|
||
|
// to swipe the whole thing as required.
|
||
|
//-------------------------------------------------------------------------
|
||
|
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// ADs class factories
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
CADsNamespacesCF g_cfNamespaces;
|
||
|
CADsProviderCF g_cfProvider;
|
||
|
CDSOCF g_cfDSO;
|
||
|
CADsSecurityDescriptorCF g_cfSed;
|
||
|
CADsAccessControlListCF g_cfAcl;
|
||
|
CADsAccessControlEntryCF g_cfAce;
|
||
|
CADsPropertyEntryCF g_cfPropEntry;
|
||
|
CADsPropertyValueCF g_cfPropertyValue;
|
||
|
CADsLargeIntegerCF g_cfLargeInteger;
|
||
|
CADsBinderCF g_cfBinder;
|
||
|
CPathnameCF g_cfPathname;
|
||
|
CADsDNWithBinaryCF g_cfDNWithBinary;
|
||
|
CADsDNWithStringCF g_cfDNWithString;
|
||
|
CADsSecurityUtilityCF g_cfADsSecurityUtility;
|
||
|
|
||
|
extern CRITICAL_SECTION g_DispTypeInfoCritSect;
|
||
|
extern CRITICAL_SECTION g_StringsCriticalSection;
|
||
|
|
||
|
struct CLSCACHE
|
||
|
{
|
||
|
const CLSID * pclsid;
|
||
|
IClassFactory * pCF;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
CLSCACHE g_aclscache[] =
|
||
|
{
|
||
|
&CLSID_ADsNamespaces, &g_cfNamespaces,
|
||
|
&CLSID_ADsProvider, &g_cfProvider,
|
||
|
&CLSID_ADsDSOObject, &g_cfDSO,
|
||
|
&CLSID_SecurityDescriptor, &g_cfSed,
|
||
|
&CLSID_AccessControlList, &g_cfAcl,
|
||
|
&CLSID_AccessControlEntry, &g_cfAce,
|
||
|
&CLSID_PropertyEntry, &g_cfPropEntry,
|
||
|
&CLSID_PropertyValue, &g_cfPropertyValue,
|
||
|
&CLSID_LargeInteger, &g_cfLargeInteger,
|
||
|
&CLSID_ADSI_BINDER, &g_cfBinder,
|
||
|
&CLSID_Pathname, &g_cfPathname,
|
||
|
&CLSID_DNWithBinary, &g_cfDNWithBinary,
|
||
|
&CLSID_DNWithString, &g_cfDNWithString,
|
||
|
&CLSID_ADsSecurityUtility, &g_cfADsSecurityUtility
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
// ATL Module definition
|
||
|
//------------------------------------------------------------------------
|
||
|
CComModule _Module;
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllGetClassObject
|
||
|
//
|
||
|
// Synopsis: Standard DLL entrypoint for locating class factories
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
STDAPI
|
||
|
DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID FAR* ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
size_t i;
|
||
|
|
||
|
if( ppv == NULL )
|
||
|
RRETURN( E_INVALIDARG );
|
||
|
|
||
|
*ppv = NULL;
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(g_aclscache); i++)
|
||
|
{
|
||
|
if (IsEqualCLSID(clsid, *g_aclscache[i].pclsid))
|
||
|
{
|
||
|
hr = g_aclscache[i].pCF->QueryInterface(iid, ppv);
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*ppv = NULL;
|
||
|
|
||
|
//
|
||
|
// Add Debugging Code to indicate that the ADs.DllGetClassObject
|
||
|
// has been called with an unknown CLSID.
|
||
|
//
|
||
|
|
||
|
return CLASS_E_CLASSNOTAVAILABLE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllCanUnloadNow
|
||
|
//
|
||
|
// Synopsis: Standard DLL entrypoint to determine if DLL can be unloaded
|
||
|
//
|
||
|
//---------------------------------------------------------------
|
||
|
|
||
|
STDAPI
|
||
|
DllCanUnloadNow(void)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = S_FALSE;
|
||
|
|
||
|
if (DllReadyToUnload())
|
||
|
hr = S_OK;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: LibMain
|
||
|
//
|
||
|
// Synopsis: Standard DLL initialization entrypoint
|
||
|
//
|
||
|
//---------------------------------------------------------------
|
||
|
|
||
|
EXTERN_C BOOL __cdecl
|
||
|
LibMain(HINSTANCE hInst, ULONG ulReason, LPVOID pvReserved)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
switch (ulReason)
|
||
|
{
|
||
|
case DLL_PROCESS_ATTACH:
|
||
|
//
|
||
|
// Need to put in try catch block as init crit sects can fail.
|
||
|
//
|
||
|
__try {
|
||
|
|
||
|
DisableThreadLibraryCalls(hInst);
|
||
|
|
||
|
g_hInst = hInst;
|
||
|
|
||
|
#if DBG==1
|
||
|
#ifndef MSVC
|
||
|
InitializeCriticalSection(&g_csOT); // Used by Object Tracker
|
||
|
InitializeCriticalSection(&g_csMem); // Used by Object Tracker
|
||
|
#endif
|
||
|
InitializeCriticalSection(&g_csDP); // Used by ADsDebug
|
||
|
#endif
|
||
|
|
||
|
InitializeCriticalSection(&g_DispTypeInfoCritSect);
|
||
|
|
||
|
InitializeCriticalSection(&g_StringsCriticalSection);
|
||
|
|
||
|
InitializeCriticalSection(&g_csRouterHeadCritSect); // router initialization
|
||
|
|
||
|
}
|
||
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
//
|
||
|
// Critical failure
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case DLL_PROCESS_DETACH:
|
||
|
if (g_pRouterHead) {
|
||
|
CleanupRouter(g_pRouterHead);
|
||
|
}
|
||
|
FreeTypeInfoTable();
|
||
|
|
||
|
//
|
||
|
// Delete the cs we inited.
|
||
|
//
|
||
|
#if DBG==1
|
||
|
#ifndef MSVC
|
||
|
DeleteCriticalSection(&g_csOT); // Used by Object Tracker
|
||
|
DeleteCriticalSection(&g_csMem); // Used by Object Tracker
|
||
|
#endif
|
||
|
DeleteCriticalSection(&g_csDP); // Used by ADsDebug
|
||
|
#endif
|
||
|
|
||
|
DeleteCriticalSection(&g_DispTypeInfoCritSect);
|
||
|
DeleteCriticalSection(&g_StringsCriticalSection);
|
||
|
DeleteCriticalSection(&g_csRouterHeadCritSect);
|
||
|
//
|
||
|
// Free any libs we loaded using loadlibrary
|
||
|
//
|
||
|
if (g_hDllAdvapi32) {
|
||
|
FreeLibrary((HMODULE) g_hDllAdvapi32);
|
||
|
g_hDllAdvapi32 = NULL;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllMain
|
||
|
//
|
||
|
// Synopsis: entry point for NT - post .546
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
||
|
{
|
||
|
return LibMain((HINSTANCE)hDll, dwReason, lpReserved);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetCachedClsidIndex
|
||
|
//
|
||
|
// Synopsis: Returns the index of the given CLSID in the cache, or
|
||
|
// -1 if the CLSID is not present in the cache
|
||
|
//
|
||
|
// Arguments: [clsid]
|
||
|
//
|
||
|
// Returns: int
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
int
|
||
|
GetCachedClsidIndex(REFCLSID clsid)
|
||
|
{
|
||
|
int i;
|
||
|
CLSCACHE * pclscache;
|
||
|
|
||
|
for (i = 0, pclscache = g_aclscache;
|
||
|
i < ARRAY_SIZE(g_aclscache);
|
||
|
i ++, pclscache++)
|
||
|
{
|
||
|
if (IsEqualCLSID(*pclscache->pclsid, clsid))
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetCachedClassFactory
|
||
|
//
|
||
|
// Synopsis: Returns the cached class factory with the given index.
|
||
|
// The pointer returned has been AddRef'd.
|
||
|
//
|
||
|
// Arguments: [iclsid]
|
||
|
//
|
||
|
// Returns: IClassFactory *
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
IClassFactory *
|
||
|
GetCachedClassFactory(int iclsid)
|
||
|
{
|
||
|
IClassFactory * pCF;
|
||
|
|
||
|
// Assert(iclsid >= 0);
|
||
|
// Assert(iclsid < ARRAY_SIZE(g_aclscache));
|
||
|
|
||
|
pCF = g_aclscache[iclsid].pCF;
|
||
|
pCF->AddRef();
|
||
|
|
||
|
return pCF;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetCachedClsid
|
||
|
//
|
||
|
// Synopsis: Returns the CLSID corresponding to the given index.
|
||
|
// Normally, code should call GetCachedClassFactory to get
|
||
|
// the class factory directly.
|
||
|
//
|
||
|
// Arguments: [iclsid] -- Clsid index
|
||
|
// [pclsid] -- Matching clsid returned in *pclsid
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
GetCachedClsid(int iclsid, CLSID * pclsid)
|
||
|
{
|
||
|
// Assert(iclsid >= 0);
|
||
|
// Assert(iclsid < ARRAY_SIZE(g_aclscache));
|
||
|
|
||
|
*pclsid = *g_aclscache[iclsid].pclsid;
|
||
|
}
|
||
|
|
||
|
STDAPI DllRegisterServer()
|
||
|
{
|
||
|
PWCHAR pwszClsid = NULL;
|
||
|
WCHAR pwszSubKey[256];
|
||
|
HRESULT hr = S_OK;
|
||
|
#if (!defined(BUILD_FOR_NT40))
|
||
|
auto_rel<IRegisterProvider> pRegisterProvider;
|
||
|
wcscpy(pwszSubKey, L"SOFTWARE\\Classes\\CLSID\\");
|
||
|
hr = StringFromCLSID(CLSID_ADSI_BINDER, &pwszClsid);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
wcscat(pwszSubKey, pwszClsid);
|
||
|
|
||
|
HKEY hKeyClsid = NULL, hKeyDll = NULL;
|
||
|
DWORD dwDisposition;
|
||
|
LONG lRetVal;
|
||
|
|
||
|
//
|
||
|
// Make sure the router has been initialized
|
||
|
//
|
||
|
EnterCriticalSection(&g_csRouterHeadCritSect);
|
||
|
if (!g_pRouterHead) {
|
||
|
g_pRouterHead = InitializeRouter();
|
||
|
}
|
||
|
LeaveCriticalSection(&g_csRouterHeadCritSect);
|
||
|
|
||
|
|
||
|
//Create CLSID entry
|
||
|
lRetVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
||
|
pwszSubKey,
|
||
|
0,
|
||
|
L"",
|
||
|
0,
|
||
|
KEY_ALL_ACCESS,
|
||
|
NULL,
|
||
|
&hKeyClsid,
|
||
|
&dwDisposition);
|
||
|
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//set the value
|
||
|
lRetVal = RegSetValueEx(hKeyClsid,
|
||
|
NULL,
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(CONST BYTE *)L"Provider Binder for DS OLE DB Provider",
|
||
|
78);
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//Create InprocServer32 entry
|
||
|
lRetVal = RegCreateKeyEx(hKeyClsid,
|
||
|
L"InprocServer32",
|
||
|
0,
|
||
|
L"activeds.dll",
|
||
|
0,
|
||
|
KEY_ALL_ACCESS,
|
||
|
NULL,
|
||
|
&hKeyDll,
|
||
|
&dwDisposition);
|
||
|
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//set the value
|
||
|
lRetVal = RegSetValueEx(hKeyDll,
|
||
|
NULL,
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(CONST BYTE *)L"activeds.dll",
|
||
|
26);
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//Now set the threadingModel value for the dll key
|
||
|
lRetVal = RegSetValueEx(hKeyDll,
|
||
|
L"ThreadingModel",
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(CONST BYTE *)L"Both",
|
||
|
10);
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//Now register the provider with the root binder.
|
||
|
//Cocreate Root Binder and get IRegisterProvider interface.
|
||
|
hr = CoCreateInstance ( DBGUID_ROOTBINDER,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(IRegisterProvider),
|
||
|
(void **) &pRegisterProvider
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Go through list of ADS providers and register each of them
|
||
|
// with the root binder.
|
||
|
for ( PROUTER_ENTRY pProvider = g_pRouterHead;
|
||
|
pProvider != NULL;
|
||
|
pProvider=pProvider->pNext)
|
||
|
{
|
||
|
// Invalid provider ProgID? If so, continue with next provider
|
||
|
if (NULL == pProvider->szProviderProgId)
|
||
|
continue;
|
||
|
|
||
|
hr = pRegisterProvider->SetURLMapping(
|
||
|
pProvider->szProviderProgId,
|
||
|
0,
|
||
|
CLSID_ADSI_BINDER);
|
||
|
if (FAILED(hr))
|
||
|
AtlTrace(_T("Failed to register %s mapping hr = %x\n"),
|
||
|
pProvider->szProviderProgId, hr);
|
||
|
|
||
|
// Ignore error and continue with next provider
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AtlTrace(_T("Creation of Root Binder failed! hr = %x\n"), hr);
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
CoTaskMemFree(pwszClsid);
|
||
|
if (hKeyClsid) {
|
||
|
RegCloseKey(hKeyClsid);
|
||
|
}
|
||
|
|
||
|
if (hKeyDll) {
|
||
|
RegCloseKey(hKeyDll);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDAPI DllUnregisterServer()
|
||
|
{
|
||
|
PWCHAR pwszClsid = NULL;
|
||
|
WCHAR pwszClsidKey[256];
|
||
|
WCHAR pwszDllKey[256];
|
||
|
HRESULT hr = S_OK;
|
||
|
LONG lRetVal;
|
||
|
#if (!defined(BUILD_FOR_NT40))
|
||
|
auto_rel<IRegisterProvider> pRegisterProvider;
|
||
|
wcscpy(pwszClsidKey, L"SOFTWARE\\Classes\\CLSID\\");
|
||
|
hr = StringFromCLSID(CLSID_ADSI_BINDER, &pwszClsid);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
wcscat(pwszClsidKey, pwszClsid);
|
||
|
|
||
|
wcscpy(pwszDllKey, pwszClsidKey);
|
||
|
wcscat(pwszDllKey, L"\\InprocServer32");
|
||
|
|
||
|
//
|
||
|
// Make sure the router has been initialized
|
||
|
//
|
||
|
EnterCriticalSection(&g_csRouterHeadCritSect);
|
||
|
if (!g_pRouterHead) {
|
||
|
g_pRouterHead = InitializeRouter();
|
||
|
}
|
||
|
LeaveCriticalSection(&g_csRouterHeadCritSect);
|
||
|
|
||
|
|
||
|
//Delete InprocServer32 key
|
||
|
lRetVal = RegDeleteKey(HKEY_LOCAL_MACHINE, pwszDllKey);
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//Delete key and all its subkeys.
|
||
|
lRetVal = RegDeleteKey(HKEY_LOCAL_MACHINE, pwszClsidKey);
|
||
|
if (lRetVal != ERROR_SUCCESS)
|
||
|
BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
|
||
|
|
||
|
//Now unregister provider binder from Root Binder.
|
||
|
//Cocreate Root Binder and get IRegisterProvider interface.
|
||
|
hr = CoCreateInstance ( DBGUID_ROOTBINDER,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(IRegisterProvider),
|
||
|
(void **) &pRegisterProvider
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Unregister each provider with the root binder
|
||
|
for ( PROUTER_ENTRY pProvider = g_pRouterHead;
|
||
|
pProvider != NULL;
|
||
|
pProvider=pProvider->pNext)
|
||
|
{
|
||
|
// Invalid provider ProgID? If so, continue with next provider
|
||
|
if (NULL == pProvider->szProviderProgId)
|
||
|
continue;
|
||
|
|
||
|
pRegisterProvider->UnregisterProvider(
|
||
|
pProvider->szProviderProgId,
|
||
|
0,
|
||
|
CLSID_ADSI_BINDER);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
CoTaskMemFree(pwszClsid);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return hr;
|
||
|
}
|