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.

837 lines
23 KiB

  1. #include "priv.h"
  2. // Build this file only on Win9X or NT4
  3. #ifdef DOWNLEVEL_PLATFORM
  4. __inline LPWSTR StrCpyNXW(LPWSTR psz1, LPCWSTR psz2, int cchMax)
  5. {
  6. ASSERT(psz1);
  7. ASSERT(psz2);
  8. if (0 < cchMax)
  9. {
  10. // Leave room for the null terminator
  11. while (0 < --cchMax)
  12. {
  13. if ( !(*psz1++ = *psz2++) ) {
  14. --psz1;
  15. break;
  16. }
  17. }
  18. if (0 == cchMax)
  19. *psz1 = L'\0';
  20. ASSERT(*psz1 == 0);
  21. }
  22. return psz1;
  23. }
  24. LPWSTR StrCpyNW(LPWSTR psz1, LPCWSTR psz2, int cchMax)
  25. {
  26. StrCpyNXW(psz1, psz2, cchMax);
  27. return psz1;
  28. }
  29. LPWSTR StrCpyW(LPWSTR psz1, LPCWSTR psz2)
  30. {
  31. LPWSTR psz = psz1;
  32. ASSERT(psz1);
  33. ASSERT(psz2);
  34. while (*psz1++ = *psz2++)
  35. ;
  36. return psz;
  37. }
  38. STDAPI_(DWORD)
  39. RegData_AtoW(
  40. IN LPCVOID pvData,
  41. IN DWORD dwSize,
  42. IN DWORD dwType,
  43. /*INOUT*/ LPDWORD pcbData
  44. )
  45. {
  46. DWORD dwRet = NO_ERROR;
  47. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType || REG_MULTI_SZ == dwType)
  48. {
  49. DWORD cbData = pcbData ? *pcbData : -1;
  50. if (pvData)
  51. {
  52. // Allocate a temporary buffer to work with
  53. int cch = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pvData, cbData, NULL, 0);
  54. LPWSTR pwszT = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cch));
  55. if (!pwszT)
  56. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  57. else
  58. {
  59. if (CbFromCchW(cch) > dwSize)
  60. dwRet = ERROR_MORE_DATA;
  61. else
  62. {
  63. // Convert it to the temporary buffer
  64. MultiByteToWideChar(CP_ACP, 0, (LPSTR)pvData, cbData, pwszT, cch);
  65. // Copy it back to the output buffer
  66. StrCpyW((LPWSTR)pvData, pwszT);
  67. }
  68. LocalFree(pwszT);
  69. }
  70. // If string data, make room for unicode
  71. if (pcbData)
  72. {
  73. (*pcbData) = cch * sizeof(WCHAR);
  74. }
  75. }
  76. else if (pcbData)
  77. {
  78. // We don't have the data so guess (actual value may be less)
  79. // PERF: Does this need to be exact? For now this seem sufficient. (Stevepro)
  80. (*pcbData) *= sizeof(WCHAR);
  81. }
  82. }
  83. return dwRet;
  84. }
  85. /*----------------------------------------------------------
  86. Purpose: Recursively delete the key, including all child values
  87. and keys. Mimics what RegDeleteKey does in Win95.
  88. Returns:
  89. Cond: --
  90. */
  91. DWORD
  92. DeleteKeyRecursively(
  93. IN HKEY hkey,
  94. IN LPCSTR pszSubKey)
  95. {
  96. DWORD dwRet;
  97. HKEY hkSubKey;
  98. // Open the subkey so we can enumerate any children
  99. dwRet = RegOpenKeyExA(hkey, pszSubKey, 0, MAXIMUM_ALLOWED, &hkSubKey);
  100. if (ERROR_SUCCESS == dwRet)
  101. {
  102. DWORD dwIndex;
  103. CHAR szSubKeyName[MAX_PATH + 1];
  104. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  105. CHAR szClass[MAX_PATH];
  106. DWORD cbClass = ARRAYSIZE(szClass);
  107. // I can't just call RegEnumKey with an ever-increasing index, because
  108. // I'm deleting the subkeys as I go, which alters the indices of the
  109. // remaining subkeys in an implementation-dependent way. In order to
  110. // be safe, I have to count backwards while deleting the subkeys.
  111. // Find out how many subkeys there are
  112. dwRet = RegQueryInfoKeyA(hkSubKey,
  113. szClass,
  114. &cbClass,
  115. NULL,
  116. &dwIndex, // The # of subkeys -- all we need
  117. NULL,
  118. NULL,
  119. NULL,
  120. NULL,
  121. NULL,
  122. NULL,
  123. NULL);
  124. if (NO_ERROR == dwRet)
  125. {
  126. // dwIndex is now the count of subkeys, but it needs to be
  127. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  128. // than post-decrement.
  129. while (ERROR_SUCCESS == RegEnumKeyA(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  130. {
  131. DeleteKeyRecursively(hkSubKey, szSubKeyName);
  132. }
  133. }
  134. RegCloseKey(hkSubKey);
  135. dwRet = RegDeleteKeyA(hkey, pszSubKey);
  136. }
  137. return dwRet;
  138. }
  139. /*----------------------------------------------------------
  140. Purpose: Recursively delete the key, including all child values
  141. and keys.
  142. Returns:
  143. Cond: --
  144. */
  145. STDAPI_(DWORD)
  146. SHDeleteKeyA(
  147. IN HKEY hkey,
  148. IN LPCSTR pszSubKey)
  149. {
  150. DWORD dwRet;
  151. if (g_bRunOnNT)
  152. {
  153. dwRet = DeleteKeyRecursively(hkey, pszSubKey);
  154. }
  155. else
  156. {
  157. // On Win95, RegDeleteKey does what we want
  158. dwRet = RegDeleteKeyA(hkey, pszSubKey);
  159. }
  160. return dwRet;
  161. }
  162. /*----------------------------------------------------------
  163. Purpose: Recursively delete the key, including all child values
  164. and keys.
  165. Returns:
  166. Cond: --
  167. */
  168. STDAPI_(DWORD)
  169. SHDeleteKeyW(
  170. IN HKEY hkey,
  171. IN LPCWSTR pwszSubKey)
  172. {
  173. DWORD dwRet;
  174. CHAR sz[MAX_PATH];
  175. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, sz, SIZECHARS(sz), NULL, NULL);
  176. if (g_bRunOnNT)
  177. {
  178. dwRet = DeleteKeyRecursively(hkey, sz);
  179. }
  180. else
  181. {
  182. // On Win95, RegDeleteKey does what we want
  183. dwRet = RegDeleteKeyA(hkey, sz);
  184. }
  185. return dwRet;
  186. }
  187. /*----------------------------------------------------------
  188. Purpose: Behaves just like RegQueryValueEx, except if the
  189. data type is REG_EXPAND_SZ, then this goes ahead
  190. and expands out the string. *pdwType will always
  191. be massaged to REG_SZ if this happens.
  192. Returns:
  193. Cond: --
  194. */
  195. STDAPI_(DWORD)
  196. SHQueryValueExA(
  197. IN HKEY hkey,
  198. IN LPCSTR pszValue,
  199. IN LPDWORD lpReserved,
  200. OUT LPDWORD pdwType,
  201. OUT LPVOID pvData,
  202. IN OUT LPDWORD pcbData)
  203. {
  204. DWORD dwRet;
  205. DWORD cbSize;
  206. DWORD dwType;
  207. LPSTR lpsz;
  208. // Trying to get back data
  209. if (pcbData)
  210. cbSize = *pcbData; // Size of output buffer
  211. dwRet = RegQueryValueExA(hkey, pszValue, lpReserved, &dwType,
  212. pvData, &cbSize);
  213. // Normally, we'd be done with this. But do some extra work
  214. // if this is an expandable string (something that has system
  215. // variables in it), or if we need to pad the buffer.
  216. if (NO_ERROR == dwRet)
  217. {
  218. // Note: on Win95, RegSetValueEx will always write the
  219. // full string out, including the null terminator. On NT,
  220. // it won't unless the write length was specified.
  221. // Hence, we have the following check.
  222. // Pad the buffer, in case the string didn't have a null
  223. // terminator when it was stored?
  224. if (REG_SZ == dwType)
  225. {
  226. // Yes
  227. if (pvData && cbSize < *pcbData)
  228. {
  229. LPSTR lpszData = pvData;
  230. lpszData[cbSize] = '\0';
  231. }
  232. }
  233. // Expand the string?
  234. else if (REG_EXPAND_SZ == dwType)
  235. {
  236. // Yes
  237. // Use a temporary buffer to expand
  238. if (pvData)
  239. {
  240. lpsz = (LPSTR)LocalAlloc(LPTR, *pcbData);
  241. if ( !lpsz )
  242. return ERROR_OUTOFMEMORY;
  243. cbSize = ExpandEnvironmentStringsA(pvData, lpsz, *pcbData);
  244. // NT screws up the cbSize returned...
  245. if (cbSize > 0)
  246. cbSize = lstrlenA(lpsz) + 1;
  247. if (cbSize > 0 && cbSize <= *pcbData)
  248. lstrcpynA(pvData, lpsz, *pcbData);
  249. else
  250. dwRet = GetLastError();
  251. }
  252. else
  253. {
  254. //
  255. // Find out the length of the expanded string
  256. // we have to call in and actually get the data to do this
  257. //
  258. CHAR szBuff[1];
  259. lpsz = (LPSTR)LocalAlloc(LPTR, cbSize);
  260. if (!lpsz)
  261. return ERROR_OUTOFMEMORY;
  262. dwRet = RegQueryValueExA(hkey, pszValue, lpReserved, NULL,
  263. (LPBYTE)lpsz, &cbSize);
  264. if (NO_ERROR == dwRet)
  265. {
  266. // dummy buffer required...
  267. DWORD cbExpand = ExpandEnvironmentStringsA(lpsz, szBuff, ARRAYSIZE(szBuff));
  268. cbSize = max(cbExpand, cbSize);
  269. }
  270. }
  271. LocalFree(lpsz);
  272. // Massage dwType so that callers always see REG_SZ
  273. dwType = REG_SZ;
  274. }
  275. }
  276. if (pdwType)
  277. *pdwType = dwType;
  278. if (pcbData)
  279. *pcbData = cbSize;
  280. return dwRet;
  281. }
  282. #ifdef UNICODE
  283. /*----------------------------------------------------------
  284. Purpose: Behaves just like RegQueryValueEx, except if the
  285. data type is REG_EXPAND_SZ, then this goes ahead
  286. and expands out the string. *pdwType will always
  287. be massaged to REG_SZ if this happens.
  288. Returns:
  289. Cond: --
  290. */
  291. STDAPI_(DWORD)
  292. SHQueryValueExW(
  293. IN HKEY hkey,
  294. IN LPCWSTR pwszValue,
  295. IN LPDWORD lpReserved,
  296. OUT LPDWORD pdwType,
  297. OUT LPVOID pvData,
  298. IN OUT LPDWORD pcbData)
  299. {
  300. DWORD dwRet;
  301. DWORD cbSize;
  302. DWORD dwType;
  303. LPWSTR lpsz;
  304. if ( !g_bRunOnNT )
  305. {
  306. CHAR szValue[MAX_PATH];
  307. LPSTR pszValue = NULL;
  308. DWORD dwOriginalSize = 0;
  309. if (pcbData)
  310. dwOriginalSize = *pcbData;
  311. if (pwszValue)
  312. {
  313. WideCharToMultiByte(CP_ACP, 0, pwszValue, -1, szValue, SIZECHARS(szValue), NULL, NULL);
  314. pszValue = szValue;
  315. }
  316. if (!pdwType)
  317. pdwType = &dwType;
  318. dwRet = SHQueryValueExA(hkey, pszValue, lpReserved, pdwType, pvData, pcbData);
  319. if (NO_ERROR == dwRet)
  320. dwRet = RegData_AtoW(pvData, dwOriginalSize, *pdwType, pcbData); // Thunk data from ANSI->UNICODE if needed.
  321. }
  322. else
  323. {
  324. // Running on NT
  325. // Trying to get back data
  326. if (pcbData)
  327. cbSize = *pcbData; // Size of output buffer
  328. dwRet = RegQueryValueExW(hkey, pwszValue, lpReserved, &dwType,
  329. pvData, &cbSize);
  330. // Normally, we'd be done with this. But do some extra work
  331. // if this is an expandable string (something that has system
  332. // variables in it), or if we need to pad the buffer.
  333. if (NO_ERROR == dwRet)
  334. {
  335. // Note: on Win95, RegSetValueEx will always write the
  336. // full string out, including the null terminator. On NT,
  337. // it won't unless the write length was specified.
  338. // Hence, we have the following check.
  339. // Pad the buffer, in case the string didn't have a null
  340. // terminator when it was stored?
  341. if (REG_SZ == dwType)
  342. {
  343. // Yes
  344. if (pvData && cbSize + sizeof(WCHAR) <= *pcbData)
  345. {
  346. LPWSTR lpszData = pvData;
  347. lpszData[cbSize / sizeof(WCHAR)] = '\0';
  348. }
  349. }
  350. // Expand the string?
  351. else if (REG_EXPAND_SZ == dwType)
  352. {
  353. if (pvData)
  354. {
  355. // Yes
  356. // Use a temporary buffer to expand
  357. lpsz = (LPWSTR)LocalAlloc(LPTR, *pcbData);
  358. if (!lpsz)
  359. return ERROR_OUTOFMEMORY;
  360. cbSize = CbFromCchW(ExpandEnvironmentStringsW(pvData, lpsz, *pcbData / sizeof(WCHAR)));
  361. if (cbSize > 0 && cbSize <= *pcbData)
  362. StrCpyNW(pvData, lpsz, *pcbData / sizeof(WCHAR));
  363. else
  364. dwRet = GetLastError();
  365. }
  366. else
  367. {
  368. //
  369. // Find out the length of the expanded string
  370. // we have to call in and actually get the data to do this
  371. //
  372. WCHAR szBuff[1];
  373. // Find out the length of the expanded string
  374. //
  375. lpsz = (LPWSTR)LocalAlloc(LPTR, cbSize);
  376. if (!lpsz)
  377. return ERROR_OUTOFMEMORY;
  378. dwRet = RegQueryValueExW(hkey, pwszValue, lpReserved, NULL,
  379. (LPBYTE)lpsz, &cbSize);
  380. if (NO_ERROR == dwRet)
  381. {
  382. DWORD cbExpand = CbFromCchW(ExpandEnvironmentStringsW(lpsz, szBuff,
  383. ARRAYSIZE(szBuff)));
  384. cbSize = max(cbExpand, cbSize);
  385. }
  386. }
  387. LocalFree(lpsz);
  388. // Massage dwType so that callers always see REG_SZ
  389. dwType = REG_SZ;
  390. }
  391. }
  392. if (pdwType)
  393. *pdwType = dwType;
  394. if (pcbData)
  395. *pcbData = cbSize;
  396. }
  397. return dwRet;
  398. }
  399. #endif //UNICODE
  400. /*
  401. * @doc INTERNAL
  402. *
  403. * @func int | SHAnsiToUnicodeNativeCP |
  404. *
  405. * Convert an ANSI string to a UNICODE string via the
  406. * specified Windows code page. If the source string is too large
  407. * for the destination buffer, then as many characters as
  408. * possible are copied.
  409. *
  410. * The resulting output string is always null-terminated.
  411. *
  412. * @parm UINT | uiCP |
  413. *
  414. * The code page in which to perform the conversion.
  415. * This must be a Windows code page.
  416. *
  417. * @parm LPCSTR | pszSrc |
  418. *
  419. * Source buffer containing ANSI string to be converted.
  420. *
  421. * @parm int | cchSrc |
  422. *
  423. * Source buffer length, including terminating null.
  424. *
  425. * @parm LPWSTR | pwszDst |
  426. *
  427. * Destination buffer to receive converted UNICODE string.
  428. *
  429. * @parm int | cwchBuf |
  430. *
  431. * Size of the destination buffer in <t WCHAR>s.
  432. *
  433. * @returns
  434. *
  435. * On success, the number of characters copied to the output
  436. * buffer is returned, including the terminating null.
  437. */
  438. int
  439. SHAnsiToUnicodeNativeCP(UINT uiCP,
  440. LPCSTR pszSrc, int cchSrc,
  441. LPWSTR pwszDst, int cwchBuf)
  442. {
  443. int cwchRc = 0; /* Assume failure */
  444. /*
  445. * Checks the caller should've made.
  446. */
  447. ASSERT(IS_VALID_STRING_PTRA(pszSrc, -1));
  448. ASSERT(cchSrc == lstrlenA(pszSrc) + 1);
  449. ASSERT(IS_VALID_WRITE_BUFFER(pwszDst, WCHAR, cwchBuf));
  450. ASSERT(pszSrc != NULL);
  451. ASSERT(uiCP != 1200 && uiCP != 65000 && uiCP != 50000 && uiCP != 65001);
  452. ASSERT(pwszDst);
  453. ASSERT(cwchBuf);
  454. cwchRc = MultiByteToWideChar(uiCP, 0, pszSrc, cchSrc, pwszDst, cwchBuf);
  455. if (cwchRc) {
  456. /*
  457. * The output buffer was big enough; no double-buffering
  458. * needed.
  459. */
  460. } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  461. /*
  462. * The output buffer wasn't big enough. Need to double-buffer.
  463. */
  464. int cwchNeeded = MultiByteToWideChar(uiCP, 0, pszSrc, cchSrc,
  465. NULL, 0);
  466. ASSERT(cwchRc == 0); /* In case we fail later */
  467. if (cwchNeeded) {
  468. LPWSTR pwsz = (LPWSTR)LocalAlloc(LMEM_FIXED,
  469. cwchNeeded * SIZEOF(WCHAR));
  470. if (pwsz) {
  471. cwchRc = MultiByteToWideChar(uiCP, 0, pszSrc, cchSrc,
  472. pwsz, cwchNeeded);
  473. if (cwchRc) {
  474. StrCpyNW(pwszDst, pwsz, cwchBuf);
  475. cwchRc = cwchBuf;
  476. }
  477. LocalFree(pwsz);
  478. }
  479. }
  480. } else {
  481. /* Possibly unsupported code page */
  482. ASSERT(!"Unexpected error in MultiByteToWideChar");
  483. }
  484. return cwchRc;
  485. }
  486. int
  487. SHAnsiToUnicodeCP_ACP(LPCSTR pszSrc, LPWSTR pwszDst, int cwchBuf)
  488. {
  489. int cwchRc = 0; /* Assume failure */
  490. ASSERT(IS_VALID_STRING_PTRA(pszSrc, -1));
  491. ASSERT(IS_VALID_WRITE_BUFFER(pwszDst, WCHAR, cwchBuf));
  492. /*
  493. * Sanity check - NULL source string is treated as a null string.
  494. */
  495. if (pszSrc == NULL) {
  496. pszSrc = "";
  497. }
  498. /*
  499. * Sanity check - Output buffer must be non-NULL and must be of
  500. * nonzero size.
  501. */
  502. if (pwszDst && cwchBuf) {
  503. int cchSrc;
  504. pwszDst[0] = 0; /* In case of error */
  505. cchSrc = lstrlenA(pszSrc) + 1;
  506. cwchRc = SHAnsiToUnicodeNativeCP(CP_ACP, pszSrc, cchSrc, pwszDst, cwchBuf);
  507. }
  508. return cwchRc;
  509. }
  510. /*
  511. * @doc EXTERNAL
  512. *
  513. * @func int | SHAnsiToUnicode |
  514. *
  515. * Convert an ANSI string to a UNICODE string via the
  516. * <c CP_ACP> code page. If the source string is too large
  517. * for the destination buffer, then as many characters as
  518. * possible are copied.
  519. *
  520. * The resulting output string is always null-terminated.
  521. *
  522. * @parm LPCSTR | pszSrc |
  523. *
  524. * Source buffer containing ANSI string to be converted.
  525. *
  526. * @parm LPWSTR | pwszDst |
  527. *
  528. * Destination buffer to receive converted UNICODE string.
  529. *
  530. * @parm int | cwchBuf |
  531. *
  532. * Size of the destination buffer in <t WCHAR>s.
  533. *
  534. * @returns
  535. *
  536. * On success, the number of characters copied to the output
  537. * buffer is returned, including the terminating null.
  538. *
  539. */
  540. int
  541. SHAnsiToUnicode(LPCSTR pszSrc, LPWSTR pwszDst, int cwchBuf)
  542. {
  543. return SHAnsiToUnicodeCP_ACP(pszSrc, pwszDst, cwchBuf);
  544. }
  545. // dupe a string using the task allocator for returing from a COM interface
  546. // These functions use SHAlloc, so they cannot go into shlwapi.
  547. STDAPI SHStrDupA(LPCSTR psz, WCHAR **ppwsz)
  548. {
  549. DWORD cch = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  550. *ppwsz = (WCHAR *)CoTaskMemAlloc((cch + 1) * SIZEOF(WCHAR));
  551. if (*ppwsz)
  552. {
  553. MultiByteToWideChar(CP_ACP, 0, psz, -1, *ppwsz, cch);
  554. return S_OK;
  555. }
  556. return E_OUTOFMEMORY;
  557. }
  558. // dupe a string using the task allocator for returing from a COM interface
  559. STDAPI SHStrDupW(LPCWSTR psz, WCHAR **ppwsz)
  560. {
  561. *ppwsz = (WCHAR *)CoTaskMemAlloc((lstrlenW(psz) + 1) * SIZEOF(WCHAR));
  562. if (*ppwsz)
  563. {
  564. StrCpyW(*ppwsz, psz);
  565. return S_OK;
  566. }
  567. return E_OUTOFMEMORY;
  568. }
  569. // Modifies:
  570. // szRoot
  571. //
  572. // Returns:
  573. // TRUE if a drive root was found
  574. // FALSE otherwise
  575. //
  576. STDAPI_(BOOL)
  577. PathStripToRoot(
  578. LPTSTR szRoot)
  579. {
  580. while(!PathIsRoot(szRoot))
  581. {
  582. if (!PathRemoveFileSpec(szRoot))
  583. {
  584. // If we didn't strip anything off,
  585. // must be current drive
  586. return(FALSE);
  587. }
  588. }
  589. return(TRUE);
  590. }
  591. //
  592. // SHStringFromGUIDA
  593. //
  594. // converts GUID into (...) form without leading identifier; returns
  595. // amount of data copied to lpsz if successful; 0 if buffer too small.
  596. //
  597. // An endian-dependant map of what bytes go where in the GUID
  598. // text representation.
  599. //
  600. // Do NOT use the TEXT() macro in GuidMap... they're intended to be bytes
  601. //
  602. static const BYTE c_rgbGuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
  603. 8, 9, '-', 10, 11, 12, 13, 14, 15 };
  604. static const CHAR c_szDigitsA[] = "0123456789ABCDEF";
  605. static const WCHAR c_szDigitsW[] = TEXTW("0123456789ABCDEF");
  606. STDAPI_(int)
  607. SHStringFromGUIDA(
  608. UNALIGNED REFGUID rguid,
  609. LPSTR psz,
  610. int cchMax)
  611. {
  612. int i;
  613. const BYTE * pBytes = (const BYTE *) rguid;
  614. if (cchMax < GUIDSTR_MAX)
  615. return 0;
  616. #ifdef BIG_ENDIAN
  617. // This is the slow, but portable version
  618. wnsprintf(psz, cchMax,"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  619. rguid->Data1, rguid->Data2, rguid->Data3,
  620. rguid->Data4[0], rguid->Data4[1],
  621. rguid->Data4[2], rguid->Data4[3],
  622. rguid->Data4[4], rguid->Data4[5],
  623. rguid->Data4[6], rguid->Data4[7]);
  624. #else
  625. // The following algorithm is faster than the wsprintf.
  626. *psz++ = '{';
  627. for (i = 0; i < SIZEOF(c_rgbGuidMap); i++)
  628. {
  629. if (c_rgbGuidMap[i] == '-') // don't TEXT() this line
  630. {
  631. *psz++ = '-';
  632. }
  633. else
  634. {
  635. // Convert a byte-value into a character representation
  636. *psz++ = c_szDigitsA[ (pBytes[c_rgbGuidMap[i]] & 0xF0) >> 4 ];
  637. *psz++ = c_szDigitsA[ (pBytes[c_rgbGuidMap[i]] & 0x0F) ];
  638. }
  639. }
  640. *psz++ = '}';
  641. *psz = '\0';
  642. #endif /* !BIG_ENDIAN */
  643. return GUIDSTR_MAX;
  644. }
  645. STDAPI_(int)
  646. SHStringFromGUIDW(
  647. UNALIGNED REFGUID rguid,
  648. LPWSTR psz,
  649. int cchMax)
  650. {
  651. int i;
  652. const BYTE * pBytes = (const BYTE *) rguid;
  653. if (cchMax < GUIDSTR_MAX)
  654. return 0;
  655. #ifdef BIG_ENDIAN
  656. // This is the slow, but portable version
  657. wnsprintfW(psz, cchMax, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  658. rguid->Data1, rguid->Data2, rguid->Data3,
  659. rguid->Data4[0], rguid->Data4[1],
  660. rguid->Data4[2], rguid->Data4[3],
  661. rguid->Data4[4], rguid->Data4[5],
  662. rguid->Data4[6], rguid->Data4[7]);
  663. #else
  664. // The following algorithm is faster than the wsprintf.
  665. *psz++ = TEXTW('{');
  666. for (i = 0; i < SIZEOF(c_rgbGuidMap); i++)
  667. {
  668. if (c_rgbGuidMap[i] == '-') // don't TEXT() this line
  669. {
  670. *psz++ = TEXTW('-');
  671. }
  672. else
  673. {
  674. // Convert a byte-value into a character representation
  675. *psz++ = c_szDigitsW[ (pBytes[c_rgbGuidMap[i]] & 0xF0) >> 4 ];
  676. *psz++ = c_szDigitsW[ (pBytes[c_rgbGuidMap[i]] & 0x0F) ];
  677. }
  678. }
  679. *psz++ = TEXTW('}');
  680. *psz = TEXTW('\0');
  681. #endif /* !BIG_ENDIAN */
  682. return GUIDSTR_MAX;
  683. }
  684. //
  685. // Why do we use the unsafe version?
  686. //
  687. // - Unsafe is much faster.
  688. //
  689. // - The safe version isn't safe after all and serves only to mask
  690. // existing bugs. The situation the safe version "saves" is if
  691. // two threads both try to atomicrelease the same object. This
  692. // means that at the same moment, both threads think the object
  693. // is alive. Change the timing slightly, and now one thread
  694. // atomicreleases the object before the other one, so the other
  695. // thread is now using an object after the first thread already
  696. // atomicreleased it. Bug.
  697. //
  698. STDAPI_(void) IUnknown_AtomicRelease(void **ppunk)
  699. {
  700. #if 1 // Unsafe
  701. if (ppunk && *ppunk) {
  702. IUnknown* punk = *(IUnknown**)ppunk;
  703. *ppunk = NULL;
  704. punk->lpVtbl->Release(punk);
  705. }
  706. #else // Safe
  707. if (ppunk) {
  708. IUnknown* punk = (IUnknown *)InterlockedExchangePointer(ppunk, NULL);
  709. if (punk) {
  710. punk->Release();
  711. }
  712. }
  713. #endif
  714. }
  715. #endif //DOWNLEVEL_PLATFORM