Leaked source code of windows server 2003
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.

746 lines
21 KiB

  1. #include "oleds.hxx"
  2. #include "bindercf.hxx"
  3. #include "atlbase.h"
  4. #pragma hdrstop
  5. //+---------------------------------------------------------------------------
  6. //
  7. // Microsoft Windows
  8. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  9. //
  10. // File: libmain.cxx
  11. //
  12. // Contents: LibMain for ADs.dll
  13. //
  14. // Functions: LibMain, DllGetClassObject
  15. //
  16. // History: 25-Oct-94 KrishnaG Created.
  17. //
  18. //----------------------------------------------------------------------------
  19. HINSTANCE g_hInst = NULL;
  20. PROUTER_ENTRY g_pRouterHead = NULL;
  21. CRITICAL_SECTION g_csRouterHeadCritSect;
  22. //
  23. // Dll's we load dynamically.
  24. //
  25. extern HANDLE g_hDllAdvapi32;
  26. extern const GUID DBGUID_ROOTBINDER =
  27. {0xFF151822, 0xB0BF, 0x11D1, {0xA8, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
  28. //---------------------------------------------------------------------------
  29. // ADs debug print, mem leak and object tracking-related stuff
  30. //---------------------------------------------------------------------------
  31. DECLARE_INFOLEVEL(ADs)
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Function: ShutDown
  35. //
  36. // Synopsis: Function to handle printing out heap debugging display
  37. //
  38. //----------------------------------------------------------------------------
  39. inline VOID ShutDown()
  40. {
  41. #if DBG==1
  42. #ifndef MSVC
  43. DUMP_TRACKING_INFO_DELETE();
  44. AllocArenaDump( NULL );
  45. DeleteCriticalSection(&g_csOT);
  46. #endif // ifndef MSVC
  47. DeleteCriticalSection(&g_csDP);
  48. #endif
  49. }
  50. extern "C" DWORD heapInfoLevel;
  51. extern "C" DWORD OtInfoLevel;
  52. extern "C" DWORD ADsInfoLevel;
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Function: GetINIHeapInfoLevel
  56. //
  57. // Synopsis: Gets various infolevel values from win.ini
  58. //
  59. //----------------------------------------------------------------------------
  60. inline VOID GetINIHeapInfoLevel()
  61. {
  62. #if DBG==1
  63. const INT MAXINFOLEN=11;
  64. WCHAR awcs[MAXINFOLEN];
  65. #ifndef MSVC
  66. if (GetProfileString(L"ADs",L"heapInfoLevel", L"00000003", awcs,MAXINFOLEN))
  67. heapInfoLevel = wcstoul(awcs, NULL, 16);
  68. if (GetProfileString(L"ADs",L"Ot", L"00000003", awcs, MAXINFOLEN))
  69. OtInfoLevel = wcstoul(awcs, NULL, 16);
  70. #endif // MSVC
  71. if (GetProfileString(L"ADs",L"ADsInfoLevel", L"00000003", awcs,MAXINFOLEN))
  72. ADsInfoLevel = wcstoul(awcs, NULL, 16);
  73. #endif
  74. }
  75. // Globals
  76. ULONG g_ulObjCount = 0; // Number of objects alivein ADs.dll
  77. //+------------------------------------------------------------------------
  78. //
  79. // Macro that calculates the number of elements in a statically-defined
  80. // array.
  81. //
  82. // Note - I swiped this from formsary.cxx - A type-safe array class. Remember
  83. // to swipe the whole thing as required.
  84. //-------------------------------------------------------------------------
  85. #define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
  86. //+------------------------------------------------------------------------
  87. //
  88. // ADs class factories
  89. //
  90. //-------------------------------------------------------------------------
  91. CADsNamespacesCF g_cfNamespaces;
  92. CADsProviderCF g_cfProvider;
  93. CDSOCF g_cfDSO;
  94. CADsSecurityDescriptorCF g_cfSed;
  95. CADsAccessControlListCF g_cfAcl;
  96. CADsAccessControlEntryCF g_cfAce;
  97. CADsPropertyEntryCF g_cfPropEntry;
  98. CADsPropertyValueCF g_cfPropertyValue;
  99. CADsLargeIntegerCF g_cfLargeInteger;
  100. CADsBinderCF g_cfBinder;
  101. CPathnameCF g_cfPathname;
  102. CADsDNWithBinaryCF g_cfDNWithBinary;
  103. CADsDNWithStringCF g_cfDNWithString;
  104. CADsSecurityUtilityCF g_cfADsSecurityUtility;
  105. extern CRITICAL_SECTION g_DispTypeInfoCritSect;
  106. extern CRITICAL_SECTION g_StringsCriticalSection;
  107. struct CLSCACHE
  108. {
  109. const CLSID * pclsid;
  110. IClassFactory * pCF;
  111. };
  112. CLSCACHE g_aclscache[] =
  113. {
  114. &CLSID_ADsNamespaces, &g_cfNamespaces,
  115. &CLSID_ADsProvider, &g_cfProvider,
  116. &CLSID_ADsDSOObject, &g_cfDSO,
  117. &CLSID_SecurityDescriptor, &g_cfSed,
  118. &CLSID_AccessControlList, &g_cfAcl,
  119. &CLSID_AccessControlEntry, &g_cfAce,
  120. &CLSID_PropertyEntry, &g_cfPropEntry,
  121. &CLSID_PropertyValue, &g_cfPropertyValue,
  122. &CLSID_LargeInteger, &g_cfLargeInteger,
  123. &CLSID_ADSI_BINDER, &g_cfBinder,
  124. &CLSID_Pathname, &g_cfPathname,
  125. &CLSID_DNWithBinary, &g_cfDNWithBinary,
  126. &CLSID_DNWithString, &g_cfDNWithString,
  127. &CLSID_ADsSecurityUtility, &g_cfADsSecurityUtility
  128. };
  129. //------------------------------------------------------------------------
  130. // ATL Module definition
  131. //------------------------------------------------------------------------
  132. CComModule _Module;
  133. //+---------------------------------------------------------------
  134. //
  135. // Function: DllGetClassObject
  136. //
  137. // Synopsis: Standard DLL entrypoint for locating class factories
  138. //
  139. //----------------------------------------------------------------
  140. STDAPI
  141. DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID FAR* ppv)
  142. {
  143. HRESULT hr;
  144. size_t i;
  145. if( ppv == NULL )
  146. RRETURN( E_INVALIDARG );
  147. *ppv = NULL;
  148. for (i = 0; i < ARRAY_SIZE(g_aclscache); i++)
  149. {
  150. if (IsEqualCLSID(clsid, *g_aclscache[i].pclsid))
  151. {
  152. hr = g_aclscache[i].pCF->QueryInterface(iid, ppv);
  153. RRETURN(hr);
  154. }
  155. }
  156. *ppv = NULL;
  157. //
  158. // Add Debugging Code to indicate that the ADs.DllGetClassObject
  159. // has been called with an unknown CLSID.
  160. //
  161. return CLASS_E_CLASSNOTAVAILABLE;
  162. }
  163. //+---------------------------------------------------------------
  164. //
  165. // Function: DllCanUnloadNow
  166. //
  167. // Synopsis: Standard DLL entrypoint to determine if DLL can be unloaded
  168. //
  169. //---------------------------------------------------------------
  170. STDAPI
  171. DllCanUnloadNow(void)
  172. {
  173. HRESULT hr;
  174. hr = S_FALSE;
  175. if (DllReadyToUnload())
  176. hr = S_OK;
  177. return hr;
  178. }
  179. //+---------------------------------------------------------------
  180. //
  181. // Function: LibMain
  182. //
  183. // Synopsis: Standard DLL initialization entrypoint
  184. //
  185. //---------------------------------------------------------------
  186. EXTERN_C BOOL __cdecl
  187. LibMain(HINSTANCE hInst, ULONG ulReason, LPVOID pvReserved)
  188. {
  189. HRESULT hr;
  190. static UINT uiNumCritSectsInitialized = 0;
  191. switch (ulReason)
  192. {
  193. case DLL_PROCESS_ATTACH:
  194. //
  195. // Need to put in try catch block as init crit sects can fail.
  196. //
  197. __try {
  198. DisableThreadLibraryCalls(hInst);
  199. g_hInst = hInst;
  200. InitializeCriticalSection(&g_DispTypeInfoCritSect);
  201. ++uiNumCritSectsInitialized;
  202. InitializeCriticalSection(&g_StringsCriticalSection);
  203. ++uiNumCritSectsInitialized;
  204. InitializeCriticalSection(&g_csRouterHeadCritSect); // router initialization
  205. ++uiNumCritSectsInitialized;
  206. #if DBG==1
  207. InitializeCriticalSection(&g_csDP); // Used by ADsDebug
  208. ++uiNumCritSectsInitialized;
  209. #ifndef MSVC
  210. InitializeCriticalSection(&g_csOT); // Used by Object Tracker
  211. ++uiNumCritSectsInitialized;
  212. InitializeCriticalSection(&g_csMem); // Used by Object Tracker
  213. ++uiNumCritSectsInitialized;
  214. #endif
  215. #endif
  216. }
  217. __except (EXCEPTION_EXECUTE_HANDLER) {
  218. //
  219. // Critical failure
  220. //
  221. //
  222. // Delete the cs we init'ed. The fall through in each case is
  223. // intentional, as is the fact that we delete the critical sections
  224. // in the reverse order to which we initialized them.
  225. //
  226. switch(uiNumCritSectsInitialized)
  227. {
  228. #if DBG==1
  229. #ifndef MSVC
  230. case 6:
  231. DeleteCriticalSection(&g_csMem); // Used by Object Tracker
  232. case 5:
  233. DeleteCriticalSection(&g_csOT); // Used by Object Tracker
  234. #endif
  235. case 4:
  236. DeleteCriticalSection(&g_csDP); // Used by ADsDebug
  237. #endif
  238. case 3:
  239. DeleteCriticalSection(&g_csRouterHeadCritSect);
  240. case 2:
  241. DeleteCriticalSection(&g_StringsCriticalSection);
  242. case 1:
  243. DeleteCriticalSection(&g_DispTypeInfoCritSect);
  244. }
  245. //
  246. // Reset the counts of critical sections that we have initialized, just
  247. // in case LibMain(DLL_PROCESS_DETACH) does get called.
  248. //
  249. uiNumCritSectsInitialized = 0;
  250. return FALSE;
  251. }
  252. break;
  253. case DLL_PROCESS_DETACH:
  254. if (g_pRouterHead) {
  255. CleanupRouter(g_pRouterHead);
  256. }
  257. FreeTypeInfoTable();
  258. //
  259. // Delete the cs we init'ed. The fall through in each case is
  260. // intentional, as is the fact that we delete the critical sections
  261. // in the reverse order to which we initialized them.
  262. //
  263. switch(uiNumCritSectsInitialized)
  264. {
  265. #if DBG==1
  266. #ifndef MSVC
  267. case 6:
  268. DeleteCriticalSection(&g_csMem); // Used by Object Tracker
  269. case 5:
  270. DeleteCriticalSection(&g_csOT); // Used by Object Tracker
  271. #endif
  272. case 4:
  273. DeleteCriticalSection(&g_csDP); // Used by ADsDebug
  274. #endif
  275. case 3:
  276. DeleteCriticalSection(&g_csRouterHeadCritSect);
  277. case 2:
  278. DeleteCriticalSection(&g_StringsCriticalSection);
  279. case 1:
  280. DeleteCriticalSection(&g_DispTypeInfoCritSect);
  281. }
  282. //
  283. // Free any libs we loaded using loadlibrary
  284. //
  285. if (g_hDllAdvapi32) {
  286. FreeLibrary((HMODULE) g_hDllAdvapi32);
  287. g_hDllAdvapi32 = NULL;
  288. }
  289. break;
  290. default:
  291. break;
  292. }
  293. return TRUE;
  294. }
  295. //+---------------------------------------------------------------------------
  296. //
  297. // Function: DllMain
  298. //
  299. // Synopsis: entry point for NT - post .546
  300. //
  301. //----------------------------------------------------------------------------
  302. BOOL
  303. DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
  304. {
  305. return LibMain((HINSTANCE)hDll, dwReason, lpReserved);
  306. }
  307. //+------------------------------------------------------------------------
  308. //
  309. // Function: GetCachedClsidIndex
  310. //
  311. // Synopsis: Returns the index of the given CLSID in the cache, or
  312. // -1 if the CLSID is not present in the cache
  313. //
  314. // Arguments: [clsid]
  315. //
  316. // Returns: int
  317. //
  318. //-------------------------------------------------------------------------
  319. int
  320. GetCachedClsidIndex(REFCLSID clsid)
  321. {
  322. int i;
  323. CLSCACHE * pclscache;
  324. for (i = 0, pclscache = g_aclscache;
  325. i < ARRAY_SIZE(g_aclscache);
  326. i ++, pclscache++)
  327. {
  328. if (IsEqualCLSID(*pclscache->pclsid, clsid))
  329. return i;
  330. }
  331. return -1;
  332. }
  333. //+------------------------------------------------------------------------
  334. //
  335. // Function: GetCachedClassFactory
  336. //
  337. // Synopsis: Returns the cached class factory with the given index.
  338. // The pointer returned has been AddRef'd.
  339. //
  340. // Arguments: [iclsid]
  341. //
  342. // Returns: IClassFactory *
  343. //
  344. //-------------------------------------------------------------------------
  345. IClassFactory *
  346. GetCachedClassFactory(int iclsid)
  347. {
  348. IClassFactory * pCF;
  349. // Assert(iclsid >= 0);
  350. // Assert(iclsid < ARRAY_SIZE(g_aclscache));
  351. pCF = g_aclscache[iclsid].pCF;
  352. pCF->AddRef();
  353. return pCF;
  354. }
  355. //+------------------------------------------------------------------------
  356. //
  357. // Function: GetCachedClsid
  358. //
  359. // Synopsis: Returns the CLSID corresponding to the given index.
  360. // Normally, code should call GetCachedClassFactory to get
  361. // the class factory directly.
  362. //
  363. // Arguments: [iclsid] -- Clsid index
  364. // [pclsid] -- Matching clsid returned in *pclsid
  365. //
  366. //-------------------------------------------------------------------------
  367. void
  368. GetCachedClsid(int iclsid, CLSID * pclsid)
  369. {
  370. // Assert(iclsid >= 0);
  371. // Assert(iclsid < ARRAY_SIZE(g_aclscache));
  372. *pclsid = *g_aclscache[iclsid].pclsid;
  373. }
  374. STDAPI DllRegisterServer()
  375. {
  376. PWCHAR pwszClsid = NULL;
  377. WCHAR pwszSubKey[256];
  378. const WCHAR pwTypeLibraryName[] = L"activeds.tlb";
  379. // 15 includes name of the type libaray, NULL terminator, backslash and one extra space
  380. WCHAR pwTypeLibPath[MAX_PATH + 15] = L"";
  381. HRESULT hr = S_OK;
  382. #if (!defined(BUILD_FOR_NT40))
  383. auto_rel<IRegisterProvider> pRegisterProvider;
  384. wcscpy(pwszSubKey, L"SOFTWARE\\Classes\\CLSID\\");
  385. hr = StringFromCLSID(CLSID_ADSI_BINDER, &pwszClsid);
  386. if (FAILED(hr))
  387. return hr;
  388. wcscat(pwszSubKey, pwszClsid);
  389. HKEY hKeyClsid = NULL, hKeyDll = NULL;
  390. DWORD dwDisposition;
  391. LONG lRetVal;
  392. ITypeLib *pITypeLib = NULL;
  393. UINT iSize = 0;
  394. //
  395. // Make sure the router has been initialized
  396. //
  397. EnterCriticalSection(&g_csRouterHeadCritSect);
  398. if (!g_pRouterHead) {
  399. g_pRouterHead = InitializeRouter();
  400. }
  401. LeaveCriticalSection(&g_csRouterHeadCritSect);
  402. //Create CLSID entry
  403. lRetVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  404. pwszSubKey,
  405. 0,
  406. L"",
  407. 0,
  408. KEY_ALL_ACCESS,
  409. NULL,
  410. &hKeyClsid,
  411. &dwDisposition);
  412. if (lRetVal != ERROR_SUCCESS)
  413. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  414. //set the value
  415. lRetVal = RegSetValueEx(hKeyClsid,
  416. NULL,
  417. 0,
  418. REG_SZ,
  419. (CONST BYTE *)L"Provider Binder for DS OLE DB Provider",
  420. 78);
  421. if (lRetVal != ERROR_SUCCESS)
  422. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  423. //Create InprocServer32 entry
  424. lRetVal = RegCreateKeyEx(hKeyClsid,
  425. L"InprocServer32",
  426. 0,
  427. L"activeds.dll",
  428. 0,
  429. KEY_ALL_ACCESS,
  430. NULL,
  431. &hKeyDll,
  432. &dwDisposition);
  433. if (lRetVal != ERROR_SUCCESS)
  434. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  435. //set the value
  436. lRetVal = RegSetValueEx(hKeyDll,
  437. NULL,
  438. 0,
  439. REG_SZ,
  440. (CONST BYTE *)L"activeds.dll",
  441. 26);
  442. if (lRetVal != ERROR_SUCCESS)
  443. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  444. //Now set the threadingModel value for the dll key
  445. lRetVal = RegSetValueEx(hKeyDll,
  446. L"ThreadingModel",
  447. 0,
  448. REG_SZ,
  449. (CONST BYTE *)L"Both",
  450. 10);
  451. if (lRetVal != ERROR_SUCCESS)
  452. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  453. //Now register the provider with the root binder.
  454. //Cocreate Root Binder and get IRegisterProvider interface.
  455. hr = CoCreateInstance ( DBGUID_ROOTBINDER,
  456. NULL,
  457. CLSCTX_ALL,
  458. __uuidof(IRegisterProvider),
  459. (void **) &pRegisterProvider
  460. );
  461. if (SUCCEEDED(hr))
  462. {
  463. // Go through list of ADS providers and register each of them
  464. // with the root binder.
  465. for ( PROUTER_ENTRY pProvider = g_pRouterHead;
  466. pProvider != NULL;
  467. pProvider=pProvider->pNext)
  468. {
  469. // Invalid provider ProgID? If so, continue with next provider
  470. if (NULL == pProvider->szProviderProgId)
  471. continue;
  472. hr = pRegisterProvider->SetURLMapping(
  473. pProvider->szProviderProgId,
  474. 0,
  475. CLSID_ADSI_BINDER);
  476. if (FAILED(hr))
  477. AtlTrace(_T("Failed to register %s mapping hr = %x\n"),
  478. pProvider->szProviderProgId, hr);
  479. // Ignore error and continue with next provider
  480. hr = S_OK;
  481. }
  482. }
  483. else
  484. {
  485. AtlTrace(_T("Creation of Root Binder failed! hr = %x\n"), hr);
  486. goto error;
  487. }
  488. // register our activeds.tlb
  489. iSize = GetSystemDirectoryW(pwTypeLibPath, MAX_PATH + 1);
  490. if(iSize == 0 || iSize > MAX_PATH + 1) {
  491. wcscpy(pwTypeLibPath, pwTypeLibraryName);
  492. }
  493. else {
  494. wcscat(pwTypeLibPath, L"\\");
  495. wcscat(pwTypeLibPath,pwTypeLibraryName);
  496. }
  497. hr = LoadTypeLib(pwTypeLibPath, &pITypeLib);
  498. if(FAILED(hr))
  499. {
  500. AtlTrace(_T("LoadTypeLib() failed! hr=%x\n"), hr);
  501. goto error;
  502. }
  503. hr = RegisterTypeLib(pITypeLib, pwTypeLibPath, NULL);
  504. if(FAILED(hr))
  505. {
  506. AtlTrace(_T("RegisterTypeLib() failed! hr=%x\n"), hr);
  507. }
  508. error:
  509. CoTaskMemFree(pwszClsid);
  510. if (hKeyClsid) {
  511. RegCloseKey(hKeyClsid);
  512. }
  513. if (hKeyDll) {
  514. RegCloseKey(hKeyDll);
  515. }
  516. if(pITypeLib) {
  517. pITypeLib->Release();
  518. }
  519. #endif
  520. return hr;
  521. }
  522. STDAPI DllUnregisterServer()
  523. {
  524. PWCHAR pwszClsid = NULL;
  525. WCHAR pwszClsidKey[256];
  526. WCHAR pwszDllKey[256];
  527. HRESULT hr = S_OK;
  528. LONG lRetVal;
  529. ITypeLib *pITypeLib = NULL;
  530. const WCHAR pwTypeLibraryName[] = L"activeds.tlb";
  531. // 15 includes name of the type libaray, NULL terminator, backslash and one extra space
  532. WCHAR pwTypeLibPath[MAX_PATH + 15] = L"";
  533. TLIBATTR* pTLibAttr = NULL;
  534. UINT iSize = 0;
  535. #if (!defined(BUILD_FOR_NT40))
  536. auto_rel<IRegisterProvider> pRegisterProvider;
  537. wcscpy(pwszClsidKey, L"SOFTWARE\\Classes\\CLSID\\");
  538. hr = StringFromCLSID(CLSID_ADSI_BINDER, &pwszClsid);
  539. if (FAILED(hr))
  540. return hr;
  541. wcscat(pwszClsidKey, pwszClsid);
  542. wcscpy(pwszDllKey, pwszClsidKey);
  543. wcscat(pwszDllKey, L"\\InprocServer32");
  544. //
  545. // Make sure the router has been initialized
  546. //
  547. EnterCriticalSection(&g_csRouterHeadCritSect);
  548. if (!g_pRouterHead) {
  549. g_pRouterHead = InitializeRouter();
  550. }
  551. LeaveCriticalSection(&g_csRouterHeadCritSect);
  552. //Delete InprocServer32 key
  553. lRetVal = RegDeleteKey(HKEY_LOCAL_MACHINE, pwszDllKey);
  554. if (lRetVal != ERROR_SUCCESS)
  555. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  556. //Delete key and all its subkeys.
  557. lRetVal = RegDeleteKey(HKEY_LOCAL_MACHINE, pwszClsidKey);
  558. if (lRetVal != ERROR_SUCCESS)
  559. BAIL_ON_FAILURE(HRESULT_FROM_WIN32(lRetVal));
  560. //Now unregister provider binder from Root Binder.
  561. //Cocreate Root Binder and get IRegisterProvider interface.
  562. hr = CoCreateInstance ( DBGUID_ROOTBINDER,
  563. NULL,
  564. CLSCTX_ALL,
  565. __uuidof(IRegisterProvider),
  566. (void **) &pRegisterProvider
  567. );
  568. if (SUCCEEDED(hr))
  569. {
  570. // Unregister each provider with the root binder
  571. for ( PROUTER_ENTRY pProvider = g_pRouterHead;
  572. pProvider != NULL;
  573. pProvider=pProvider->pNext)
  574. {
  575. // Invalid provider ProgID? If so, continue with next provider
  576. if (NULL == pProvider->szProviderProgId)
  577. continue;
  578. pRegisterProvider->UnregisterProvider(
  579. pProvider->szProviderProgId,
  580. 0,
  581. CLSID_ADSI_BINDER);
  582. }
  583. // Unregister the type library
  584. iSize = GetSystemDirectoryW(pwTypeLibPath, MAX_PATH + 1);
  585. if(iSize == 0 || iSize > MAX_PATH + 1) {
  586. wcscpy(pwTypeLibPath, pwTypeLibraryName);
  587. }
  588. else {
  589. wcscat(pwTypeLibPath, L"\\");
  590. wcscat(pwTypeLibPath,pwTypeLibraryName);
  591. }
  592. hr = LoadTypeLib(pwTypeLibPath, &pITypeLib);
  593. if (SUCCEEDED(hr)) {
  594. hr = pITypeLib->GetLibAttr(&pTLibAttr);
  595. if(SUCCEEDED(hr)) {
  596. hr = UnRegisterTypeLib(pTLibAttr->guid,
  597. pTLibAttr->wMajorVerNum,
  598. pTLibAttr->wMinorVerNum,
  599. pTLibAttr->lcid,
  600. pTLibAttr->syskind);
  601. pITypeLib->ReleaseTLibAttr(pTLibAttr);
  602. }
  603. pITypeLib->Release();
  604. }
  605. }
  606. error:
  607. CoTaskMemFree(pwszClsid);
  608. #endif
  609. return hr;
  610. }