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.

1245 lines
46 KiB

  1. ////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997-2001 Microsoft Corporation, All rights reserved
  4. //
  5. // Module: regcode.cpp
  6. //
  7. // Implements the Service registration routines
  8. //
  9. // History:
  10. //
  11. // ivanbrug 17-09-2000 CreateF
  12. //
  13. //
  14. //
  15. ////////////////////////////////////////////////////////////////////////
  16. #include "precomp.h"
  17. #include <winmgmt.h>
  18. #include <strings.h> // for LoadString
  19. #include <malloc.h>
  20. #include <winntsec.h>
  21. #include <autoptr.h>
  22. #include <strutils.h>
  23. #define SVCHOST_HOME TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost")
  24. #define SERVICE_PATH TEXT("System\\CurrentControlSet\\Services\\")
  25. #define DLL_PATH TEXT("%SystemRoot%\\system32\\wbem\\WMIsvc.dll")
  26. #define ENTRY_POINT TEXT("ServiceMain")
  27. #define COM_APPID TEXT("Software\\classes\\AppID\\{8BC3F05E-D86B-11D0-A075-00C04FB68820}")
  28. //= Windows Management Instrumentation
  29. //LocalService = WinMgmt
  30. #define COM_APPID_NAME TEXT("Software\\classes\\AppID\\winmgmt")
  31. //AppID = {8BC3F05E-D86B-11D0-A075-00C04FB68820}
  32. #define SERVICE_CLSID TEXT("{8BC3F05E-D86B-11D0-A075-00C04FB68820}")
  33. #define SERVICE_NAME_GROUP_ALONE TEXT("winmgmt")
  34. #define SERVICE_NAME_GROUP TEXT("netsvcs")
  35. #define SERVICE_NAME_GROUP_TOGETHER TEXT("netsvcs")
  36. // see winmgmt.h
  37. //#define SERVICE_NAME TEXT("winmgmt")
  38. #define VALUE_AUTH TEXT("AuthenticationCapabilities")
  39. #define VALUE_COINIT TEXT("CoInitializeSecurityParam")
  40. #define VALUE_AUTZN TEXT("AuthenticationLevel")
  41. #define VALUE_IMPER TEXT("ImpersonationLevel")
  42. #define ACCOUNT_NAME TEXT("LocalService") // unused, for now
  43. #define DISPLAY_CLSID TEXT("Windows Management and Instrumentation")
  44. #define DISPLAY_BACKUP_CLSID TEXT("Windows Management Instrumentation Backup and Recovery")
  45. //
  46. // for the Description string
  47. //
  48. #define MAX_BUFF 2048
  49. //
  50. // this is the rundll32 interface
  51. // usage is
  52. // C:\>rundll32 %windir%\system32\wbem\wmisvc.dll,MoveToAlone X
  53. // where X is the AuthenticationLevel
  54. //
  55. //////////////////////////////////////////////////////////////////
  56. void CALLBACK
  57. MoveToAlone(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) //RPC_C_AUTHN_LEVEL_CONNECT
  58. {
  59. BOOL bRet = TRUE;
  60. LONG lRet;
  61. DWORD dwLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  62. if (lpszCmdLine)
  63. {
  64. dwLevel = atoi(lpszCmdLine);
  65. if (0 == dwLevel) // in case of error
  66. {
  67. dwLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  68. }
  69. }
  70. if (bRet)
  71. {
  72. // create the new group key under svchost
  73. HKEY hKey;
  74. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  75. SVCHOST_HOME,
  76. 0,
  77. KEY_ALL_ACCESS,
  78. &hKey);
  79. if (ERROR_SUCCESS == lRet)
  80. {
  81. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm(hKey);
  82. // add the group
  83. LONG lRet2;
  84. DWORD dwCurrSize = 0;
  85. DWORD dwType;
  86. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,&dwType,NULL,&dwCurrSize);
  87. if (ERROR_SUCCESS == lRet2)
  88. {
  89. // the key is there, append to the multistring
  90. BYTE * pMulti = new BYTE[(dwCurrSize+sizeof(SERVICE_NAME)+4)];
  91. wmilib::auto_buffer<BYTE> rm_(pMulti);
  92. if (pMulti)
  93. {
  94. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,&dwType,pMulti,&dwCurrSize);
  95. if (ERROR_SUCCESS == lRet2 && REG_MULTI_SZ == dwType)
  96. {
  97. TCHAR * pInsertPoint = (TCHAR *)(pMulti+dwCurrSize-sizeof(TCHAR));
  98. // verify the multisz
  99. TCHAR *pEnd = (TCHAR *)pMulti;
  100. BOOL bIsThere = FALSE;
  101. while (*pEnd)
  102. {
  103. if (0 == wbem_wcsicmp(pEnd,SERVICE_NAME))
  104. {
  105. bIsThere = TRUE;
  106. }
  107. while (*pEnd){
  108. pEnd++;
  109. }
  110. pEnd++; // past the zero who terminates the string
  111. }
  112. if (!bIsThere)
  113. {
  114. if ((ULONG_PTR)pEnd == (ULONG_PTR)pInsertPoint)
  115. {
  116. wcsncpy(pEnd,SERVICE_NAME TEXT("\0"),sizeof(SERVICE_NAME)/sizeof(TCHAR)+1);
  117. DWORD dwNowSize = dwCurrSize+sizeof(SERVICE_NAME);
  118. if (ERROR_SUCCESS == RegSetValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,REG_MULTI_SZ,pMulti,dwNowSize))
  119. bRet = TRUE;
  120. else
  121. bRet = FALSE;
  122. }
  123. else
  124. {
  125. bRet = FALSE;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. else if (ERROR_FILE_NOT_FOUND == lRet2)
  132. {
  133. BYTE * pMulti = (BYTE *)SERVICE_NAME_GROUP_ALONE TEXT("\0");
  134. LONG lResInner = RegSetValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,REG_MULTI_SZ,pMulti,sizeof(SERVICE_NAME_GROUP)+sizeof(TEXT("")));
  135. bRet = (ERROR_SUCCESS == lResInner)?TRUE:FALSE;
  136. }
  137. else
  138. {
  139. bRet = FALSE;
  140. }
  141. // create the key with the COM init Param
  142. if (bRet)
  143. {
  144. HKEY hKey2;
  145. DWORD dwDisposistion;
  146. lRet = RegCreateKeyEx(hKey,
  147. SERVICE_NAME_GROUP_ALONE,
  148. 0,NULL,
  149. REG_OPTION_NON_VOLATILE,
  150. KEY_ALL_ACCESS,
  151. NULL,
  152. &hKey2,
  153. &dwDisposistion);
  154. if (ERROR_SUCCESS == lRet)
  155. {
  156. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm2(hKey2);
  157. // any value non NULL will work
  158. DWORD dwVal = 1;
  159. RegSetValueEx(hKey2,VALUE_COINIT,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  160. // from packet to connect
  161. dwVal = dwLevel; //RPC_C_AUTHN_LEVEL_CONNECT;
  162. RegSetValueEx(hKey2,VALUE_AUTZN,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  163. dwVal = RPC_C_IMP_LEVEL_IDENTIFY;
  164. RegSetValueEx(hKey2,VALUE_IMPER,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  165. dwVal = EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL | EOAC_STATIC_CLOAKING ;
  166. RegSetValueEx(hKey2,VALUE_AUTH,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  167. bRet = TRUE;
  168. }
  169. else
  170. {
  171. bRet = FALSE;
  172. }
  173. }
  174. }
  175. else
  176. {
  177. // no svchost key
  178. bRet = FALSE;
  179. }
  180. }
  181. if (bRet)
  182. {
  183. SC_HANDLE scHandle = OpenSCManager(NULL,SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
  184. if (scHandle)
  185. {
  186. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm1(scHandle);
  187. SC_HANDLE scService = OpenService(scHandle,SERVICE_NAME,SERVICE_ALL_ACCESS);
  188. if (scService)
  189. {
  190. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm2(scService);
  191. DWORD dwNeeded = 0;
  192. bRet = QueryServiceConfig(scService,NULL,0,&dwNeeded);
  193. if (!bRet && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
  194. {
  195. BYTE * pByte = new BYTE[dwNeeded];
  196. wmilib::auto_buffer<BYTE> rm_(pByte);
  197. QUERY_SERVICE_CONFIG* pConfig = (QUERY_SERVICE_CONFIG *)pByte;
  198. if (pConfig)
  199. {
  200. bRet = QueryServiceConfig(scService,pConfig,dwNeeded,&dwNeeded);
  201. if (bRet)
  202. {
  203. TCHAR BinPath[MAX_PATH];
  204. StringCchPrintf(BinPath,MAX_PATH,TEXT("%%systemroot%%\\system32\\svchost.exe -k %s"),SERVICE_NAME_GROUP_ALONE);
  205. bRet = ChangeServiceConfig(scService,
  206. pConfig->dwServiceType,
  207. pConfig->dwStartType,
  208. pConfig->dwErrorControl,
  209. BinPath,
  210. pConfig->lpLoadOrderGroup,
  211. NULL, //&pConfig->dwTagId,
  212. pConfig->lpDependencies,
  213. pConfig->lpServiceStartName,
  214. NULL,
  215. pConfig->lpDisplayName);
  216. if (!bRet)
  217. {
  218. DBG_PRINTFA((pBuff,"ChangeServiceConfig %d\n",GetLastError()));
  219. }
  220. }
  221. }
  222. else
  223. {
  224. bRet = FALSE;
  225. }
  226. }
  227. else
  228. {
  229. bRet = FALSE;
  230. }
  231. }
  232. else
  233. {
  234. // the service was not there or other error
  235. DBG_PRINTFA((pBuff,"MoveToStandalone OpenService %d\n",GetLastError()));
  236. bRet = FALSE;
  237. }
  238. }
  239. else
  240. {
  241. DBG_PRINTFA((pBuff,"MoveToStandalone OpenSCManager %d\n",GetLastError()));
  242. bRet = FALSE;
  243. }
  244. }
  245. if (bRet)
  246. {
  247. //
  248. // remove the winmgmt string from the multi-sz of netsvcs
  249. //
  250. HKEY hKey;
  251. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  252. SVCHOST_HOME,
  253. 0,
  254. KEY_ALL_ACCESS,
  255. &hKey);
  256. if (ERROR_SUCCESS == lRet)
  257. {
  258. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm3(hKey);
  259. // add the group
  260. LONG lRet2;
  261. DWORD dwCurrSize = 0;
  262. DWORD dwType;
  263. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,&dwType,NULL,&dwCurrSize);
  264. if (ERROR_SUCCESS == lRet2)
  265. {
  266. // the key is there, append to the multistring
  267. BYTE * pMulti = new BYTE[dwCurrSize+4];
  268. wmilib::auto_buffer<BYTE> rm1_(pMulti);
  269. BYTE * pMultiNew = new BYTE[dwCurrSize+4];
  270. wmilib::auto_buffer<BYTE> rm2_(pMultiNew);
  271. TCHAR * pMultiNewCopy = (TCHAR *)pMultiNew;
  272. if (pMulti && pMultiNew)
  273. {
  274. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,&dwType,pMulti,&dwCurrSize);
  275. if (ERROR_SUCCESS == lRet2 && REG_MULTI_SZ == dwType)
  276. {
  277. // verify the multisz
  278. TCHAR *pEnd = (TCHAR *)pMulti;
  279. BOOL bIsThere = FALSE;
  280. while (*pEnd)
  281. {
  282. if (0 == wbem_wcsicmp(pEnd,SERVICE_NAME))
  283. {
  284. bIsThere = TRUE;
  285. while (*pEnd){
  286. pEnd++;
  287. }
  288. pEnd++; // past the zero who terminates the string
  289. }
  290. else // copy
  291. {
  292. while (*pEnd){
  293. *pMultiNewCopy++ = *pEnd++;
  294. }
  295. pEnd++; // past the zero who terminates the string
  296. *pMultiNewCopy++ = 0;
  297. }
  298. }
  299. *pMultiNewCopy++ = 0; // put the double terminator
  300. if (bIsThere)
  301. {
  302. DWORD dwNowSize = dwCurrSize-sizeof(SERVICE_NAME);
  303. RegSetValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,REG_MULTI_SZ,pMultiNew,dwNowSize);
  304. }
  305. }
  306. else
  307. {
  308. bRet = FALSE;
  309. }
  310. }
  311. else
  312. {
  313. bRet = FALSE;
  314. }
  315. }
  316. else
  317. {
  318. //
  319. // the netsvcs multi sz MUST be there !!!!
  320. //
  321. bRet = TRUE;
  322. }
  323. }
  324. else
  325. {
  326. bRet = FALSE;
  327. }
  328. }
  329. return;
  330. }
  331. //
  332. //
  333. // this is the rundll32 interface
  334. //
  335. //
  336. //////////////////////////////////////////////////////////////////
  337. void CALLBACK
  338. MoveToShared(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) //RPC_C_AUTHN_LEVEL_CONNECT
  339. {
  340. //
  341. BOOL bRet = TRUE;
  342. LONG lRet;
  343. DWORD dwLevel = RPC_C_PROTECT_LEVEL_PKT;
  344. if (lpszCmdLine)
  345. {
  346. dwLevel = atoi(lpszCmdLine);
  347. if (0 == dwLevel) // in case of error
  348. {
  349. dwLevel = RPC_C_PROTECT_LEVEL_PKT;
  350. }
  351. }
  352. // create the new group key under svchost
  353. if (bRet)
  354. {
  355. HKEY hKey;
  356. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  357. SVCHOST_HOME,
  358. 0,
  359. KEY_ALL_ACCESS,
  360. &hKey);
  361. if (ERROR_SUCCESS == lRet)
  362. {
  363. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm(hKey);
  364. // add the group
  365. LONG lRet2;
  366. DWORD dwCurrSize = 0;
  367. DWORD dwType;
  368. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,&dwType,NULL,&dwCurrSize);
  369. if (ERROR_SUCCESS == lRet2)
  370. {
  371. // the key is there, append to the multistring
  372. BYTE * pMulti = new BYTE[(dwCurrSize+sizeof(SERVICE_NAME)+4)];
  373. wmilib::auto_buffer<BYTE> rm_(pMulti);
  374. if (pMulti)
  375. {
  376. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,&dwType,pMulti,&dwCurrSize);
  377. if (ERROR_SUCCESS == lRet2 && REG_MULTI_SZ == dwType)
  378. {
  379. TCHAR * pInsertPoint = (TCHAR *)(pMulti+dwCurrSize-sizeof(TCHAR));
  380. // verify the multisz
  381. TCHAR *pEnd = (TCHAR *)pMulti;
  382. BOOL bIsThere = FALSE;
  383. while (*pEnd)
  384. {
  385. if (0 == wbem_wcsicmp(pEnd,SERVICE_NAME))
  386. {
  387. bIsThere = TRUE;
  388. }
  389. while (*pEnd){
  390. pEnd++;
  391. }
  392. pEnd++; // past the zero who terminates the string
  393. }
  394. if (!bIsThere)
  395. {
  396. if ((ULONG_PTR)pEnd == (ULONG_PTR)pInsertPoint)
  397. {
  398. wcsncpy(pEnd,SERVICE_NAME TEXT("\0"),sizeof(SERVICE_NAME)/sizeof(TCHAR)+1);
  399. DWORD dwNowSize = dwCurrSize+sizeof(SERVICE_NAME);
  400. RegSetValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,REG_MULTI_SZ,pMulti,dwNowSize);
  401. }
  402. else
  403. {
  404. bRet = FALSE;
  405. DBG_PRINTFA((pBuff,"Malformed REG_MULTI_SZ under %S\n",SERVICE_NAME_GROUP_TOGETHER));
  406. }
  407. }
  408. }
  409. else
  410. {
  411. // invalid type in reg_multi_sz
  412. bRet = FALSE;
  413. }
  414. }
  415. else
  416. {
  417. bRet = FALSE;
  418. }
  419. }
  420. else if (ERROR_FILE_NOT_FOUND == lRet2)
  421. {
  422. BYTE * pMulti = (BYTE *)SERVICE_NAME_GROUP_TOGETHER TEXT("\0");
  423. RegSetValueEx(hKey,SERVICE_NAME_GROUP_TOGETHER,0,REG_MULTI_SZ,pMulti,sizeof(SERVICE_NAME_GROUP)+sizeof(TEXT("")));
  424. }
  425. else
  426. {
  427. bRet = FALSE;
  428. }
  429. HKEY hKey2;
  430. DWORD dwDisposistion;
  431. lRet = RegCreateKeyEx(hKey,
  432. SERVICE_NAME_GROUP_TOGETHER,
  433. 0,NULL,
  434. REG_OPTION_NON_VOLATILE,
  435. KEY_ALL_ACCESS,
  436. NULL,
  437. &hKey2,
  438. &dwDisposistion);
  439. if (ERROR_SUCCESS == lRet)
  440. {
  441. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm2(hKey2);
  442. // any value non NULL will work
  443. DWORD dwVal = 1;
  444. RegSetValueEx(hKey2,VALUE_COINIT,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  445. // from packet to connect
  446. dwVal = dwLevel; //RPC_C_AUTHN_LEVEL_CONNECT;
  447. RegSetValueEx(hKey2,VALUE_AUTZN,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  448. dwVal = RPC_C_IMP_LEVEL_IDENTIFY;
  449. RegSetValueEx(hKey2,VALUE_IMPER,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  450. dwVal = EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL | EOAC_STATIC_CLOAKING ;
  451. RegSetValueEx(hKey2,VALUE_AUTH,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  452. bRet = TRUE;
  453. }
  454. else
  455. {
  456. DBG_PRINTFA((pBuff,"Could not create %S\n",SERVICE_NAME_GROUP_TOGETHER));
  457. bRet = FALSE;
  458. }
  459. }
  460. else
  461. {
  462. bRet = FALSE;
  463. }
  464. }
  465. //
  466. // changes the SCM database
  467. //
  468. if (bRet)
  469. {
  470. SC_HANDLE scHandle = OpenSCManager(NULL,SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
  471. if (scHandle)
  472. {
  473. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm1(scHandle);
  474. SC_HANDLE scService = OpenService(scHandle,SERVICE_NAME,SERVICE_ALL_ACCESS);
  475. if (scService)
  476. {
  477. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm2(scService);
  478. DWORD dwNeeded = 0;
  479. bRet = QueryServiceConfig(scService,NULL,0,&dwNeeded);
  480. if (!bRet && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
  481. {
  482. BYTE * pByte = new BYTE[dwNeeded];
  483. wmilib::auto_buffer<BYTE> rm1_(pByte);
  484. QUERY_SERVICE_CONFIG* pConfig = (QUERY_SERVICE_CONFIG *)pByte;
  485. if (pConfig)
  486. {
  487. bRet = QueryServiceConfig(scService,pConfig,dwNeeded,&dwNeeded);
  488. if (bRet)
  489. {
  490. TCHAR BinPath[MAX_PATH];
  491. StringCchPrintf(BinPath,MAX_PATH,TEXT("%%systemroot%%\\system32\\svchost.exe -k %s"),SERVICE_NAME_GROUP_TOGETHER);
  492. bRet = ChangeServiceConfig(scService,
  493. pConfig->dwServiceType,
  494. pConfig->dwStartType,
  495. pConfig->dwErrorControl,
  496. BinPath,
  497. pConfig->lpLoadOrderGroup,
  498. NULL, //&pConfig->dwTagId,
  499. pConfig->lpDependencies,
  500. pConfig->lpServiceStartName,
  501. NULL,
  502. pConfig->lpDisplayName);
  503. if (!bRet)
  504. {
  505. DBG_PRINTFA((pBuff,"ChangeServiceConfig %d\n",GetLastError()));
  506. }
  507. }
  508. }
  509. else
  510. {
  511. bRet = FALSE;
  512. }
  513. }
  514. else
  515. {
  516. bRet = FALSE;
  517. }
  518. }
  519. else
  520. {
  521. // the service was not there or other error
  522. DBG_PRINTFA((pBuff,"MoveToShared OpenService %d\n",GetLastError()));
  523. bRet = FALSE;
  524. }
  525. }
  526. else
  527. {
  528. DBG_PRINTFA((pBuff,"MoveToShared OpenSCManager %d\n",GetLastError()));
  529. bRet = FALSE;
  530. }
  531. }
  532. if (bRet)
  533. {
  534. //
  535. // remove the winmgmt string from the multi-sz of winmgmt
  536. //
  537. HKEY hKey;
  538. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  539. SVCHOST_HOME,
  540. 0,
  541. KEY_ALL_ACCESS,
  542. &hKey);
  543. if (ERROR_SUCCESS == lRet)
  544. {
  545. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm3(hKey);
  546. // add the group
  547. LONG lRet2;
  548. DWORD dwCurrSize;
  549. DWORD dwType;
  550. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,&dwType,NULL,&dwCurrSize);
  551. if (ERROR_SUCCESS == lRet2)
  552. {
  553. // the key is there, append to the multistring
  554. BYTE * pMulti = new BYTE[dwCurrSize+4];
  555. wmilib::auto_buffer<BYTE> rm2_(pMulti);
  556. BYTE * pMultiNew = new BYTE[dwCurrSize+4];
  557. wmilib::auto_buffer<BYTE> rm3_(pMultiNew);
  558. TCHAR * pMultiNewCopy = (TCHAR *)pMultiNew;
  559. if (pMulti && pMultiNew)
  560. {
  561. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,&dwType,pMulti,&dwCurrSize);
  562. if (ERROR_SUCCESS == lRet2 && REG_MULTI_SZ == dwType)
  563. {
  564. // verify the multisz
  565. TCHAR *pEnd = (TCHAR *)pMulti;
  566. BOOL bIsThere = FALSE;
  567. while (*pEnd)
  568. {
  569. if (0 == wbem_wcsicmp(pEnd,SERVICE_NAME))
  570. {
  571. bIsThere = TRUE;
  572. while (*pEnd){
  573. pEnd++;
  574. }
  575. pEnd++; // past the zero who terminates the string
  576. }
  577. else // copy
  578. {
  579. while (*pEnd){
  580. *pMultiNewCopy++ = *pEnd++;
  581. }
  582. pEnd++; // past the zero who terminates the string
  583. *pMultiNewCopy++ = 0;
  584. }
  585. }
  586. *pMultiNewCopy++ = 0; // put the double terminator
  587. if (bIsThere)
  588. {
  589. DWORD dwNowSize = dwCurrSize-sizeof(SERVICE_NAME);
  590. RegSetValueEx(hKey,SERVICE_NAME_GROUP_ALONE,0,REG_MULTI_SZ,pMultiNew,dwNowSize);
  591. }
  592. }
  593. else
  594. {
  595. bRet = FALSE;
  596. }
  597. }
  598. else
  599. {
  600. bRet = FALSE;
  601. }
  602. }
  603. else
  604. {
  605. //
  606. // the winmgmt multi sz MUST can be NOT there
  607. //
  608. bRet = TRUE;
  609. }
  610. }
  611. else
  612. {
  613. bRet = FALSE;
  614. }
  615. }
  616. }
  617. //***************************************************************************
  618. //
  619. // void InitializeLaunchPermissions()
  620. //
  621. // DESCRIPTION:
  622. //
  623. // Sets the DCOM Launch permissions.
  624. //
  625. //***************************************************************************
  626. void InitializeLaunchPermissions()
  627. {
  628. Registry reg(__TEXT("SOFTWARE\\CLASSES\\APPID\\{8bc3f05e-d86b-11d0-a075-00c04fb68820}"));
  629. if(reg.GetLastError() != 0)
  630. return;
  631. // If there already is a SD, then dont overwrite
  632. BYTE * pData = NULL;
  633. DWORD dwDataSize = 0;
  634. int iRet = reg.GetBinary(__TEXT("LaunchPermission"), &pData, &dwDataSize);
  635. if(iRet == 0)
  636. {
  637. delete [] pData;
  638. return; // it's already there
  639. }
  640. PSID pEveryoneSid;
  641. SID_IDENTIFIER_AUTHORITY id_World = SECURITY_WORLD_SID_AUTHORITY;
  642. if(!AllocateAndInitializeSid( &id_World, 1,
  643. SECURITY_WORLD_RID,
  644. 0,0,0,0,0,0,0,
  645. &pEveryoneSid)) return;
  646. OnDelete<PSID,PVOID(*)(PSID),FreeSid> freeSid1(pEveryoneSid);
  647. SID_IDENTIFIER_AUTHORITY id_NT = SECURITY_NT_AUTHORITY;
  648. PSID pAdministratorsSid = NULL;
  649. if (!AllocateAndInitializeSid(&id_NT,
  650. 2,
  651. SECURITY_BUILTIN_DOMAIN_RID,
  652. DOMAIN_ALIAS_RID_ADMINS,
  653. 0, 0, 0, 0, 0, 0,
  654. &pAdministratorsSid)) return;
  655. OnDelete<PSID,PVOID(*)(PSID),FreeSid> freeSid2(pAdministratorsSid);
  656. // Create the class sids for everyone and administrators
  657. CNtSid SidEveryone(pEveryoneSid);
  658. CNtSid SidAdmins(pAdministratorsSid);
  659. if(SidEveryone.GetStatus() != 0 || SidAdmins.GetStatus() != 0)
  660. return;
  661. // Create a single ACE, and add it to the ACL
  662. CNtAcl DestAcl;
  663. CNtAce Users(1, ACCESS_ALLOWED_ACE_TYPE, 0, SidEveryone);
  664. if(Users.GetStatus() != 0)
  665. return;
  666. DestAcl.AddAce(&Users);
  667. if(DestAcl.GetStatus() != 0)
  668. return;
  669. // Set the descresionary acl, and the owner and group sids
  670. // Create a sd with a single entry for launch permissions.
  671. CNtSecurityDescriptor LaunchPermSD;
  672. LaunchPermSD.SetDacl(&DestAcl);
  673. LaunchPermSD.SetOwner(&SidAdmins);
  674. LaunchPermSD.SetGroup(&SidAdmins);
  675. if(LaunchPermSD.GetStatus() != 0) return;
  676. // Write it out
  677. reg.SetBinary(__TEXT("LaunchPermission"), (BYTE *)LaunchPermSD.GetPtr(), LaunchPermSD.GetSize());
  678. }
  679. //***************************************************************************
  680. //
  681. // DllRegisterServer
  682. //
  683. // Standard OLE entry point for registering the COM server.
  684. //
  685. // RETURN VALUES:
  686. //
  687. // S_OK Registration was successful
  688. // E_FAIL Registration failed.
  689. //
  690. //***************************************************************************
  691. //
  692. // Phase 1 : Create the MULTI_SZ under the svchost key (AKA, create a group of services)
  693. // If the key is there, check if the WinMgmt service is already there, otherwise add it
  694. // Phase 2 : Use the SCM Api in order to create the service if not there
  695. // otherwise change the service configuration to some known value
  696. // Phase 3 : Creates specific keys under the Services\WinMgmt key.
  697. // cannot be done before, if the service is not already there
  698. // Phase 4 : Expose this service as a COM server, creates CLSID, APPID and misc keys
  699. //
  700. STDAPI DllRegisterServer(void)
  701. {
  702. LONG lRet;
  703. BOOL bRet = TRUE;
  704. //
  705. // Phase 1
  706. //
  707. if (bRet)
  708. {
  709. HKEY hKey;
  710. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  711. SVCHOST_HOME,
  712. 0,
  713. KEY_ALL_ACCESS,
  714. &hKey);
  715. if (ERROR_SUCCESS == lRet)
  716. {
  717. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm(hKey);
  718. // add the group
  719. LONG lRet2;
  720. DWORD dwCurrSize = 0;
  721. DWORD dwType;
  722. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP,0,&dwType,NULL,&dwCurrSize);
  723. if (ERROR_SUCCESS == lRet2)
  724. {
  725. // the key is there, append to the multistring
  726. BYTE * pMulti = new BYTE[(dwCurrSize+sizeof(SERVICE_NAME)+4)];
  727. wmilib::auto_buffer<BYTE> rm4_(pMulti);
  728. if (pMulti)
  729. {
  730. lRet2 = RegQueryValueEx(hKey,SERVICE_NAME_GROUP,0,&dwType,pMulti,&dwCurrSize);
  731. if (ERROR_SUCCESS == lRet2 && REG_MULTI_SZ == dwType )
  732. {
  733. TCHAR * pInsertPoint = (TCHAR *)(pMulti+dwCurrSize-sizeof(TCHAR));
  734. // verify the multisz
  735. TCHAR *pEnd = (TCHAR *)pMulti;
  736. BOOL bIsThere = FALSE;
  737. while (*pEnd)
  738. {
  739. if (0 == wbem_wcsicmp(pEnd,SERVICE_NAME))
  740. {
  741. bIsThere = TRUE;
  742. }
  743. while (*pEnd){
  744. pEnd++;
  745. }
  746. pEnd++; // past the zero who terminates the string
  747. }
  748. if (!bIsThere)
  749. {
  750. if ((ULONG_PTR)pEnd == (ULONG_PTR)pInsertPoint)
  751. {
  752. wcsncpy(pEnd,SERVICE_NAME TEXT("\0"),sizeof(SERVICE_NAME)/sizeof(TCHAR)+1);
  753. DWORD dwNowSize = dwCurrSize+sizeof(SERVICE_NAME);
  754. RegSetValueEx(hKey,SERVICE_NAME_GROUP,0,REG_MULTI_SZ,pMulti,dwNowSize);
  755. }
  756. else
  757. {
  758. bRet = FALSE;
  759. }
  760. }
  761. }
  762. else
  763. {
  764. bRet = FALSE;
  765. }
  766. }
  767. else
  768. {
  769. bRet = FALSE;
  770. }
  771. }
  772. else if (ERROR_FILE_NOT_FOUND == lRet2)
  773. {
  774. BYTE * pMulti = (BYTE *)SERVICE_NAME_GROUP TEXT("\0");
  775. lRet = RegSetValueEx(hKey,SERVICE_NAME_GROUP,0,REG_MULTI_SZ,pMulti,sizeof(SERVICE_NAME_GROUP)+sizeof(TEXT("")));
  776. bRet = (ERROR_SUCCESS == lRet)?TRUE:FALSE;
  777. }
  778. else
  779. {
  780. bRet = FALSE;
  781. }
  782. HKEY hKey2;
  783. DWORD dwDisposistion;
  784. lRet = RegCreateKeyEx(hKey,
  785. SERVICE_NAME_GROUP,
  786. 0,NULL,
  787. REG_OPTION_NON_VOLATILE,
  788. KEY_ALL_ACCESS,
  789. NULL,
  790. &hKey2,
  791. &dwDisposistion);
  792. if (ERROR_SUCCESS == lRet)
  793. {
  794. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm2(hKey2);
  795. // any value non NULL will work
  796. DWORD dwVal = 1;
  797. RegSetValueEx(hKey2,VALUE_COINIT,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  798. // servicehost default + static cloaking
  799. dwVal = EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL | EOAC_STATIC_CLOAKING ;
  800. RegSetValueEx(hKey2,VALUE_AUTH,0,REG_DWORD,(BYTE *)&dwVal,sizeof(DWORD));
  801. bRet = TRUE;
  802. }
  803. else
  804. {
  805. bRet = FALSE;
  806. }
  807. }
  808. else
  809. {
  810. bRet = FALSE;
  811. }
  812. }
  813. //
  814. // Phase 2
  815. //
  816. if (bRet)
  817. {
  818. SC_HANDLE hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  819. if (hSCM)
  820. {
  821. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm1(hSCM);
  822. DWORD dwTag;
  823. TCHAR BinPath[MAX_PATH];
  824. StringCchPrintf(BinPath,MAX_PATH,TEXT("%%systemroot%%\\system32\\svchost.exe -k %s"),SERVICE_NAME_GROUP);
  825. TCHAR * pServiceDisplay = new TCHAR[MAX_BUFF];
  826. wmilib::auto_buffer<TCHAR> rm(pServiceDisplay);
  827. if (pServiceDisplay)
  828. {
  829. int nRet = LoadString(g_hInstance,ID_WINMGMT_SERVICE,pServiceDisplay,MAX_BUFF);
  830. }
  831. else
  832. {
  833. bRet = FALSE;
  834. }
  835. SC_HANDLE hService = NULL;
  836. if (bRet)
  837. {
  838. hService = OpenService(hSCM,SERVICE_NAME,SERVICE_ALL_ACCESS );
  839. }
  840. SC_ACTION ac[2];
  841. ac[0].Type = SC_ACTION_RESTART;
  842. ac[0].Delay = 60000;
  843. ac[1].Type = SC_ACTION_RESTART;
  844. ac[1].Delay = 60000;
  845. SERVICE_FAILURE_ACTIONS sf;
  846. sf.dwResetPeriod = 86400;
  847. sf.lpRebootMsg = NULL;
  848. sf.lpCommand = NULL;
  849. sf.cActions = 2;
  850. sf.lpsaActions = ac;
  851. if (hService)
  852. {
  853. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm2(hService);
  854. bRet = ChangeServiceConfig(hService,
  855. SERVICE_WIN32_SHARE_PROCESS,
  856. SERVICE_AUTO_START, //SERVICE_DEMAND_START,
  857. SERVICE_ERROR_IGNORE,
  858. BinPath,
  859. NULL,
  860. NULL,
  861. TEXT("RPCSS\0Eventlog\0\0\0"),
  862. NULL, //ACCOUNT_NAME,
  863. NULL,
  864. pServiceDisplay);
  865. if (bRet)
  866. {
  867. ChangeServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, &sf);
  868. //
  869. // insert code for description here
  870. TCHAR * pBuff = new TCHAR[MAX_BUFF];
  871. if (pBuff)
  872. {
  873. int nRet = LoadString(g_hInstance,ID_WINMGMT_DESCRIPTION,pBuff,MAX_BUFF);
  874. if (nRet)
  875. {
  876. SERVICE_DESCRIPTION sd;
  877. sd.lpDescription = pBuff;
  878. ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,&sd);
  879. }
  880. delete [] pBuff;
  881. }
  882. //
  883. //
  884. }
  885. else
  886. {
  887. DBG_PRINTFA((pBuff,"ChangeServiceConfig %d\n",GetLastError()));
  888. }
  889. }
  890. else
  891. {
  892. // Create it
  893. hService = CreateService(hSCM,
  894. SERVICE_NAME,
  895. pServiceDisplay,
  896. SERVICE_ALL_ACCESS,
  897. SERVICE_WIN32_SHARE_PROCESS,
  898. SERVICE_AUTO_START, //SERVICE_DEMAND_START,
  899. SERVICE_ERROR_IGNORE,
  900. BinPath,
  901. NULL,
  902. NULL,
  903. TEXT("RPCSS\0Eventlog\0\0\0"),
  904. NULL, //ACCOUNT_NAME,
  905. NULL);
  906. if (hService)
  907. {
  908. OnDelete<SC_HANDLE,BOOL(*)(SC_HANDLE),CloseServiceHandle> cm3(hService);
  909. ChangeServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, &sf);
  910. //
  911. // insert code for description here
  912. TCHAR * pBuff = new TCHAR[MAX_BUFF];
  913. if (pBuff)
  914. {
  915. int nRet = LoadString(g_hInstance,ID_WINMGMT_DESCRIPTION,pBuff,MAX_BUFF);
  916. if (nRet)
  917. {
  918. SERVICE_DESCRIPTION sd;
  919. sd.lpDescription = pBuff;
  920. ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,&sd);
  921. }
  922. delete [] pBuff;
  923. }
  924. bRet = TRUE;
  925. }
  926. else
  927. {
  928. bRet = FALSE;
  929. }
  930. }
  931. }
  932. else
  933. {
  934. bRet = FALSE;
  935. }
  936. }
  937. //
  938. // Phase 3
  939. //
  940. if (bRet)
  941. {
  942. HKEY hKey;
  943. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  944. SERVICE_PATH SERVICE_NAME,
  945. 0,
  946. KEY_ALL_ACCESS,
  947. &hKey);
  948. if (ERROR_SUCCESS == lRet)
  949. {
  950. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> cm3(hKey);
  951. HKEY hKey3;
  952. DWORD dwDisposistion;
  953. lRet = RegCreateKeyEx(hKey,
  954. TEXT("Parameters"),
  955. 0,NULL,
  956. REG_OPTION_NON_VOLATILE,
  957. KEY_ALL_ACCESS,
  958. NULL,
  959. &hKey3,
  960. &dwDisposistion);
  961. if (ERROR_SUCCESS == lRet)
  962. {
  963. RegSetValueEx(hKey3,TEXT("ServiceDll"),0,REG_EXPAND_SZ,(BYTE *)DLL_PATH,sizeof(DLL_PATH)-sizeof(TCHAR));
  964. RegSetValueEx(hKey3,TEXT("ServiceMain"),0,REG_SZ,(BYTE *)ENTRY_POINT,sizeof(ENTRY_POINT)-sizeof(TCHAR));
  965. RegCloseKey(hKey3);
  966. bRet = TRUE;
  967. }
  968. else
  969. {
  970. bRet = FALSE;
  971. }
  972. }
  973. else
  974. {
  975. bRet = FALSE;
  976. }
  977. }
  978. //
  979. // Phase 4
  980. //
  981. if (bRet)
  982. {
  983. HKEY hKey4;
  984. DWORD dwDisposistion;
  985. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  986. COM_APPID,
  987. 0,NULL,
  988. REG_OPTION_NON_VOLATILE,
  989. KEY_ALL_ACCESS,
  990. NULL,
  991. &hKey4,
  992. &dwDisposistion);
  993. if (ERROR_SUCCESS == lRet)
  994. {
  995. RegSetValueEx(hKey4,NULL,0,REG_SZ,(BYTE *)DISPLAY_CLSID,sizeof(DISPLAY_CLSID)-sizeof(TCHAR));
  996. RegSetValueEx(hKey4,TEXT("LocalService"),0,REG_SZ,(BYTE *)SERVICE_NAME,sizeof(SERVICE_NAME)-sizeof(TCHAR));
  997. RegCloseKey(hKey4);
  998. }
  999. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1000. COM_APPID_NAME,
  1001. 0,NULL,
  1002. REG_OPTION_NON_VOLATILE,
  1003. KEY_ALL_ACCESS,
  1004. NULL,
  1005. &hKey4,
  1006. &dwDisposistion);
  1007. if (ERROR_SUCCESS == lRet)
  1008. {
  1009. RegSetValueEx(hKey4,TEXT("AppID"),0,REG_SZ,(BYTE *)SERVICE_CLSID,sizeof(SERVICE_CLSID)-sizeof(TCHAR));
  1010. RegCloseKey(hKey4);
  1011. }
  1012. InitializeLaunchPermissions();
  1013. OLECHAR ClsidBuff[40];
  1014. TCHAR * ClsidBuff2;
  1015. TCHAR ClsidPath[MAX_PATH];
  1016. StringFromGUID2(CLSID_WbemLevel1Login,ClsidBuff,40);
  1017. #ifdef UNICODE
  1018. ClsidBuff2 = ClsidBuff;
  1019. #else
  1020. TCHAR pTmp_[40];
  1021. ClsidBuff2 = pTmp_;
  1022. WideCharToMultiByte(CP_ACP,0,ClsidBuff,-1,ClsidBuff2,40,NULL,NULL);
  1023. #endif
  1024. StringCchPrintf(ClsidPath,MAX_PATH,TEXT("software\\classes\\CLSID\\%s"),ClsidBuff2);
  1025. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1026. ClsidPath,
  1027. 0,NULL,
  1028. REG_OPTION_NON_VOLATILE,
  1029. KEY_ALL_ACCESS,
  1030. NULL,
  1031. &hKey4,
  1032. &dwDisposistion);
  1033. if (ERROR_SUCCESS == lRet)
  1034. {
  1035. RegSetValueEx(hKey4,NULL,0,REG_SZ,(BYTE *)DISPLAY_CLSID,sizeof(DISPLAY_CLSID)-sizeof(TCHAR));
  1036. RegSetValueEx(hKey4,TEXT("AppId"),0,REG_SZ,(BYTE *)SERVICE_CLSID,sizeof(SERVICE_CLSID)-sizeof(TCHAR));
  1037. RegSetValueEx(hKey4,TEXT("LocalService"),0,REG_SZ,(BYTE *)SERVICE_NAME,sizeof(SERVICE_NAME)-sizeof(TCHAR));
  1038. RegCloseKey(hKey4);
  1039. }
  1040. StringFromGUID2(CLSID_WbemBackupRestore,ClsidBuff,40);
  1041. #ifdef UNICODE
  1042. ClsidBuff2 = ClsidBuff;
  1043. #else
  1044. WideCharToMultiByte(CP_ACP,0,ClsidBuff,-1,ClsidBuff2,40,NULL,NULL);
  1045. #endif
  1046. StringCchPrintf(ClsidPath,MAX_PATH,TEXT("software\\classes\\CLSID\\%s"),ClsidBuff);
  1047. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1048. ClsidPath,
  1049. 0,NULL,
  1050. REG_OPTION_NON_VOLATILE,
  1051. KEY_ALL_ACCESS,
  1052. NULL,
  1053. &hKey4,
  1054. &dwDisposistion);
  1055. if (ERROR_SUCCESS == lRet)
  1056. {
  1057. RegSetValueEx(hKey4,NULL,0,REG_SZ,(BYTE *)DISPLAY_BACKUP_CLSID,sizeof(DISPLAY_BACKUP_CLSID)-sizeof(TCHAR));
  1058. RegSetValueEx(hKey4,TEXT("AppId"),0,REG_SZ,(BYTE *)SERVICE_CLSID,sizeof(SERVICE_CLSID)-sizeof(TCHAR));
  1059. RegSetValueEx(hKey4,TEXT("LocalService"),0,REG_SZ,(BYTE *)SERVICE_NAME,sizeof(SERVICE_NAME)-sizeof(TCHAR));
  1060. RegCloseKey(hKey4);
  1061. }
  1062. }
  1063. return S_OK;
  1064. }
  1065. //***************************************************************************
  1066. //
  1067. // DllUnregisterServer
  1068. //
  1069. // Standard OLE entry point for unregistering the COM server.
  1070. //
  1071. // RETURN VALUES:
  1072. //
  1073. // S_OK Unregistration was successful
  1074. //
  1075. //***************************************************************************
  1076. STDAPI DllUnregisterServer(void)
  1077. {
  1078. LONG lRet;
  1079. TCHAR ClsidBuff[40];
  1080. TCHAR ClsidPath[MAX_PATH];
  1081. #ifdef UNICODE
  1082. StringFromCLSID(CLSID_WbemLevel1Login,(LPOLESTR *)ClsidBuff);
  1083. #else
  1084. WCHAR ClsidPath2[40];
  1085. StringFromCLSID(CLSID_WbemLevel1Login,(LPOLESTR *)ClsidBuff2);
  1086. MultiByteToWideChar(CP_ACP,0,ClsidBuff2,-1,ClsidBuff,40);
  1087. #endif
  1088. StringCchPrintf(ClsidPath,MAX_PATH,TEXT("software\\classes\\CLSID\\%s"),ClsidBuff);
  1089. lRet = RegDeleteKey(HKEY_LOCAL_MACHINE,ClsidPath);
  1090. if (ERROR_SUCCESS != lRet) return E_FAIL;
  1091. #ifdef UNICODE
  1092. StringFromCLSID(CLSID_WbemBackupRestore,(LPOLESTR *)ClsidBuff);
  1093. #else
  1094. WCHAR ClsidPath2[40];
  1095. StringFromCLSID(CLSID_WbemBackupRestore,(LPOLESTR *)ClsidBuff2);
  1096. MultiByteToWideChar(CP_ACP,0,ClsidBuff2,-1,ClsidBuff,40);
  1097. #endif
  1098. StringCchPrintf(ClsidPath,MAX_PATH,TEXT("software\\classes\\CLSID\\%s"),ClsidBuff);
  1099. lRet = RegDeleteKey(HKEY_LOCAL_MACHINE,ClsidPath);
  1100. if (ERROR_SUCCESS != lRet) return E_FAIL;
  1101. lRet = RegDeleteKey(HKEY_LOCAL_MACHINE,COM_APPID);
  1102. if (ERROR_SUCCESS != lRet) return E_FAIL;
  1103. lRet = RegDeleteKey(HKEY_LOCAL_MACHINE,COM_APPID_NAME);
  1104. if (ERROR_SUCCESS != lRet) return E_FAIL;
  1105. return S_OK;
  1106. }