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.

1391 lines
38 KiB

  1. #include "dtctreg.h"
  2. #include "hwdev.h"
  3. #include "pnp.h"
  4. #include "cmmn.h"
  5. #include "sfstr.h"
  6. #include "reg.h"
  7. #include "misc.h"
  8. #include "shobjidl.h"
  9. #include "shpriv.h"
  10. #include "users.h"
  11. #include "strsafe.h"
  12. #include "str.h"
  13. #include "dbg.h"
  14. #include "mischlpr.h"
  15. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  16. HRESULT _GetValueToUse(LPWSTR pszKeyName, LPWSTR psz, DWORD cch)
  17. {
  18. HKEY hkey;
  19. HRESULT hr = _RegOpenKey(HKEY_LOCAL_MACHINE, pszKeyName, &hkey);
  20. if (SUCCEEDED(hr) && (S_FALSE != hr))
  21. {
  22. // For now we take the first one.
  23. hr = _RegEnumStringValue(hkey, 0, psz, cch);
  24. _RegCloseKey(hkey);
  25. }
  26. return hr;
  27. }
  28. // Return Values:
  29. // S_FALSE: Can't find it
  30. HRESULT _GetEventHandlerFromKey(LPCWSTR pszKeyName, LPCWSTR pszEventType,
  31. LPWSTR pszEventHandler, DWORD cchEventHandler)
  32. {
  33. WCHAR szEventHandler[MAX_KEY];
  34. DWORD cchLeft;
  35. LPWSTR pszNext;
  36. HRESULT hr = SafeStrCpyNEx(szEventHandler, pszKeyName,
  37. ARRAYSIZE(szEventHandler), &pszNext, &cchLeft);
  38. if (SUCCEEDED(hr))
  39. {
  40. hr = SafeStrCpyNEx(pszNext, TEXT("\\EventHandlers\\"), cchLeft,
  41. &pszNext, &cchLeft);
  42. if (SUCCEEDED(hr))
  43. {
  44. hr = SafeStrCpyN(pszNext, pszEventType, cchLeft);
  45. if (SUCCEEDED(hr))
  46. {
  47. hr = _GetValueToUse(szEventHandler, pszEventHandler,
  48. cchEventHandler);
  49. }
  50. }
  51. }
  52. return hr;
  53. }
  54. // Return Values:
  55. // S_FALSE: Can't find it
  56. HRESULT _GetEventHandlerFromDeviceHandler(LPCWSTR pszDeviceHandler,
  57. LPCWSTR pszEventType, LPWSTR pszEventHandler, DWORD cchEventHandler)
  58. {
  59. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("DeviceHandlers\\"));
  60. HRESULT hr = SafeStrCatN(szKeyName, pszDeviceHandler,
  61. ARRAYSIZE(szKeyName));
  62. if (SUCCEEDED(hr))
  63. {
  64. hr = _GetEventHandlerFromKey(szKeyName, pszEventType, pszEventHandler,
  65. cchEventHandler);
  66. }
  67. return hr;
  68. }
  69. HRESULT _GetStuffFromHandlerHelper(LPCWSTR pszHandler, LPCWSTR pszValueName,
  70. LPWSTR psz, DWORD cch)
  71. {
  72. HKEY hkey;
  73. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("Handlers\\"));
  74. HRESULT hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey);
  75. if (SUCCEEDED(hr) && (S_FALSE != hr))
  76. {
  77. hr = _RegQueryString(hkey, pszHandler,
  78. pszValueName, psz, cch);
  79. _RegCloseKey(hkey);
  80. }
  81. return hr;
  82. }
  83. HRESULT _GetActionFromHandler(LPCWSTR pszHandler, LPWSTR pszAction,
  84. DWORD cchAction)
  85. {
  86. HRESULT hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("Action"),
  87. pszAction, cchAction);
  88. if (SUCCEEDED(hr) && (S_FALSE == hr))
  89. {
  90. hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("FriendlyName"),
  91. pszAction, cchAction);
  92. }
  93. return hr;
  94. }
  95. HRESULT _GetProviderFromHandler(LPCWSTR pszHandler, LPWSTR pszProvider,
  96. DWORD cchProvider)
  97. {
  98. HRESULT hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("Provider"),
  99. pszProvider, cchProvider);
  100. if (SUCCEEDED(hr) && (S_FALSE == hr))
  101. {
  102. hr = SafeStrCpyN(pszProvider, TEXT("<need provider>"), cchProvider);
  103. }
  104. return hr;
  105. }
  106. HRESULT _GetIconLocationFromHandler(LPCWSTR pszHandler,
  107. LPWSTR pszIconLocation, DWORD cchIconLocation)
  108. {
  109. return _GetStuffFromHandlerHelper(pszHandler, TEXT("DefaultIcon"),
  110. pszIconLocation, cchIconLocation);
  111. }
  112. HRESULT _GetInvokeProgIDFromHandler(LPCWSTR pszHandler,
  113. LPWSTR pszInvokeProgID, DWORD cchInvokeProgID)
  114. {
  115. return _GetStuffFromHandlerHelper(pszHandler, TEXT("InvokeProgID"),
  116. pszInvokeProgID, cchInvokeProgID);
  117. }
  118. HRESULT _GetInvokeVerbFromHandler(LPCWSTR pszHandler,
  119. LPWSTR pszInvokeVerb, DWORD cchInvokeVerb)
  120. {
  121. return _GetStuffFromHandlerHelper(pszHandler, TEXT("InvokeVerb"),
  122. pszInvokeVerb, cchInvokeVerb);
  123. }
  124. HRESULT _GetEventKeyName(LPCWSTR pszDeviceID, LPCWSTR pszEventType,
  125. LPWSTR pszEventKeyName, DWORD cchEventKeyName)
  126. {
  127. WCHAR szDeviceIDReal[MAX_DEVICEID];
  128. HRESULT hr = _GetDeviceID(pszDeviceID, szDeviceIDReal,
  129. ARRAYSIZE(szDeviceIDReal));
  130. if (SUCCEEDED(hr) && (S_FALSE != hr))
  131. {
  132. CHWDeviceInst* phwdevinst;
  133. CNamedElem* pelemToRelease;
  134. hr = _GetHWDeviceInstFromDeviceOrVolumeIntfID(szDeviceIDReal,
  135. &phwdevinst, &pelemToRelease);
  136. if (SUCCEEDED(hr) && (S_FALSE != hr))
  137. {
  138. WCHAR szDeviceHandler[MAX_DEVICEHANDLER];
  139. hr = _GetDeviceHandler(phwdevinst, szDeviceHandler,
  140. ARRAYSIZE(szDeviceHandler));
  141. if (SUCCEEDED(hr) && (S_FALSE != hr))
  142. {
  143. LPWSTR pszNext;
  144. DWORD cchLeft;
  145. hr = SafeStrCpyNEx(pszEventKeyName,
  146. SHDEVICEEVENTROOT(TEXT("DeviceHandlers\\")),
  147. cchEventKeyName, &pszNext, &cchLeft);
  148. if (SUCCEEDED(hr))
  149. {
  150. hr = SafeStrCpyNEx(pszNext, szDeviceHandler,
  151. cchLeft, &pszNext, &cchLeft);
  152. if (SUCCEEDED(hr))
  153. {
  154. hr = SafeStrCpyNEx(pszNext, TEXT("\\EventHandlers\\"),
  155. cchLeft, &pszNext, &cchLeft);
  156. if (SUCCEEDED(hr))
  157. {
  158. hr = SafeStrCpyN(pszNext, pszEventType, cchLeft);
  159. }
  160. }
  161. }
  162. }
  163. pelemToRelease->RCRelease();
  164. }
  165. }
  166. if (FAILED(hr) || (S_FALSE == hr))
  167. {
  168. *pszEventKeyName = NULL;
  169. }
  170. return hr;
  171. }
  172. HRESULT _GetEventString(LPCWSTR pszDeviceID, LPCWSTR pszEventType,
  173. LPCWSTR pszValueName, LPWSTR psz, DWORD cch)
  174. {
  175. WCHAR szKeyName[MAX_KEY];
  176. HRESULT hr = _GetEventKeyName(pszDeviceID, pszEventType, szKeyName,
  177. ARRAYSIZE(szKeyName));
  178. if (SUCCEEDED(hr) && (S_FALSE != hr))
  179. {
  180. HKEY hkey;
  181. hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey);
  182. if (SUCCEEDED(hr) && (S_FALSE != hr))
  183. {
  184. hr = _RegQueryString(hkey, NULL, pszValueName, psz, cch);
  185. _RegCloseKey(hkey);
  186. }
  187. }
  188. return hr;
  189. }
  190. HRESULT _GetEventFriendlyName(LPCWSTR pszDeviceID, LPCWSTR pszEventType,
  191. LPWSTR pszFriendlyName, DWORD cchFriendlyName)
  192. {
  193. return _GetEventString(pszDeviceID, pszEventType, TEXT("FriendlyName"),
  194. pszFriendlyName, cchFriendlyName);
  195. }
  196. HRESULT _GetEventIconLocation(LPCWSTR pszDeviceID, LPCWSTR pszEventType,
  197. LPWSTR pszIconLocation, DWORD cchIconLocation)
  198. {
  199. return _GetEventString(pszDeviceID, pszEventType, TEXT("DefaultIcon"),
  200. pszIconLocation, cchIconLocation);
  201. }
  202. ///////////////////////////////////////////////////////////////////////////////
  203. //
  204. // Return values:
  205. // S_FALSE: Did not find it
  206. // S_OK: Found it
  207. //
  208. // If finds it, the subkey is appended to pszKey
  209. HRESULT _CheckForSubKeyExistence(LPWSTR pszKey, DWORD cchKey, LPCWSTR pszSubKey)
  210. {
  211. LPWSTR pszNext;
  212. DWORD cchLeft;
  213. HRESULT hr = SafeStrCatNEx(pszKey, TEXT("\\"), cchKey, &pszNext,
  214. &cchLeft);
  215. if (SUCCEEDED(hr))
  216. {
  217. hr = SafeStrCpyNEx(pszNext, pszSubKey, cchLeft, &pszNext,
  218. &cchLeft);
  219. if (SUCCEEDED(hr))
  220. {
  221. // Check if it exist
  222. HKEY hkey;
  223. hr = _RegOpenKey(HKEY_LOCAL_MACHINE, pszKey, &hkey);
  224. if (SUCCEEDED(hr) && (S_FALSE != hr))
  225. {
  226. _RegCloseKey(hkey);
  227. }
  228. }
  229. }
  230. return hr;
  231. }
  232. HRESULT _GetDevicePropertySize(CHWDeviceInst* phwdevinst,
  233. LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pcbSize)
  234. {
  235. // Instance
  236. DEVINST devinst;
  237. HRESULT hr = phwdevinst->GetDeviceInstance(&devinst);
  238. if (SUCCEEDED(hr) && (S_FALSE != hr))
  239. {
  240. BYTE rgb[1];
  241. ULONG ulData = sizeof(rgb);
  242. ULONG ulFlags = 0;
  243. if (fUseMergeMultiSz)
  244. {
  245. ulFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ;
  246. }
  247. CONFIGRET cr = CM_Get_DevNode_Custom_Property(devinst, pszPropName,
  248. NULL, rgb, &ulData, ulFlags);
  249. if (CR_SUCCESS != cr)
  250. {
  251. if (CR_BUFFER_SMALL == cr)
  252. {
  253. hr = S_OK;
  254. *pcbSize = ulData;
  255. }
  256. else
  257. {
  258. // If we do not have the data at the instance level, let's try it
  259. // at the DeviceGroup level.
  260. // DeviceGroup
  261. WCHAR szDeviceGroup[MAX_DEVICEGROUP];
  262. ulData = sizeof(szDeviceGroup);
  263. cr = CM_Get_DevNode_Custom_Property(devinst, TEXT("DeviceGroup"),
  264. NULL, (PBYTE)szDeviceGroup, &ulData, 0);
  265. if (CR_SUCCESS == cr)
  266. {
  267. WCHAR szKey[MAX_KEY] =
  268. SHDEVICEEVENTROOT(TEXT("DeviceGroups\\"));
  269. hr = SafeStrCatN(szKey, szDeviceGroup, ARRAYSIZE(szKey));
  270. if (SUCCEEDED(hr))
  271. {
  272. hr = _GetPropertySizeHelper(szKey, pszPropName,
  273. pcbSize);
  274. }
  275. }
  276. else
  277. {
  278. hr = S_FALSE;
  279. }
  280. }
  281. }
  282. }
  283. if (S_FALSE == hr)
  284. {
  285. // If we do not have the data at the instance level, nor the device
  286. // group level, let's try it at the DeviceClass level.
  287. // DeviceClass
  288. GUID guidInterface;
  289. hr = phwdevinst->GetInterfaceGUID(&guidInterface);
  290. if (SUCCEEDED(hr) && (S_FALSE != hr))
  291. {
  292. WCHAR szKey[MAX_KEY];
  293. LPWSTR pszNext;
  294. DWORD cchLeft;
  295. hr = SafeStrCpyNEx(szKey,
  296. SHDEVICEEVENTROOT(TEXT("DeviceClasses\\")), ARRAYSIZE(szKey),
  297. &pszNext, &cchLeft);
  298. if (SUCCEEDED(hr))
  299. {
  300. hr = _StringFromGUID(&guidInterface, pszNext, cchLeft);
  301. if (SUCCEEDED(hr) && (S_FALSE != hr))
  302. {
  303. hr = _GetPropertySizeHelper(szKey, pszPropName, pcbSize);
  304. }
  305. }
  306. }
  307. }
  308. return hr;
  309. }
  310. HRESULT _GetDevicePropertyGeneric(CHWDeviceInst* phwdevinst,
  311. LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pdwType, LPBYTE pbData,
  312. DWORD cbData)
  313. {
  314. // Instance
  315. DEVINST devinst;
  316. HRESULT hr = phwdevinst->GetDeviceInstance(&devinst);
  317. if (CHWEventDetectorHelper::_fDiagnosticAppPresent)
  318. {
  319. WCHAR szPnpID[MAX_PNPID];
  320. WCHAR szGUID[MAX_GUIDSTRING];
  321. GUID guid;
  322. HRESULT hrTmp = phwdevinst->GetPnpID(szPnpID, ARRAYSIZE(szPnpID));
  323. if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp))
  324. {
  325. DIAGNOSTIC((TEXT("[0269]Device PnP ID: %s"), szPnpID));
  326. }
  327. hrTmp = phwdevinst->GetInterfaceGUID(&guid);
  328. if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp))
  329. {
  330. hrTmp = _StringFromGUID(&guid, szGUID, ARRAYSIZE(szGUID));
  331. if (SUCCEEDED(hrTmp))
  332. {
  333. DIAGNOSTIC((TEXT("[0270]Device Class ID: %s"), szGUID));
  334. }
  335. }
  336. }
  337. *pdwType = 0;
  338. if (SUCCEEDED(hr) && (S_FALSE != hr))
  339. {
  340. ULONG ulData = cbData;
  341. ULONG ulType;
  342. ULONG ulFlags = 0;
  343. if (fUseMergeMultiSz)
  344. {
  345. ulFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ;
  346. }
  347. CONFIGRET cr = CM_Get_DevNode_Custom_Property(devinst, pszPropName,
  348. &ulType, pbData, &ulData, ulFlags);
  349. if (CR_SUCCESS != cr)
  350. {
  351. // If we do not have the data at the instance level, let's try it
  352. // at the DeviceGroup level.
  353. // DeviceGroup
  354. WCHAR szDeviceGroup[MAX_DEVICEGROUP];
  355. DIAGNOSTIC((TEXT("[0252]Did NOT get Custom Property (%s) at device instance level"),
  356. pszPropName));
  357. ulData = sizeof(szDeviceGroup);
  358. cr = CM_Get_DevNode_Custom_Property(devinst, TEXT("DeviceGroup"),
  359. NULL, (PBYTE)szDeviceGroup, &ulData, 0);
  360. if (CR_SUCCESS == cr)
  361. {
  362. WCHAR szKey[MAX_KEY] =
  363. SHDEVICEEVENTROOT(TEXT("DeviceGroups\\"));
  364. hr = SafeStrCatN(szKey, szDeviceGroup, ARRAYSIZE(szKey));
  365. if (SUCCEEDED(hr))
  366. {
  367. hr = _GetPropertyHelper(szKey, pszPropName, pdwType,
  368. pbData, cbData);
  369. if (SUCCEEDED(hr))
  370. {
  371. if (S_FALSE != hr)
  372. {
  373. DIAGNOSTIC((TEXT("[0253]Got Custom Property (%s) at DeviceGroup level (%s)"),
  374. pszPropName, szDeviceGroup));
  375. }
  376. else
  377. {
  378. DIAGNOSTIC((TEXT("[0254]Did NOT get Custom Property (%s) at DeviceGroup level (%s)"),
  379. pszPropName, szDeviceGroup));
  380. }
  381. }
  382. }
  383. }
  384. else
  385. {
  386. hr = S_FALSE;
  387. }
  388. }
  389. else
  390. {
  391. DIAGNOSTIC((TEXT("[0251]Got Custom Property (%s) at device instance level"), pszPropName));
  392. *pdwType = (DWORD)ulType;
  393. }
  394. }
  395. if (S_FALSE == hr)
  396. {
  397. // If we do not have the data at the instance level, nor the device
  398. // group level, let's try it at the DeviceClass level.
  399. // DeviceClass
  400. GUID guidInterface;
  401. hr = phwdevinst->GetInterfaceGUID(&guidInterface);
  402. if (SUCCEEDED(hr) && (S_FALSE != hr))
  403. {
  404. WCHAR szKey[MAX_KEY];
  405. LPWSTR pszNext;
  406. DWORD cchLeft;
  407. hr = SafeStrCpyNEx(szKey,
  408. SHDEVICEEVENTROOT(TEXT("DeviceClasses\\")), ARRAYSIZE(szKey),
  409. &pszNext, &cchLeft);
  410. if (SUCCEEDED(hr))
  411. {
  412. hr = _StringFromGUID(&guidInterface, pszNext, cchLeft);
  413. if (SUCCEEDED(hr) && (S_FALSE != hr))
  414. {
  415. hr = _GetPropertyHelper(szKey, pszPropName, pdwType,
  416. pbData, cbData);
  417. if (SUCCEEDED(hr))
  418. {
  419. if (S_FALSE != hr)
  420. {
  421. DIAGNOSTIC((TEXT("[0255]Got Custom Property (%s) at DeviceClass level (%s)"),
  422. pszPropName, pszNext));
  423. }
  424. else
  425. {
  426. DIAGNOSTIC((TEXT("[0256]Did NOT get Custom Property (%s) at DeviceClass level (%s)"),
  427. pszPropName, pszNext));
  428. }
  429. }
  430. }
  431. }
  432. }
  433. }
  434. return hr;
  435. }
  436. HRESULT _GetDevicePropertyAsString(CHWDeviceInst* phwdevinst,
  437. LPCWSTR pszPropName, LPCWSTR psz, DWORD cch)
  438. {
  439. DWORD dwType;
  440. DWORD cbData = cch * sizeof(WCHAR);
  441. return _GetDevicePropertyGeneric(phwdevinst, pszPropName, FALSE, &dwType,
  442. (PBYTE)psz, cbData);
  443. }
  444. HRESULT _GetDevicePropertyGenericAsMultiSz(CHWDeviceInst* phwdevinst,
  445. LPCWSTR pszPropName, BOOL fUseMergeMultiSz, WORD_BLOB** ppblob)
  446. {
  447. DWORD cbSize = NULL;
  448. HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE,
  449. &cbSize);
  450. *ppblob = NULL;
  451. if (SUCCEEDED(hr) && (S_FALSE != hr))
  452. {
  453. WORD_BLOB* pblob = (WORD_BLOB*)CoTaskMemAlloc(
  454. sizeof(WORD_BLOB) + cbSize + sizeof(WCHAR));
  455. if (pblob)
  456. {
  457. DWORD dwType;
  458. DWORD cbSize2 = cbSize + sizeof(WCHAR);
  459. pblob->clSize = (cbSize + sizeof(WCHAR))/2;
  460. hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName,
  461. fUseMergeMultiSz, &dwType, (PBYTE)(pblob->asData),
  462. cbSize2);
  463. if (SUCCEEDED(hr) && (S_FALSE != hr))
  464. {
  465. if (REG_MULTI_SZ == dwType)
  466. {
  467. DIAGNOSTIC((TEXT("[0265]Found Property: '%s'"), pszPropName));
  468. *ppblob = pblob;
  469. pblob = NULL;
  470. }
  471. else
  472. {
  473. DIAGNOSTIC((TEXT("[0266]Found Property: '%s', but NOT REG_MULTI_SZ type"), pszPropName));
  474. hr = E_FAIL;
  475. }
  476. }
  477. if (pblob)
  478. {
  479. // It did not get assigned
  480. CoTaskMemFree(pblob);
  481. }
  482. }
  483. else
  484. {
  485. hr = E_OUTOFMEMORY;
  486. }
  487. }
  488. return hr;
  489. }
  490. HRESULT _GetDevicePropertyGenericAsBlob(CHWDeviceInst* phwdevinst,
  491. LPCWSTR pszPropName, BYTE_BLOB** ppblob)
  492. {
  493. DWORD cbSize = NULL;
  494. HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE,
  495. &cbSize);
  496. *ppblob = NULL;
  497. if (SUCCEEDED(hr) && (S_FALSE != hr))
  498. {
  499. BYTE_BLOB* pblob = (BYTE_BLOB*)CoTaskMemAlloc(
  500. sizeof(BYTE_BLOB) + cbSize);
  501. if (pblob)
  502. {
  503. DWORD dwType;
  504. pblob->clSize = cbSize;
  505. hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName,
  506. FALSE, &dwType, (PBYTE)pblob->abData, pblob->clSize);
  507. if (SUCCEEDED(hr) && (S_FALSE != hr))
  508. {
  509. if (REG_BINARY == dwType)
  510. {
  511. DIAGNOSTIC((TEXT("[0267]Found Property: '%s'"), pszPropName));
  512. *ppblob = pblob;
  513. pblob = NULL;
  514. }
  515. else
  516. {
  517. DIAGNOSTIC((TEXT("[0268]Found Property: '%s', but NOT REG_BINARY type"), pszPropName));
  518. hr = E_FAIL;
  519. }
  520. }
  521. if (pblob)
  522. {
  523. // It did not get assigned
  524. CoTaskMemFree(pblob);
  525. }
  526. }
  527. else
  528. {
  529. hr = E_OUTOFMEMORY;
  530. }
  531. }
  532. return hr;
  533. }
  534. HRESULT _GetDevicePropertyStringNoBuf(CHWDeviceInst* phwdevinst,
  535. LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pdwType,
  536. LPWSTR* ppszProp)
  537. {
  538. DWORD cbSize = NULL;
  539. HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE,
  540. &cbSize);
  541. *ppszProp = NULL;
  542. if (SUCCEEDED(hr) && (S_FALSE != hr))
  543. {
  544. LPWSTR psz;
  545. cbSize += sizeof(WCHAR);
  546. psz = (LPWSTR)CoTaskMemAlloc(cbSize);
  547. if (psz)
  548. {
  549. hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName,
  550. fUseMergeMultiSz, pdwType, (PBYTE)psz, cbSize);
  551. if (FAILED(hr) || (S_FALSE == hr))
  552. {
  553. CoTaskMemFree(psz);
  554. }
  555. else
  556. {
  557. *ppszProp = psz;
  558. }
  559. }
  560. else
  561. {
  562. hr = E_OUTOFMEMORY;
  563. }
  564. }
  565. return hr;
  566. }
  567. // Return Values:
  568. // S_FALSE: Can't find it
  569. HRESULT _GetDeviceHandler(CHWDeviceInst* phwdevinst, LPWSTR pszDeviceHandler,
  570. DWORD cchDeviceHandler)
  571. {
  572. return _GetDevicePropertyAsString(phwdevinst, TEXT("DeviceHandlers"),
  573. pszDeviceHandler, cchDeviceHandler);
  574. }
  575. ///////////////////////////////////////////////////////////////////////////////
  576. //
  577. HRESULT _OpenHandlerRegKey(LPCWSTR pszHandler, HKEY* phkey)
  578. {
  579. WCHAR szKey[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("Handlers\\"));
  580. HRESULT hr = SafeStrCatN(szKey, pszHandler, ARRAYSIZE(szKey));
  581. if (SUCCEEDED(hr))
  582. {
  583. hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKey, phkey);
  584. }
  585. return hr;
  586. }
  587. HRESULT _CloseHandlerRegKey(HKEY hkey)
  588. {
  589. return _RegCloseKey(hkey);
  590. }
  591. HRESULT _GetHandlerCancelCLSID(LPCWSTR pszHandler, CLSID* pclsid)
  592. {
  593. HKEY hkey;
  594. HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey);
  595. if (SUCCEEDED(hr))
  596. {
  597. WCHAR szProgID[MAX_PROGID];
  598. hr = _RegQueryString(hkey, NULL, TEXT("CLSIDForCancel"), szProgID,
  599. ARRAYSIZE(szProgID));
  600. if (SUCCEEDED(hr))
  601. {
  602. if (S_FALSE != hr)
  603. {
  604. hr = _GUIDFromString(szProgID, pclsid);
  605. DIAGNOSTIC((TEXT("[0162]Got Handler Cancel CLSID (from CLSIDForCancel): %s"), szProgID));
  606. TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler Cancel CLSID"));
  607. }
  608. else
  609. {
  610. hr = _GetHandlerCLSID(pszHandler, pclsid);
  611. if (CHWEventDetectorHelper::_fDiagnosticAppPresent)
  612. {
  613. if (SUCCEEDED(hr))
  614. {
  615. if (S_FALSE != hr)
  616. {
  617. hr = _StringFromGUID(pclsid, szProgID, ARRAYSIZE(szProgID));
  618. if (SUCCEEDED(hr))
  619. {
  620. DIAGNOSTIC((TEXT("[0164]Got Handler Cancel CLSID: %s"), szProgID));
  621. }
  622. }
  623. }
  624. }
  625. }
  626. }
  627. _CloseHandlerRegKey(hkey);
  628. }
  629. return hr;
  630. }
  631. HRESULT _GetHandlerCLSID(LPCWSTR pszHandler, CLSID* pclsid)
  632. {
  633. HKEY hkey;
  634. HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey);
  635. if (SUCCEEDED(hr))
  636. {
  637. WCHAR szProgID[MAX_PROGID];
  638. hr = _RegQueryString(hkey, NULL, TEXT("ProgID"), szProgID,
  639. ARRAYSIZE(szProgID));
  640. if (SUCCEEDED(hr))
  641. {
  642. if (S_FALSE != hr)
  643. {
  644. hr = CLSIDFromProgID(szProgID, pclsid);
  645. DIAGNOSTIC((TEXT("[0160]Got Handler ProgID: %s"), szProgID));
  646. TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler ProgID: %s"),
  647. szProgID);
  648. }
  649. else
  650. {
  651. // Not there, maybe we have CLSID value?
  652. // Reuse szProgID
  653. hr = _RegQueryString(hkey, NULL, TEXT("CLSID"), szProgID,
  654. ARRAYSIZE(szProgID));
  655. if (SUCCEEDED(hr) && (S_FALSE != hr))
  656. {
  657. hr = _GUIDFromString(szProgID, pclsid);
  658. DIAGNOSTIC((TEXT("[0161]Got Handler CLSID: %s"), szProgID));
  659. TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler CLSID"));
  660. }
  661. else
  662. {
  663. DIAGNOSTIC((TEXT("[0163]Did NOT get Handler ProgID or CLSID")));
  664. }
  665. }
  666. }
  667. _CloseHandlerRegKey(hkey);
  668. }
  669. return hr;
  670. }
  671. // Return values:
  672. // S_FALSE: Cannot find an InitCmdLine
  673. //
  674. HRESULT _GetInitCmdLine(LPCWSTR pszHandler, LPWSTR* ppsz)
  675. {
  676. HKEY hkey;
  677. HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey);
  678. *ppsz = NULL;
  679. if (SUCCEEDED(hr))
  680. {
  681. DWORD cb = NULL;
  682. hr = _RegQueryValueSize(hkey, NULL, TEXT("InitCmdLine"), &cb);
  683. if (SUCCEEDED(hr) && (S_FALSE != hr))
  684. {
  685. LPWSTR psz = (LPWSTR)LocalAlloc(LPTR, cb);
  686. if (psz)
  687. {
  688. hr = _RegQueryString(hkey, NULL, TEXT("InitCmdLine"), psz,
  689. cb / sizeof(WCHAR));
  690. if (SUCCEEDED(hr) && (S_FALSE != hr))
  691. {
  692. DIAGNOSTIC((TEXT("[0158]Got InitCmdLine for Handler (%s): '%s'"), pszHandler, psz));
  693. *ppsz = psz;
  694. }
  695. else
  696. {
  697. LocalFree((HLOCAL)psz);
  698. }
  699. }
  700. else
  701. {
  702. hr = E_OUTOFMEMORY;
  703. }
  704. }
  705. else
  706. {
  707. DIAGNOSTIC((TEXT("[0159]NO InitCmdLine for Handler (%s)"), pszHandler));
  708. }
  709. _CloseHandlerRegKey(hkey);
  710. }
  711. return hr;
  712. }
  713. HRESULT _MakeUserDefaultValueString(LPCWSTR pszDeviceID,
  714. LPCWSTR pszEventHandler, LPWSTR pszUserDefault, DWORD cchUserDefault)
  715. {
  716. DWORD cchLeft;
  717. LPWSTR pszNext;
  718. HRESULT hr = SafeStrCpyNEx(pszUserDefault, pszDeviceID, cchUserDefault,
  719. &pszNext, &cchLeft);
  720. if (SUCCEEDED(hr))
  721. {
  722. hr = SafeStrCpyNEx(pszNext, TEXT("+"), cchLeft, &pszNext, &cchLeft);
  723. if (SUCCEEDED(hr))
  724. {
  725. hr = SafeStrCpyN(pszNext, pszEventHandler, cchLeft);
  726. }
  727. }
  728. return hr;
  729. }
  730. // from setenum.cpp
  731. HRESULT _GetKeyLastWriteTime(LPCWSTR pszHandler, FILETIME* pft);
  732. HRESULT _HaveNewHandlersBeenInstalledSinceUserSelection(LPCWSTR pszEventHandler,
  733. FILETIME* pftUserSelection, BOOL* pfNewHandlersSinceUserSelection)
  734. {
  735. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlers\\"));
  736. HRESULT hr = SafeStrCatN(szKeyName, pszEventHandler,
  737. ARRAYSIZE(szKeyName));
  738. ULARGE_INTEGER ulUserSelection;
  739. ulUserSelection.LowPart = pftUserSelection->dwLowDateTime;
  740. ulUserSelection.HighPart = pftUserSelection->dwHighDateTime;
  741. *pfNewHandlersSinceUserSelection = FALSE;
  742. if (SUCCEEDED(hr))
  743. {
  744. HKEY hkey;
  745. hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey);
  746. if (SUCCEEDED(hr) && (S_FALSE != hr))
  747. {
  748. DWORD dw = 0;
  749. BOOL fGoOut = FALSE;
  750. do
  751. {
  752. WCHAR szHandler[MAX_HANDLER];
  753. hr = _RegEnumStringValue(hkey, dw, szHandler,
  754. ARRAYSIZE(szHandler));
  755. if (SUCCEEDED(hr) && (S_FALSE != hr))
  756. {
  757. FILETIME ft;
  758. hr = _GetKeyLastWriteTime(szHandler, &ft);
  759. if (SUCCEEDED(hr) && (S_FALSE != hr))
  760. {
  761. ULARGE_INTEGER ul;
  762. ul.LowPart = ft.dwLowDateTime;
  763. ul.HighPart = ft.dwHighDateTime;
  764. if (ul.QuadPart > ulUserSelection.QuadPart)
  765. {
  766. *pfNewHandlersSinceUserSelection = TRUE;
  767. hr = S_OK;
  768. fGoOut = TRUE;
  769. }
  770. }
  771. }
  772. else
  773. {
  774. fGoOut = TRUE;
  775. }
  776. ++dw;
  777. }
  778. while (!fGoOut);
  779. if (S_FALSE == hr)
  780. {
  781. hr = S_OK;
  782. }
  783. _RegCloseKey(hkey);
  784. }
  785. }
  786. return hr;
  787. }
  788. struct _USERSELECTIONHIDDENDATA
  789. {
  790. _USERSELECTIONHIDDENDATA() : dw(0) {}
  791. FILETIME ft;
  792. // Set this to zero so that RegSetValueEx will not NULL terminate out stuff
  793. DWORD dw;
  794. };
  795. // See comment for _MakeFinalUserDefaultHandler
  796. HRESULT _GetHandlerAndFILETIME(HKEY hkeyUser, LPCWSTR pszKeyName,
  797. LPCWSTR pszUserDefault, LPWSTR pszHandler, DWORD cchHandler, FILETIME* pft)
  798. {
  799. DWORD cb;
  800. HRESULT hr = _RegQueryValueSize(hkeyUser, pszKeyName, pszUserDefault, &cb);
  801. if (SUCCEEDED(hr) && (S_FALSE != hr))
  802. {
  803. BYTE* pb = (BYTE*)LocalAlloc(LPTR, cb);
  804. if (pb)
  805. {
  806. hr = _RegQueryGeneric(hkeyUser, pszKeyName, pszUserDefault, pb,
  807. cb);
  808. if (SUCCEEDED(hr) && (S_FALSE != hr))
  809. {
  810. // We should have something like this:
  811. // MyHandler\0<_USERSELECTIONHIDDENDATA struct>
  812. hr = StringCchCopy(pszHandler, cchHandler, (LPWSTR)pb);
  813. if (SUCCEEDED(hr))
  814. {
  815. DWORD cbString = (lstrlen(pszHandler) + 1) * sizeof(WCHAR);
  816. // Make sure we're dealing with the right thing
  817. if ((cb >= cbString + sizeof(_USERSELECTIONHIDDENDATA)) &&
  818. (cb <= cbString + sizeof(_USERSELECTIONHIDDENDATA) + sizeof(void*)))
  819. {
  820. // Yep! So _USERSELECTIONHIDDENDATA should be at the end of the blob
  821. _USERSELECTIONHIDDENDATA* pushd = (_USERSELECTIONHIDDENDATA*)
  822. (pb + (cb - sizeof(_USERSELECTIONHIDDENDATA)));
  823. *pft = pushd->ft;
  824. }
  825. else
  826. {
  827. *pszHandler = 0;
  828. hr = S_FALSE;
  829. }
  830. }
  831. }
  832. LocalFree(pb);
  833. }
  834. else
  835. {
  836. hr = E_OUTOFMEMORY;
  837. }
  838. }
  839. return hr;
  840. }
  841. HRESULT _GetEventHandlerDefault(HKEY hkeyUser, LPCWSTR pszEventHandler,
  842. LPWSTR pszHandler, DWORD cchHandler)
  843. {
  844. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\"));
  845. return _RegQueryString(hkeyUser, szKeyName, pszEventHandler, pszHandler,
  846. cchHandler);
  847. }
  848. HRESULT _GetUserDefaultHandler(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler,
  849. LPWSTR pszHandler, DWORD cchHandler, BOOL fImpersonateCaller)
  850. {
  851. WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:");
  852. HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler,
  853. &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2);
  854. if (cchHandler)
  855. {
  856. *pszHandler = 0;
  857. }
  858. if (SUCCEEDED(hr))
  859. {
  860. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\"));
  861. HKEY hkeyUser;
  862. HANDLE hThreadToken;
  863. if (GUH_IMPERSONATEUSER == fImpersonateCaller)
  864. {
  865. hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser);
  866. }
  867. else
  868. {
  869. hr = _GetCurrentUserHKCU(&hThreadToken, &hkeyUser);
  870. }
  871. if (SUCCEEDED(hr) && (S_FALSE != hr))
  872. {
  873. FILETIME ft;
  874. DWORD dwHandlerDefaultFlag = 0;
  875. hr = _GetHandlerAndFILETIME(hkeyUser, szKeyName,
  876. szUserDefault, pszHandler, cchHandler, &ft);
  877. if (SUCCEEDED(hr))
  878. {
  879. if (S_FALSE == hr)
  880. {
  881. // we do not have a UserChosenDefault
  882. hr = SafeStrCpyN(pszHandler, TEXT("MSPromptEachTime"),
  883. cchHandler);
  884. }
  885. else
  886. {
  887. // we have a user chosen default
  888. dwHandlerDefaultFlag |= HANDLERDEFAULT_USERCHOSENDEFAULT;
  889. }
  890. }
  891. if (SUCCEEDED(hr))
  892. {
  893. if (HANDLERDEFAULT_USERCHOSENDEFAULT & dwHandlerDefaultFlag)
  894. {
  895. BOOL fNewHandlersSinceUserSelection;
  896. hr = _HaveNewHandlersBeenInstalledSinceUserSelection(
  897. pszEventHandler, &ft, &fNewHandlersSinceUserSelection);
  898. if (SUCCEEDED(hr))
  899. {
  900. if (fNewHandlersSinceUserSelection)
  901. {
  902. dwHandlerDefaultFlag |=
  903. HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED;
  904. }
  905. }
  906. }
  907. }
  908. if (SUCCEEDED(hr))
  909. {
  910. BOOL fUseEventHandlerDefault = FALSE;
  911. if (!(HANDLERDEFAULT_USERCHOSENDEFAULT & dwHandlerDefaultFlag))
  912. {
  913. fUseEventHandlerDefault = TRUE;
  914. }
  915. else
  916. {
  917. if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED &
  918. dwHandlerDefaultFlag)
  919. {
  920. fUseEventHandlerDefault = TRUE;
  921. }
  922. }
  923. if (fUseEventHandlerDefault)
  924. {
  925. WCHAR szHandlerLocal[MAX_HANDLER];
  926. hr = _GetEventHandlerDefault(hkeyUser, pszEventHandler,
  927. szHandlerLocal, ARRAYSIZE(szHandlerLocal));
  928. if (SUCCEEDED(hr))
  929. {
  930. if (S_FALSE != hr)
  931. {
  932. dwHandlerDefaultFlag |=
  933. HANDLERDEFAULT_EVENTHANDLERDEFAULT;
  934. if (HANDLERDEFAULT_USERCHOSENDEFAULT &
  935. dwHandlerDefaultFlag)
  936. {
  937. if (lstrcmp(szHandlerLocal, pszHandler))
  938. {
  939. dwHandlerDefaultFlag |=
  940. HANDLERDEFAULT_DEFAULTSAREDIFFERENT;
  941. }
  942. }
  943. else
  944. {
  945. dwHandlerDefaultFlag |=
  946. HANDLERDEFAULT_DEFAULTSAREDIFFERENT;
  947. }
  948. hr = StringCchCopy(pszHandler, cchHandler,
  949. szHandlerLocal);
  950. }
  951. }
  952. }
  953. }
  954. if (SUCCEEDED(hr))
  955. {
  956. // Let's build the return value
  957. hr = HANDLERDEFAULT_MAKERETURNVALUE(dwHandlerDefaultFlag);
  958. }
  959. if (GUH_IMPERSONATEUSER == fImpersonateCaller)
  960. {
  961. _CoCloseCallingUserHKCU(hThreadToken, hkeyUser);
  962. }
  963. else
  964. {
  965. _CloseCurrentUserHKCU(hThreadToken, hkeyUser);
  966. }
  967. }
  968. }
  969. return hr;
  970. }
  971. HRESULT _GetHandlerForNoContent(LPCWSTR pszEventHandler, LPWSTR pszHandler,
  972. DWORD cchHandler)
  973. {
  974. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlers\\"));
  975. HRESULT hr = SafeStrCatN(szKeyName, pszEventHandler, ARRAYSIZE(szKeyName));
  976. if (SUCCEEDED(hr))
  977. {
  978. hr = _GetValueToUse(szKeyName, pszHandler, cchHandler);
  979. }
  980. return hr;
  981. }
  982. // We want to store the time this default is set. We'll need it to check if
  983. // other handlers for this event were installed after the user made a choice.
  984. // If that's the case, we'll reprompt the user.
  985. // *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
  986. // We store the time as a FILETIME *after* the '\0' string terminator. This is
  987. // so it will be hidden in RegEdit.
  988. // stephstm (2002-04-12)
  989. // *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
  990. HRESULT _MakeFinalUserDefaultHandler(LPCWSTR pszHandler, BYTE** ppb,
  991. DWORD* pcb)
  992. {
  993. HRESULT hr;
  994. DWORD cch = lstrlen(pszHandler) + 1;
  995. DWORD cbOffset = cch * sizeof(WCHAR);
  996. // Round up to be aligned on all platforms
  997. cbOffset = (cbOffset + sizeof(void*)) / sizeof(void*) * sizeof(void*);
  998. DWORD cb = cbOffset + sizeof(_USERSELECTIONHIDDENDATA);
  999. BYTE* pb = (BYTE*)LocalAlloc(LPTR, cb);
  1000. if (pb)
  1001. {
  1002. hr = StringCchCopy((LPWSTR)pb, cch, pszHandler);
  1003. if (SUCCEEDED(hr))
  1004. {
  1005. _USERSELECTIONHIDDENDATA ushd;
  1006. GetSystemTimeAsFileTime(&(ushd.ft));
  1007. CopyMemory(pb + cb - sizeof(_USERSELECTIONHIDDENDATA), &ushd,
  1008. sizeof(ushd));
  1009. }
  1010. if (SUCCEEDED(hr))
  1011. {
  1012. *ppb = pb;
  1013. *pcb = cb;
  1014. }
  1015. else
  1016. {
  1017. LocalFree(pb);
  1018. }
  1019. }
  1020. else
  1021. {
  1022. hr = E_OUTOFMEMORY;
  1023. }
  1024. return hr;
  1025. }
  1026. HRESULT _DeleteUserDefaultHandler(HKEY hkeyUser, LPCWSTR pszDeviceID,
  1027. LPCWSTR pszEventHandler)
  1028. {
  1029. WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:");
  1030. HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler,
  1031. &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2);
  1032. if (SUCCEEDED(hr))
  1033. {
  1034. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\"));
  1035. hr = _RegDeleteValue(hkeyUser, szKeyName, szUserDefault);
  1036. }
  1037. return hr;
  1038. }
  1039. HRESULT _SetSoftUserDefaultHandler(LPCWSTR pszDeviceID,
  1040. LPCWSTR pszEventHandler, LPCWSTR pszHandler)
  1041. {
  1042. HKEY hkey;
  1043. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\"));
  1044. HKEY hkeyUser;
  1045. HANDLE hThreadToken;
  1046. HRESULT hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser);
  1047. if (SUCCEEDED(hr) && (S_FALSE != hr))
  1048. {
  1049. DWORD dwDisp;
  1050. hr = _RegCreateKey(hkeyUser, szKeyName, &hkey, &dwDisp);
  1051. if (SUCCEEDED(hr) && (S_FALSE != hr))
  1052. {
  1053. hr = _RegSetString(hkey, pszEventHandler, pszHandler);
  1054. _DeleteUserDefaultHandler(hkeyUser, pszDeviceID, pszEventHandler);
  1055. _RegCloseKey(hkey);
  1056. }
  1057. _CoCloseCallingUserHKCU(hThreadToken, hkeyUser);
  1058. }
  1059. return hr;
  1060. }
  1061. HRESULT _DeleteSoftUserDefaultHandler(HKEY hkeyUser, LPCWSTR pszEventHandler)
  1062. {
  1063. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\"));
  1064. return _RegDeleteValue(hkeyUser, szKeyName, pszEventHandler);
  1065. }
  1066. HRESULT _SetUserDefaultHandler(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler,
  1067. LPCWSTR pszHandler)
  1068. {
  1069. WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:");
  1070. HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler,
  1071. &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2);
  1072. if (SUCCEEDED(hr))
  1073. {
  1074. HKEY hkey;
  1075. WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\"));
  1076. HKEY hkeyUser;
  1077. HANDLE hThreadToken;
  1078. hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser);
  1079. if (SUCCEEDED(hr) && (S_FALSE != hr))
  1080. {
  1081. if (!lstrcmp(pszHandler, TEXT("MSPromptEachTime")))
  1082. {
  1083. hr = _DeleteUserDefaultHandler(hkeyUser, pszDeviceID,
  1084. pszEventHandler);
  1085. }
  1086. else
  1087. {
  1088. DWORD dwDisp;
  1089. hr = _RegCreateKey(hkeyUser, szKeyName, &hkey, &dwDisp);
  1090. if (SUCCEEDED(hr) && (S_FALSE != hr))
  1091. {
  1092. BYTE* pb;
  1093. DWORD cb;
  1094. hr = _MakeFinalUserDefaultHandler(pszHandler, &pb, &cb);
  1095. if (SUCCEEDED(hr))
  1096. {
  1097. // See comment above _MakeFinalUserDefaultHandler
  1098. // StephStm: 2002-04-09
  1099. if (ERROR_SUCCESS == RegSetValueEx(hkey, szUserDefault, 0,
  1100. REG_SZ, pb, cb))
  1101. {
  1102. _DeleteSoftUserDefaultHandler(hkeyUser,
  1103. pszEventHandler);
  1104. hr = S_OK;
  1105. }
  1106. else
  1107. {
  1108. hr = S_FALSE;
  1109. }
  1110. LocalFree(pb);
  1111. }
  1112. _RegCloseKey(hkey);
  1113. }
  1114. }
  1115. _CoCloseCallingUserHKCU(hThreadToken, hkeyUser);
  1116. }
  1117. }
  1118. return hr;
  1119. }
  1120. ///////////////////////////////////////////////////////////////////////////////
  1121. //