Source code of Windows XP (NT5)
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.

676 lines
18 KiB

  1. /************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name :
  4. registry.cpp
  5. Abstract :
  6. Handles registering and unregistering the snapin.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #include "precomp.h"
  11. #include "sddl.h"
  12. // if not standalone comment out next line
  13. //#define STANDALONE
  14. // list all nodes that are extendable here
  15. // List the GUID and then the description
  16. // terminate with a NULL, NULL set.
  17. EXTENSION_NODE _ExtendableNodes[] = {
  18. {NULL, NULL}
  19. };
  20. // list all of the nodes that we extend
  21. EXTENDER_NODE _NodeExtensions[] = {
  22. // IIS instance node
  23. {PropertySheetExtension,
  24. {0xa841b6c7, 0x7577, 0x11d0, {0xbb, 0x1f, 0x00, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}}, //g_IISInstanceNode,
  25. {0x4589a47e, 0x6ec1, 0x4476, {0xba, 0x77, 0xcc, 0x9d, 0xd1, 0x12, 0x59, 0x33}},
  26. _T("BITS server MMC extension")},
  27. // IIS child node
  28. {PropertySheetExtension,
  29. {0xa841b6c8, 0x7577, 0x11d0, {0xbb, 0x1f, 0x00, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}}, // g_IISChildNode,
  30. {0x4589a47e, 0x6ec1, 0x4476, {0xba, 0x77, 0xcc, 0x9d, 0xd1, 0x12, 0x59, 0x33}},
  31. _T("BITS server MMC extension")},
  32. {DummyExtension,
  33. NULL,
  34. NULL,
  35. NULL}
  36. };
  37. ////////////////////////////////////////////////////////
  38. //
  39. // Internal helper functions prototypes
  40. //
  41. // Set the given key and its value.
  42. BOOL setKeyAndValue(const _TCHAR* pszPath,
  43. const _TCHAR* szSubkey,
  44. const _TCHAR* szValue) ;
  45. // Set the given key and its value in the MMC Snapin location
  46. BOOL setSnapInKeyAndValue(const _TCHAR* szKey,
  47. const _TCHAR* szSubkey,
  48. const _TCHAR* szName,
  49. const _TCHAR* szValue);
  50. // Set the given valuename under the key to value
  51. BOOL setValue(const _TCHAR* szKey,
  52. const _TCHAR* szValueName,
  53. const _TCHAR* szValue);
  54. BOOL setBinaryValue(
  55. const _TCHAR* szKey,
  56. const _TCHAR* szValueName,
  57. void * Data,
  58. ULONG DataSize );
  59. BOOL setSnapInExtensionNode(const _TCHAR* szSnapID,
  60. const _TCHAR* szNodeID,
  61. const _TCHAR* szDescription);
  62. // Delete szKeyChild and all of its descendents.
  63. LONG recursiveDeleteKey(HKEY hKeyParent, const _TCHAR* szKeyChild) ;
  64. ////////////////////////////////////////////////////////
  65. //
  66. // Constants
  67. //
  68. // Size of a CLSID as a string
  69. //const int CLSID_STRING_SIZE = 39 ;
  70. #if defined( UNICODE ) || defined( _UNICODE )
  71. const DWORD MAX_GUID_CHARS = 50;
  72. #else
  73. const DWORD MAX_GUID_CHARS = 50 * 8; // worst encoding
  74. #endif
  75. /////////////////////////////////////////////////////////
  76. //
  77. // Public function implementation
  78. //
  79. //
  80. // Register the component in the registry.
  81. //
  82. #if defined ( UNICODE ) || defined( _UNICODE )
  83. HRESULT
  84. StringFromGUIDInternal(
  85. const CLSID& clsid,
  86. _TCHAR * szGuidString
  87. )
  88. {
  89. return StringFromGUID2( clsid, szGuidString, MAX_GUID_CHARS );
  90. }
  91. #else
  92. #error Provide a unicode to DBCS thunk version
  93. #endif
  94. HRESULT RegisterServer(HMODULE hModule, // DLL module handle
  95. const CLSID& clsid, // Class ID
  96. const _TCHAR* szFriendlyName,
  97. const _TCHAR* ThreadingModel,
  98. bool Remoteable,
  99. const _TCHAR* SecurityString ) // IDs
  100. {
  101. // Get server location.
  102. _TCHAR szModule[512] ;
  103. DWORD dwResult =
  104. ::GetModuleFileName(hModule,
  105. szModule,
  106. sizeof(szModule)/sizeof(_TCHAR)) ;
  107. if ( !dwResult )
  108. {
  109. assert(dwResult != 0) ;
  110. return HRESULT_FROM_WIN32( GetLastError() );
  111. }
  112. // Get CLSID
  113. _TCHAR szCLSID[ MAX_GUID_CHARS ];
  114. HRESULT Hr = StringFromGUIDInternal( clsid, szCLSID );
  115. if ( FAILED( Hr ) )
  116. {
  117. assert( 0 );
  118. return Hr;
  119. }
  120. // Build the key CLSID\\{...}
  121. _TCHAR szKey[64] ;
  122. StringCbCopy(szKey, sizeof(szKey), _T("CLSID\\")) ;
  123. StringCbCat(szKey, sizeof(szKey), szCLSID) ;
  124. // Add the CLSID to the registry.
  125. setKeyAndValue(szKey, NULL, szFriendlyName) ;
  126. if ( Remoteable )
  127. setValue( szKey, _T("AppID"), szCLSID );
  128. // Add the server filename subkey under the CLSID key.
  129. setKeyAndValue(szKey, _T("InprocServer32"), szModule) ;
  130. // set the threading model
  131. StringCbCat(szKey, sizeof(szKey), _T("\\InprocServer32"));
  132. setValue(szKey, _T("ThreadingModel"), ThreadingModel);
  133. if ( Remoteable )
  134. {
  135. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  136. ULONG DescriptorSize;
  137. // build the key name
  138. StringCbCopy(szKey, sizeof(szKey), _T("AppId\\")) ;
  139. StringCbCat(szKey, sizeof(szKey), szCLSID) ;
  140. setKeyAndValue(szKey, NULL, szFriendlyName) ;
  141. setValue(szKey, _T("DllSurrogate"), _T("") );
  142. if ( !ConvertStringSecurityDescriptorToSecurityDescriptor(
  143. SecurityString,
  144. SDDL_REVISION_1,
  145. &SecurityDescriptor,
  146. &DescriptorSize
  147. ) )
  148. return HRESULT_FROM_WIN32( GetLastError() );
  149. setBinaryValue( szKey, _T("LaunchPermission"), SecurityDescriptor, DescriptorSize );
  150. setBinaryValue( szKey, _T("AccessPermission"), SecurityDescriptor, DescriptorSize );
  151. LocalFree( (HLOCAL)SecurityDescriptor );
  152. }
  153. return S_OK ;
  154. }
  155. //
  156. // Remove the component from the registry.
  157. //
  158. LONG UnregisterServer(const CLSID& clsid) // IDs
  159. {
  160. // Get CLSID
  161. _TCHAR szCLSID[ MAX_GUID_CHARS ];
  162. HRESULT Hr = StringFromGUIDInternal( clsid, szCLSID );
  163. if ( FAILED( Hr ) )
  164. {
  165. assert( 0 );
  166. return Hr;
  167. }
  168. // Build the key CLSID\\{...}
  169. _TCHAR szKey[64] ;
  170. StringCbCopy( szKey, sizeof(szKey), _T("CLSID\\") );
  171. StringCbCat( szKey, sizeof(szKey), szCLSID );
  172. // Delete the CLSID Key - CLSID\{...}
  173. LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey) ;
  174. assert((lResult == ERROR_SUCCESS) ||
  175. (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.
  176. StringCbCopy(szKey, sizeof(szKey), _T("AppId\\"));
  177. StringCbCat(szKey, sizeof(szKey), szCLSID );
  178. lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey);
  179. return S_OK;
  180. }
  181. //
  182. // Register the snap-in in the registry.
  183. //
  184. HRESULT RegisterSnapin(const CLSID& clsid, // Class ID
  185. const _TCHAR* szNameString, // NameString
  186. const CLSID& clsidAbout) // Class Id for About Class
  187. {
  188. // Get CLSID
  189. _TCHAR szCLSID[ MAX_GUID_CHARS ];
  190. _TCHAR szAboutCLSID[ MAX_GUID_CHARS ];
  191. EXTENSION_NODE *pExtensionNode;
  192. EXTENDER_NODE *pNodeExtension;
  193. _TCHAR szKeyBuf[1024] ;
  194. HKEY hKey;
  195. HRESULT Hr = StringFromGUIDInternal(clsid, szCLSID);
  196. if ( FAILED( Hr ) )
  197. {
  198. assert( 0 );
  199. return Hr;
  200. }
  201. if (IID_NULL != clsidAbout)
  202. Hr = StringFromGUIDInternal(clsidAbout, szAboutCLSID);
  203. if ( FAILED( Hr ) )
  204. {
  205. assert( 0 );
  206. return Hr;
  207. }
  208. // Add the CLSID to the registry.
  209. setSnapInKeyAndValue(szCLSID, NULL, _T("NameString"), szNameString) ;
  210. #ifdef STANDALONE
  211. setSnapInKeyAndValue(szCLSID, _T("StandAlone"), NULL, NULL);
  212. #endif
  213. if (IID_NULL != clsidAbout)
  214. setSnapInKeyAndValue(szCLSID, NULL, _T("About"), szAboutCLSID);
  215. // register each of the node types in _ExtendableNodes as an extendable node
  216. for (pExtensionNode = &(_ExtendableNodes[0]);*pExtensionNode->szDescription;pExtensionNode++)
  217. {
  218. _TCHAR szExtendCLSID[ MAX_GUID_CHARS ];
  219. Hr = StringFromGUIDInternal(pExtensionNode->GUID, szExtendCLSID);
  220. if ( FAILED( Hr ) )
  221. {
  222. assert( 0 );
  223. return Hr;
  224. }
  225. setSnapInExtensionNode(szCLSID, szExtendCLSID, pExtensionNode->szDescription);
  226. }
  227. // register each of the node extensions
  228. for (pNodeExtension = &(_NodeExtensions[0]);*pNodeExtension->szDescription;pNodeExtension++)
  229. {
  230. _TCHAR szExtendCLSID[ MAX_GUID_CHARS ];
  231. Hr = StringFromGUIDInternal(pNodeExtension->guidNode, szExtendCLSID);
  232. if ( FAILED( Hr ) )
  233. {
  234. assert(0);
  235. return Hr;
  236. }
  237. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), _T("SOFTWARE\\Microsoft\\MMC\\NodeTypes\\"));
  238. StringCbCat(szKeyBuf, sizeof( szKeyBuf), szExtendCLSID);
  239. switch (pNodeExtension->eType) {
  240. case NameSpaceExtension:
  241. StringCbCat( szKeyBuf, sizeof( szKeyBuf ), _T("\\Extensions\\NameSpace") );
  242. break;
  243. case ContextMenuExtension:
  244. StringCbCat( szKeyBuf, sizeof( szKeyBuf ), _T("\\Extensions\\ContextMenu") );
  245. break;
  246. case ToolBarExtension:
  247. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\Extensions\\ToolBar"));
  248. break;
  249. case PropertySheetExtension:
  250. StringCchCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\Extensions\\PropertySheet"));
  251. break;
  252. case TaskExtension:
  253. StringCchCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\Extensions\\Task"));
  254. break;
  255. case DynamicExtension:
  256. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\Dynamic Extensions"));
  257. default:
  258. break;
  259. }
  260. // Create and open key and subkey.
  261. long lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE ,
  262. szKeyBuf,
  263. 0, NULL, REG_OPTION_NON_VOLATILE,
  264. KEY_ALL_ACCESS, NULL,
  265. &hKey, NULL) ;
  266. if (lResult != ERROR_SUCCESS)
  267. {
  268. return FALSE ;
  269. }
  270. _TCHAR szNodeCLSID[ MAX_GUID_CHARS ];
  271. Hr = StringFromGUIDInternal(pNodeExtension->guidExtension, szNodeCLSID);
  272. if ( FAILED(Hr) )
  273. {
  274. assert( 0 );
  275. return Hr;
  276. }
  277. // Set the Value.
  278. if (pNodeExtension->szDescription != NULL)
  279. {
  280. RegSetValueEx(hKey, szNodeCLSID, 0, REG_SZ,
  281. (BYTE *)pNodeExtension->szDescription,
  282. (_tcslen(pNodeExtension->szDescription)+1)*sizeof(_TCHAR)) ;
  283. }
  284. RegCloseKey(hKey);
  285. }
  286. return S_OK;
  287. }
  288. //
  289. // Unregister the snap-in in the registry.
  290. //
  291. HRESULT UnregisterSnapin(const CLSID& clsid) // Class ID
  292. {
  293. _TCHAR szKeyBuf[1024];
  294. _TCHAR szCLSID[ MAX_GUID_CHARS ];
  295. // Get CLSID
  296. HRESULT Hr = StringFromGUIDInternal(clsid, szCLSID);
  297. if ( FAILED( Hr ) )
  298. {
  299. assert( 0 );
  300. return Hr;
  301. }
  302. // Load the buffer with the Snap-In Location
  303. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), _T("SOFTWARE\\Microsoft\\MMC\\SnapIns"));
  304. // Copy keyname into buffer.
  305. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\"));
  306. StringCchCat(szKeyBuf, sizeof( szKeyBuf ), szCLSID);
  307. // Delete the CLSID Key - CLSID\{...}
  308. LONG lResult = recursiveDeleteKey(HKEY_LOCAL_MACHINE, szKeyBuf);
  309. assert((lResult == ERROR_SUCCESS) ||
  310. (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.
  311. return S_OK;
  312. }
  313. //
  314. // Delete a key and all of its descendents.
  315. //
  316. LONG recursiveDeleteKey(HKEY hKeyParent, // Parent of key to delete
  317. const _TCHAR* lpszKeyChild) // Key to delete
  318. {
  319. // Open the child.
  320. HKEY hKeyChild ;
  321. LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
  322. KEY_ALL_ACCESS, &hKeyChild) ;
  323. if (lRes != ERROR_SUCCESS)
  324. {
  325. return lRes ;
  326. }
  327. // Enumerate all of the decendents of this child.
  328. FILETIME time ;
  329. _TCHAR szBuffer[256] ;
  330. DWORD dwSize = 256 ;
  331. while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
  332. NULL, NULL, &time) == S_OK)
  333. {
  334. // Delete the decendents of this child.
  335. lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;
  336. if (lRes != ERROR_SUCCESS)
  337. {
  338. // Cleanup before exiting.
  339. RegCloseKey(hKeyChild) ;
  340. return lRes;
  341. }
  342. dwSize = 256 ;
  343. }
  344. // Close the child.
  345. RegCloseKey(hKeyChild) ;
  346. // Delete this child.
  347. return RegDeleteKey(hKeyParent, lpszKeyChild) ;
  348. }
  349. //
  350. // Create a key and set its value.
  351. // - This helper function was borrowed and modifed from
  352. // Kraig Brockschmidt's book Inside OLE.
  353. //
  354. BOOL setKeyAndValue(const _TCHAR* szKey,
  355. const _TCHAR* szSubkey,
  356. const _TCHAR* szValue)
  357. {
  358. HKEY hKey;
  359. _TCHAR szKeyBuf[1024] ;
  360. // Copy keyname into buffer.
  361. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), szKey) ;
  362. // Add subkey name to buffer.
  363. if (szSubkey != NULL)
  364. {
  365. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\")) ;
  366. StringCchCat(szKeyBuf, sizeof( szKeyBuf ), szSubkey ) ;
  367. }
  368. // Create and open key and subkey.
  369. long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
  370. szKeyBuf,
  371. 0, NULL, REG_OPTION_NON_VOLATILE,
  372. KEY_ALL_ACCESS, NULL,
  373. &hKey, NULL) ;
  374. if (lResult != ERROR_SUCCESS)
  375. {
  376. return FALSE ;
  377. }
  378. // Set the Value.
  379. if (szValue != NULL)
  380. {
  381. RegSetValueEx(hKey, NULL, 0, REG_SZ,
  382. (BYTE *)szValue,
  383. (_tcslen(szValue)+1)*sizeof(_TCHAR)) ;
  384. }
  385. RegCloseKey(hKey) ;
  386. return TRUE ;
  387. }
  388. //
  389. // Open a key value and set it
  390. //
  391. BOOL setValue(const _TCHAR* szKey,
  392. const _TCHAR* szValueName,
  393. const _TCHAR* szValue)
  394. {
  395. HKEY hKey;
  396. _TCHAR szKeyBuf[1024] ;
  397. // Copy keyname into buffer.
  398. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), szKey) ;
  399. // Create and open key and subkey.
  400. long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
  401. szKeyBuf,
  402. 0, NULL, REG_OPTION_NON_VOLATILE,
  403. KEY_ALL_ACCESS, NULL,
  404. &hKey, NULL) ;
  405. if (lResult != ERROR_SUCCESS)
  406. {
  407. return FALSE ;
  408. }
  409. // Set the Value.
  410. if (szValue != NULL)
  411. {
  412. RegSetValueEx(hKey, szValueName, 0, REG_SZ,
  413. (BYTE *)szValue,
  414. (_tcslen(szValue)+1)*sizeof(_TCHAR)) ;
  415. }
  416. RegCloseKey(hKey) ;
  417. return TRUE ;
  418. }
  419. //
  420. // Open a key value and set it
  421. //
  422. BOOL setBinaryValue(
  423. const _TCHAR* szKey,
  424. const _TCHAR* szValueName,
  425. void * Data,
  426. ULONG DataSize )
  427. {
  428. HKEY hKey;
  429. _TCHAR szKeyBuf[1024] ;
  430. // Copy keyname into buffer.
  431. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), szKey) ;
  432. // Create and open key and subkey.
  433. long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
  434. szKeyBuf,
  435. 0, NULL, REG_OPTION_NON_VOLATILE,
  436. KEY_ALL_ACCESS, NULL,
  437. &hKey, NULL) ;
  438. if (lResult != ERROR_SUCCESS)
  439. {
  440. return FALSE ;
  441. }
  442. // Set the Value.
  443. RegSetValueEx(hKey, szValueName, 0, REG_BINARY,
  444. (BYTE *)Data,
  445. DataSize ) ;
  446. RegCloseKey(hKey) ;
  447. return TRUE ;
  448. }
  449. //
  450. // Create a key and set its value.
  451. // - This helper function was borrowed and modifed from
  452. // Kraig Brockschmidt's book Inside OLE.
  453. //
  454. BOOL setSnapInKeyAndValue(const _TCHAR* szKey,
  455. const _TCHAR* szSubkey,
  456. const _TCHAR* szName,
  457. const _TCHAR* szValue)
  458. {
  459. HKEY hKey;
  460. _TCHAR szKeyBuf[1024] ;
  461. // Load the buffer with the Snap-In Location
  462. StringCbCopy(szKeyBuf, sizeof( szKeyBuf ), _T("SOFTWARE\\Microsoft\\MMC\\SnapIns"));
  463. // Copy keyname into buffer.
  464. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), _T("\\")) ;
  465. StringCbCat(szKeyBuf, sizeof( szKeyBuf ), szKey) ;
  466. // Add subkey name to buffer.
  467. if (szSubkey != NULL)
  468. {
  469. StringCbCat( szKeyBuf, sizeof( szKeyBuf ), _T("\\") ) ;
  470. StringCbCat( szKeyBuf, sizeof( szKeyBuf ), szSubkey ) ;
  471. }
  472. // Create and open key and subkey.
  473. long lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE ,
  474. szKeyBuf,
  475. 0, NULL, REG_OPTION_NON_VOLATILE,
  476. KEY_ALL_ACCESS, NULL,
  477. &hKey, NULL) ;
  478. if (lResult != ERROR_SUCCESS)
  479. {
  480. return FALSE ;
  481. }
  482. // Set the Value.
  483. if (szValue != NULL)
  484. {
  485. RegSetValueEx(hKey, szName, 0, REG_SZ,
  486. (BYTE *)szValue,
  487. (_tcslen(szValue)+1)*sizeof(_TCHAR)) ;
  488. }
  489. RegCloseKey(hKey) ;
  490. return TRUE ;
  491. }
  492. BOOL setSnapInExtensionNode(const _TCHAR* szSnapID,
  493. const _TCHAR* szNodeID,
  494. const _TCHAR* szDescription)
  495. {
  496. HKEY hKey;
  497. _TCHAR szSnapNodeKeyBuf[1024] ;
  498. _TCHAR szMMCNodeKeyBuf[1024];
  499. // Load the buffer with the Snap-In Location
  500. StringCbCopy(szSnapNodeKeyBuf, sizeof(szSnapNodeKeyBuf), _T("SOFTWARE\\Microsoft\\MMC\\SnapIns\\"));
  501. // add in the clisid into buffer.
  502. StringCbCat(szSnapNodeKeyBuf, sizeof(szSnapNodeKeyBuf), szSnapID) ;
  503. StringCbCat(szSnapNodeKeyBuf, sizeof(szSnapNodeKeyBuf), _T("\\NodeTypes\\"));
  504. StringCbCat(szSnapNodeKeyBuf, sizeof(szSnapNodeKeyBuf), szNodeID) ;
  505. // Load the buffer with the NodeTypes Location
  506. StringCbCopy(szMMCNodeKeyBuf, sizeof( szMMCNodeKeyBuf ), _T("SOFTWARE\\Microsoft\\MMC\\NodeTypes\\"));
  507. StringCchCat(szMMCNodeKeyBuf, sizeof( szMMCNodeKeyBuf ), szNodeID) ;
  508. // Create and open the Snapin Key.
  509. long lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE ,
  510. szSnapNodeKeyBuf,
  511. 0, NULL, REG_OPTION_NON_VOLATILE,
  512. KEY_ALL_ACCESS, NULL,
  513. &hKey, NULL) ;
  514. if (lResult != ERROR_SUCCESS)
  515. {
  516. return FALSE ;
  517. }
  518. // Set the Value.
  519. if (szDescription != NULL)
  520. {
  521. RegSetValueEx(hKey, NULL, 0, REG_SZ,
  522. (BYTE *)szDescription,
  523. (_tcslen(szDescription)+1)*sizeof(_TCHAR)) ;
  524. }
  525. RegCloseKey(hKey) ;
  526. // Create and open the NodeTypes Key.
  527. lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE ,
  528. szMMCNodeKeyBuf,
  529. 0, NULL, REG_OPTION_NON_VOLATILE,
  530. KEY_ALL_ACCESS, NULL,
  531. &hKey, NULL) ;
  532. if (lResult != ERROR_SUCCESS)
  533. {
  534. return FALSE ;
  535. }
  536. // Set the Value.
  537. if (szDescription != NULL)
  538. {
  539. RegSetValueEx(hKey, NULL, 0, REG_SZ,
  540. (BYTE *)szDescription,
  541. (_tcslen(szDescription)+1)*sizeof(_TCHAR)) ;
  542. }
  543. RegCloseKey(hKey) ;
  544. return TRUE ;
  545. }