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.

1334 lines
33 KiB

  1. /*
  2. * comc.c - Shared routines.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "assoc.h"
  9. #pragma warning(disable:4001) /* "single line comment" warning */
  10. #include "filetype.h"
  11. #pragma warning(default:4001) /* "single line comment" warning */
  12. /* Global Constants
  13. *******************/
  14. #pragma data_seg(DATA_SEG_READ_ONLY)
  15. PUBLIC_DATA const char g_cszWhiteSpace[] = " \t";
  16. PUBLIC_DATA const char g_cszSlashes[] = "/\\";
  17. PUBLIC_DATA const char g_cszPathSeparators[] = ":/\\";
  18. PUBLIC_DATA const char g_cszEditFlags[] = "EditFlags";
  19. #pragma data_seg()
  20. /* Module Constants
  21. *******************/
  22. #pragma data_seg(DATA_SEG_READ_ONLY)
  23. PRIVATE_DATA CCHAR s_cszMIMETypeSubKeyFmt[] = "MIME\\Database\\Content Type\\%s";
  24. PRIVATE_DATA CCHAR s_cszDefaultVerbSubKeyFmt[] = "%s\\Shell";
  25. PRIVATE_DATA CCHAR s_cszShellOpenCmdSubKey[] = "Shell\\Open\\Command";
  26. PRIVATE_DATA CCHAR s_cszContentType[] = "Content Type";
  27. PRIVATE_DATA CCHAR s_cszExtension[] = "Extension";
  28. PRIVATE_DATA const char s_cszAppCmdLineFmt[] = " %s";
  29. PRIVATE_DATA const char s_cszQuotesAppCmdLineFmt[] = " \"%s\"";
  30. #pragma data_seg()
  31. /***************************** Private Functions *****************************/
  32. /*
  33. ** GetMIMETypeStringValue()
  34. **
  35. ** Retrieves the string for a registered MIME type's value.
  36. **
  37. ** Arguments:
  38. **
  39. ** Returns:
  40. **
  41. ** Side Effects: none
  42. */
  43. PRIVATE_CODE BOOL GetMIMETypeStringValue(PCSTR pcszMIMEType, PCSTR pcszValue,
  44. PSTR pszBuf, UINT ucBufLen)
  45. {
  46. BOOL bResult;
  47. DWORD dwValueType;
  48. DWORD dwcbLen = ucBufLen;
  49. /* GetMIMEValue() will verify parameters. */
  50. bResult = (GetMIMEValue(pcszMIMEType, pcszValue, &dwValueType,
  51. (PBYTE)pszBuf, &dwcbLen) &&
  52. dwValueType == REG_SZ);
  53. if (! bResult)
  54. {
  55. if (ucBufLen > 0)
  56. *pszBuf = '\0';
  57. }
  58. ASSERT(! ucBufLen ||
  59. IS_VALID_STRING_PTR(pszBuf, STR));
  60. return(bResult);
  61. }
  62. /****************************** Public Functions *****************************/
  63. PUBLIC_CODE BOOL DataCopy(PCBYTE pcbyteSrc, ULONG ulcbLen, PBYTE *ppbyteDest)
  64. {
  65. BOOL bResult;
  66. ASSERT(IS_VALID_READ_BUFFER_PTR(pcbyteSrc, CBYTE, ulcbLen));
  67. ASSERT(IS_VALID_WRITE_PTR(ppbyteDest, PBYTE));
  68. bResult = AllocateMemory(ulcbLen, ppbyteDest);
  69. if (bResult)
  70. CopyMemory(*ppbyteDest, pcbyteSrc, ulcbLen);
  71. else
  72. *ppbyteDest = NULL;
  73. ASSERT((bResult &&
  74. IS_VALID_READ_BUFFER_PTR(*ppbyteDest, BYTE, ulcbLen)) ||
  75. (! bResult &&
  76. EVAL(! *ppbyteDest)));
  77. return(bResult);
  78. }
  79. PUBLIC_CODE BOOL StringCopy(PCSTR pcszSrc, PSTR *ppszCopy)
  80. {
  81. BOOL bResult;
  82. ASSERT(IS_VALID_STRING_PTR(pcszSrc, CSTR));
  83. ASSERT(IS_VALID_WRITE_PTR(ppszCopy, PSTR));
  84. /* (+ 1) for null terminator. */
  85. bResult = DataCopy((PCBYTE)pcszSrc, lstrlen(pcszSrc) + 1, (PBYTE *)ppszCopy);
  86. ASSERT(! bResult ||
  87. IS_VALID_STRING_PTR(*ppszCopy, STR));
  88. return(bResult);
  89. }
  90. /*
  91. ** GetMIMETypeSubKey()
  92. **
  93. ** Generates the HKEY_CLASSES_ROOT subkey for a MIME type.
  94. **
  95. ** Arguments:
  96. **
  97. ** Returns:
  98. **
  99. ** Side Effects: none
  100. */
  101. PUBLIC_CODE BOOL GetMIMETypeSubKey(PCSTR pcszMIMEType,
  102. PSTR pszSubKeyBuf,
  103. UINT ucSubKeyBufLen)
  104. {
  105. BOOL bResult;
  106. bResult = ((UINT)lstrlen(s_cszMIMETypeSubKeyFmt) +
  107. (UINT)lstrlen(pcszMIMEType) < ucSubKeyBufLen);
  108. if (bResult)
  109. EVAL((UINT)wsprintf(pszSubKeyBuf, s_cszMIMETypeSubKeyFmt,
  110. pcszMIMEType) < ucSubKeyBufLen);
  111. else
  112. {
  113. if (ucSubKeyBufLen > 0)
  114. *pszSubKeyBuf = '\0';
  115. WARNING_OUT(("GetMIMETypeSubKey(): Given sub key buffer of length %u is too short to hold sub key for MIME type %s.",
  116. ucSubKeyBufLen,
  117. pcszMIMEType));
  118. }
  119. ASSERT(! ucSubKeyBufLen ||
  120. (IS_VALID_STRING_PTR(pszSubKeyBuf, STR) &&
  121. (UINT)lstrlen(pszSubKeyBuf) < ucSubKeyBufLen));
  122. ASSERT(bResult ||
  123. ! ucSubKeyBufLen ||
  124. ! *pszSubKeyBuf);
  125. return(bResult);
  126. }
  127. /*
  128. ** GetMIMEValue()
  129. **
  130. ** Retrieves the data for a value of a MIME type.
  131. **
  132. ** Arguments:
  133. **
  134. ** Returns:
  135. **
  136. ** Side Effects: none
  137. */
  138. PUBLIC_CODE BOOL GetMIMEValue(PCSTR pcszMIMEType, PCSTR pcszValue,
  139. PDWORD pdwValueType, PBYTE pbyteValueBuf,
  140. PDWORD pdwcbValueBufLen)
  141. {
  142. BOOL bResult;
  143. char szMIMETypeSubKey[MAX_PATH_LEN];
  144. ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR));
  145. ASSERT(! pcszValue ||
  146. IS_VALID_STRING_PTR(pcszValue, CSTR));
  147. ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD));
  148. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen));
  149. bResult = (GetMIMETypeSubKey(pcszMIMEType, szMIMETypeSubKey,
  150. sizeof(szMIMETypeSubKey)) &&
  151. GetRegKeyValue(HKEY_CLASSES_ROOT, szMIMETypeSubKey,
  152. pcszValue, pdwValueType, pbyteValueBuf,
  153. pdwcbValueBufLen) == ERROR_SUCCESS);
  154. return(bResult);
  155. }
  156. /*
  157. ** GetFileTypeValue()
  158. **
  159. ** Retrieves the data for a value of the file class associated with an
  160. ** extension.
  161. **
  162. ** Arguments:
  163. **
  164. ** Returns:
  165. **
  166. ** Side Effects: none
  167. */
  168. PUBLIC_CODE BOOL GetFileTypeValue(PCSTR pcszExtension, PCSTR pcszSubKey,
  169. PCSTR pcszValue, PDWORD pdwValueType,
  170. PBYTE pbyteValueBuf, PDWORD pdwcbValueBufLen)
  171. {
  172. BOOL bResult = FALSE;
  173. ASSERT(IsValidExtension(pcszExtension));
  174. ASSERT(! pcszSubKey ||
  175. IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  176. ASSERT(! pcszValue ||
  177. IS_VALID_STRING_PTR(pcszValue, CSTR));
  178. ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD));
  179. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen));
  180. if (EVAL(*pcszExtension))
  181. {
  182. char szSubKey[MAX_PATH_LEN];
  183. DWORD dwcbLen = sizeof(szSubKey);
  184. /* Get extension's file type. */
  185. if (GetDefaultRegKeyValue(HKEY_CLASSES_ROOT, pcszExtension, szSubKey,
  186. &dwcbLen) == ERROR_SUCCESS &&
  187. *szSubKey)
  188. {
  189. /* Any sub key to append? */
  190. if (pcszSubKey)
  191. {
  192. /* Yes. */
  193. /* (+ 1) for possible key separator. */
  194. bResult = EVAL(lstrlen(szSubKey) + 1 + lstrlen(pcszSubKey)
  195. < sizeof(szSubKey));
  196. if (bResult)
  197. {
  198. CatPath(szSubKey, pcszSubKey);
  199. ASSERT(lstrlen(szSubKey) < sizeof(szSubKey));
  200. }
  201. }
  202. else
  203. /* No. */
  204. bResult = TRUE;
  205. if (bResult)
  206. /* Get file type's value string. */
  207. bResult = (GetRegKeyValue(HKEY_CLASSES_ROOT, szSubKey, pcszValue,
  208. pdwValueType, pbyteValueBuf,
  209. pdwcbValueBufLen) == ERROR_SUCCESS);
  210. }
  211. else
  212. TRACE_OUT(("GetFileTypeValue(): No file type registered for extension %s.",
  213. pcszExtension));
  214. }
  215. else
  216. WARNING_OUT(("GetFileTypeValue(): No extension given."));
  217. return(bResult);
  218. }
  219. /*
  220. ** GetMIMEFileTypeValue()
  221. **
  222. ** Retrieves the data for a value of the file class associated with a MIME
  223. ** type.
  224. **
  225. ** Arguments:
  226. **
  227. ** Returns:
  228. **
  229. ** Side Effects: none
  230. */
  231. PUBLIC_CODE BOOL GetMIMEFileTypeValue(PCSTR pcszMIMEType, PCSTR pcszSubKey,
  232. PCSTR pcszValue, PDWORD pdwValueType,
  233. PBYTE pbyteValueBuf,
  234. PDWORD pdwcbValueBufLen)
  235. {
  236. BOOL bResult;
  237. char szExtension[MAX_PATH_LEN];
  238. ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR));
  239. ASSERT(! pcszSubKey ||
  240. IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  241. ASSERT(! pcszValue ||
  242. IS_VALID_STRING_PTR(pcszValue, CSTR));
  243. ASSERT(IS_VALID_WRITE_PTR(pdwValueType, DWORD));
  244. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyteValueBuf, BYTE, *pdwcbValueBufLen));
  245. /* Get file name extension associated with MIME type. */
  246. if (MIME_GetExtension(pcszMIMEType, szExtension, sizeof(szExtension)))
  247. bResult = GetFileTypeValue(szExtension, pcszSubKey, pcszValue, pdwValueType,
  248. pbyteValueBuf, pdwcbValueBufLen);
  249. else
  250. {
  251. bResult = FALSE;
  252. TRACE_OUT(("GetMIMEFileTypeValue(): No extension registered for MIME type %s.",
  253. pcszMIMEType));
  254. }
  255. return(bResult);
  256. }
  257. /*
  258. ** MIME_IsExternalHandlerRegistered()
  259. **
  260. ** Determines whether or not an external handler is registered for a MIME type.
  261. **
  262. ** Arguments:
  263. **
  264. ** Returns:
  265. **
  266. ** Side Effects: none
  267. */
  268. PUBLIC_CODE BOOL MIME_IsExternalHandlerRegistered(PCSTR pcszMIMEType)
  269. {
  270. BOOL bResult;
  271. DWORD dwValueType;
  272. char szOpenCmd[MAX_PATH_LEN];
  273. DWORD dwcbOpenCmdLen = sizeof(szOpenCmd);
  274. /* GetMIMEFileTypeValue() will verify parameters. */
  275. /* Look up the open command of the MIME type's associated file type. */
  276. bResult = (GetMIMEFileTypeValue(pcszMIMEType, s_cszShellOpenCmdSubKey,
  277. NULL, &dwValueType, (PBYTE)szOpenCmd,
  278. &dwcbOpenCmdLen) &&
  279. dwValueType == REG_SZ);
  280. TRACE_OUT(("MIME_IsExternalHandlerRegistered(): %s external handler is registered for MIME type %s.",
  281. bResult ? "An" : "No",
  282. pcszMIMEType));
  283. return(bResult);
  284. }
  285. /*
  286. ** MIME_GetExtension()
  287. **
  288. ** Determines the file name extension to be used when writing a file of a MIME
  289. ** type to the file system.
  290. **
  291. ** Arguments:
  292. **
  293. ** Returns:
  294. **
  295. ** Side Effects: none
  296. */
  297. PUBLIC_CODE BOOL MIME_GetExtension(PCSTR pcszMIMEType, PSTR pszExtensionBuf,
  298. UINT ucExtensionBufLen)
  299. {
  300. BOOL bResult = FALSE;
  301. ASSERT(IS_VALID_STRING_PTR(pcszMIMEType, CSTR));
  302. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszExtensionBuf, STR, ucExtensionBufLen));
  303. if (EVAL(ucExtensionBufLen > 2))
  304. {
  305. /* Leave room for possible leading period. */
  306. if (GetMIMETypeStringValue(pcszMIMEType, s_cszExtension,
  307. pszExtensionBuf + 1, ucExtensionBufLen - 1))
  308. {
  309. if (pszExtensionBuf[1])
  310. {
  311. /* Prepend period if necessary. */
  312. if (pszExtensionBuf[1] == PERIOD)
  313. /* (+ 1) for null terminator. */
  314. MoveMemory(pszExtensionBuf, pszExtensionBuf + 1,
  315. lstrlen(pszExtensionBuf + 1) + 1);
  316. else
  317. pszExtensionBuf[0] = PERIOD;
  318. bResult = TRUE;
  319. }
  320. }
  321. }
  322. if (! bResult)
  323. {
  324. if (ucExtensionBufLen > 0)
  325. *pszExtensionBuf = '\0';
  326. }
  327. if (bResult)
  328. TRACE_OUT(("MIME_GetExtension(): Extension %s registered as default extension for MIME type %s.",
  329. pszExtensionBuf,
  330. pcszMIMEType));
  331. else
  332. TRACE_OUT(("MIME_GetExtension(): No default extension registered for MIME type %s.",
  333. pcszMIMEType));
  334. ASSERT((bResult &&
  335. IsValidExtension(pszExtensionBuf)) ||
  336. (! bResult &&
  337. (! ucExtensionBufLen ||
  338. ! *pszExtensionBuf)));
  339. ASSERT(! ucExtensionBufLen ||
  340. (UINT)lstrlen(pszExtensionBuf) < ucExtensionBufLen);
  341. return(bResult);
  342. }
  343. /*
  344. ** MIME_GetMIMETypeFromExtension()
  345. **
  346. ** Determines the MIME type associated with a file extension.
  347. **
  348. ** Arguments:
  349. **
  350. ** Returns:
  351. **
  352. ** Side Effects: none
  353. */
  354. PUBLIC_CODE BOOL MIME_GetMIMETypeFromExtension(PCSTR pcszPath,
  355. PSTR pszMIMETypeBuf,
  356. UINT ucMIMETypeBufLen)
  357. {
  358. BOOL bResult;
  359. PCSTR pcszExtension;
  360. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  361. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszMIMETypeBuf, STR, ucMIMETypeBufLen));
  362. pcszExtension = ExtractExtension(pcszPath);
  363. if (*pcszExtension)
  364. {
  365. DWORD dwcLen = ucMIMETypeBufLen;
  366. bResult = (GetRegKeyStringValue(HKEY_CLASSES_ROOT, pcszExtension,
  367. s_cszContentType, pszMIMETypeBuf,
  368. &dwcLen) == ERROR_SUCCESS);
  369. if (bResult)
  370. TRACE_OUT(("MIME_GetMIMETypeFromExtension(): MIME type for extension %s is %s.",
  371. pcszExtension,
  372. pszMIMETypeBuf));
  373. else
  374. TRACE_OUT(("MIME_GetMIMETypeFromExtension(): No MIME type registered for extension %s.",
  375. pcszExtension));
  376. }
  377. else
  378. {
  379. bResult = FALSE;
  380. TRACE_OUT(("MIME_GetMIMETypeFromExtension(): No extension in path %s.",
  381. pcszPath));
  382. }
  383. if (! bResult)
  384. {
  385. if (ucMIMETypeBufLen > 0)
  386. *pszMIMETypeBuf = '\0';
  387. }
  388. ASSERT(! ucMIMETypeBufLen ||
  389. (IS_VALID_STRING_PTR(pszMIMETypeBuf, STR) &&
  390. (UINT)lstrlen(pszMIMETypeBuf) < ucMIMETypeBufLen));
  391. ASSERT(bResult ||
  392. ! ucMIMETypeBufLen ||
  393. ! *pszMIMETypeBuf);
  394. return(bResult);
  395. }
  396. /*
  397. ** CatPath()
  398. **
  399. ** Appends a filename to a path string.
  400. **
  401. ** Arguments: pszPath - path string that file name is to be appended to
  402. ** pcszSubPath - path to append
  403. **
  404. ** Returns: void
  405. **
  406. ** Side Effects: none
  407. **
  408. ** N.b., truncates path to MAX_PATH_LEN characters in length.
  409. **
  410. ** Examples:
  411. **
  412. ** input path input file name output path
  413. ** ---------- --------------- -----------
  414. ** c:\ foo c:\foo
  415. ** c: foo c:foo
  416. ** c:\foo\bar\ goo c:\foo\bar\goo
  417. ** c:\foo\bar\ \goo c:\foo\bar\goo
  418. ** c:\foo\bar\ goo\shoe c:\foo\bar\goo\shoe
  419. ** c:\foo\bar\ \goo\shoe\ c:\foo\bar\goo\shoe\
  420. ** foo\bar\ goo foo\bar\goo
  421. ** <empty string> <empty string> <empty string>
  422. ** <empty string> foo foo
  423. ** foo <empty string> foo
  424. ** fred bird fred\bird
  425. */
  426. PUBLIC_CODE void CatPath(PSTR pszPath, PCSTR pcszSubPath)
  427. {
  428. PSTR pcsz;
  429. PSTR pcszLast;
  430. ASSERT(IS_VALID_STRING_PTR(pszPath, STR));
  431. ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
  432. /* (+ 1) for possible separator. */
  433. /* (+ 1) for null terminator. */
  434. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPath, STR, lstrlen(pszPath) + 1 + lstrlen(pcszSubPath) + 1));
  435. /* Find last character in path string. */
  436. for (pcsz = pcszLast = pszPath; *pcsz; pcsz = CharNext(pcsz))
  437. pcszLast = pcsz;
  438. if (IS_SLASH(*pcszLast) && IS_SLASH(*pcszSubPath))
  439. pcszSubPath++;
  440. else if (! IS_SLASH(*pcszLast) && ! IS_SLASH(*pcszSubPath))
  441. {
  442. if (*pcszLast && *pcszLast != COLON && *pcszSubPath)
  443. *pcsz++ = '\\';
  444. }
  445. lstrcpy(pcsz, pcszSubPath);
  446. ASSERT(IS_VALID_STRING_PTR(pszPath, STR));
  447. return;
  448. }
  449. /*
  450. ** MyLStrCpyN()
  451. **
  452. ** Like lstrcpy(), but the copy is limited to ucb bytes. The destination
  453. ** string is always null-terminated.
  454. **
  455. ** Arguments: pszDest - pointer to destination buffer
  456. ** pcszSrc - pointer to source string
  457. ** ncb - maximum number of bytes to copy, including null
  458. ** terminator
  459. **
  460. ** Returns: void
  461. **
  462. ** Side Effects: none
  463. **
  464. ** N.b., this function behaves quite differently than strncpy()! It does not
  465. ** pad out the destination buffer with null characters, and it always null
  466. ** terminates the destination string.
  467. */
  468. PUBLIC_CODE void MyLStrCpyN(PSTR pszDest, PCSTR pcszSrc, int ncb)
  469. {
  470. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDest, STR, ncb));
  471. ASSERT(IS_VALID_STRING_PTR(pcszSrc, CSTR));
  472. ASSERT(ncb > 0);
  473. while (ncb > 1)
  474. {
  475. ncb--;
  476. *pszDest = *pcszSrc;
  477. if (*pcszSrc)
  478. {
  479. pszDest++;
  480. pcszSrc++;
  481. }
  482. else
  483. break;
  484. }
  485. if (ncb == 1)
  486. *pszDest = '\0';
  487. ASSERT(IS_VALID_STRING_PTR(pszDest, STR));
  488. ASSERT(lstrlen(pszDest) < ncb);
  489. ASSERT(lstrlen(pszDest) <= lstrlen(pcszSrc));
  490. return;
  491. }
  492. PUBLIC_CODE COMPARISONRESULT MapIntToComparisonResult(int nResult)
  493. {
  494. COMPARISONRESULT cr;
  495. /* Any integer is valid input. */
  496. if (nResult < 0)
  497. cr = CR_FIRST_SMALLER;
  498. else if (nResult > 0)
  499. cr = CR_FIRST_LARGER;
  500. else
  501. cr = CR_EQUAL;
  502. return(cr);
  503. }
  504. /*
  505. ** TrimWhiteSpace()
  506. **
  507. ** Trims leading and trailing white space from a string in place.
  508. **
  509. ** Arguments:
  510. **
  511. ** Returns:
  512. **
  513. ** Side Effects: none
  514. */
  515. PUBLIC_CODE void TrimWhiteSpace(PSTR pszTrimMe)
  516. {
  517. ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR));
  518. TrimString(pszTrimMe, g_cszWhiteSpace);
  519. /* TrimString() validates pszTrimMe on output. */
  520. return;
  521. }
  522. /*
  523. ** TrimSlashes()
  524. **
  525. ** Trims leading and trailing slashes from a string in place.
  526. **
  527. ** Arguments:
  528. **
  529. ** Returns:
  530. **
  531. ** Side Effects: none
  532. */
  533. PUBLIC_CODE void TrimSlashes(PSTR pszTrimMe)
  534. {
  535. ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR));
  536. TrimString(pszTrimMe, g_cszSlashes);
  537. /* TrimString() validates pszTrimMe on output. */
  538. return;
  539. }
  540. PUBLIC_CODE void TrimString(PSTR pszTrimMe, PCSTR pszTrimChars)
  541. {
  542. PSTR psz;
  543. PSTR pszStartMeat;
  544. ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR));
  545. ASSERT(IS_VALID_STRING_PTR(pszTrimChars, CSTR));
  546. if ( !pszTrimMe )
  547. return;
  548. /* Trim leading characters. */
  549. psz = pszTrimMe;
  550. while (*psz && strchr(pszTrimChars, *psz))
  551. psz = CharNext(psz);
  552. pszStartMeat = psz;
  553. /* Trim trailing characters. */
  554. if (*psz)
  555. {
  556. psz += lstrlen(psz);
  557. psz = CharPrev(pszStartMeat, psz);
  558. if (psz > pszStartMeat)
  559. {
  560. while (strchr(pszTrimChars, *psz))
  561. psz = CharPrev(pszStartMeat, psz);
  562. psz = CharNext(psz);
  563. ASSERT(psz > pszStartMeat);
  564. *psz = '\0';
  565. }
  566. }
  567. /* Relocate stripped string. */
  568. if (pszStartMeat > pszTrimMe)
  569. /* (+ 1) for null terminator. */
  570. MoveMemory(pszTrimMe, pszStartMeat, lstrlen(pszStartMeat) + 1);
  571. else
  572. ASSERT(pszStartMeat == pszTrimMe);
  573. ASSERT(IS_VALID_STRING_PTR(pszTrimMe, STR));
  574. return;
  575. }
  576. /*
  577. ** ExtractFileName()
  578. **
  579. ** Extracts the file name from a path name.
  580. **
  581. ** Arguments: pcszPathName - path string from which to extract file name
  582. **
  583. ** Returns: Pointer to file name in path string.
  584. **
  585. ** Side Effects: none
  586. */
  587. PUBLIC_CODE PCSTR ExtractFileName(PCSTR pcszPathName)
  588. {
  589. PCSTR pcszLastComponent;
  590. PCSTR pcsz;
  591. ASSERT(IS_VALID_STRING_PTR(pcszPathName, CSTR));
  592. for (pcszLastComponent = pcsz = pcszPathName;
  593. *pcsz;
  594. pcsz = CharNext(pcsz))
  595. {
  596. if (IS_SLASH(*pcsz) || *pcsz == COLON)
  597. pcszLastComponent = CharNext(pcsz);
  598. }
  599. ASSERT(IsValidPath(pcszLastComponent));
  600. return(pcszLastComponent);
  601. }
  602. /*
  603. ** ExtractExtension()
  604. **
  605. ** Extracts the extension from a name.
  606. **
  607. ** Arguments: pcszName - name whose extension is to be extracted
  608. **
  609. ** Returns: If the name contains an extension, a pointer to the period at
  610. ** the beginning of the extension is returned. If the name has
  611. ** no extension, a pointer to the name's null terminator is
  612. ** returned.
  613. **
  614. ** Side Effects: none
  615. */
  616. PUBLIC_CODE PCSTR ExtractExtension(PCSTR pcszName)
  617. {
  618. PCSTR pcszLastPeriod;
  619. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  620. /* Make sure we have an isolated file name. */
  621. pcszName = ExtractFileName(pcszName);
  622. pcszLastPeriod = NULL;
  623. while (*pcszName)
  624. {
  625. if (*pcszName == PERIOD)
  626. pcszLastPeriod = pcszName;
  627. pcszName = CharNext(pcszName);
  628. }
  629. if (! pcszLastPeriod)
  630. {
  631. /* Point at null terminator. */
  632. pcszLastPeriod = pcszName;
  633. ASSERT(! *pcszLastPeriod);
  634. }
  635. else
  636. /* Point at period at beginning of extension. */
  637. ASSERT(*pcszLastPeriod == PERIOD);
  638. ASSERT(! *pcszLastPeriod ||
  639. IsValidExtension(pcszLastPeriod));
  640. return(pcszLastPeriod);
  641. }
  642. /*
  643. ** SetRegKeyValue()
  644. **
  645. ** Sets the data associated with a registry key's value.
  646. **
  647. ** Arguments:
  648. **
  649. ** Returns:
  650. **
  651. ** Side Effects: none
  652. */
  653. PUBLIC_CODE LONG SetRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey,
  654. PCSTR pcszValue, DWORD dwType,
  655. PCBYTE pcbyte, DWORD dwcb)
  656. {
  657. LONG lResult;
  658. HKEY hkeySubKey;
  659. ASSERT(IS_VALID_HANDLE(hkeyParent, KEY));
  660. ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  661. ASSERT(IsValidRegistryValueType(dwType));
  662. ASSERT(! pcszValue ||
  663. IS_VALID_STRING_PTR(pcszValue, CSTR));
  664. ASSERT(IS_VALID_READ_BUFFER_PTR(pcbyte, CBYTE, dwcb));
  665. lResult = RegCreateKeyEx(hkeyParent, pcszSubKey, 0, NULL, 0, KEY_SET_VALUE,
  666. NULL, &hkeySubKey, NULL);
  667. if (lResult == ERROR_SUCCESS)
  668. {
  669. LONG lResultClose;
  670. lResult = RegSetValueEx(hkeySubKey, pcszValue, 0, dwType, pcbyte, dwcb);
  671. lResultClose = RegCloseKey(hkeySubKey);
  672. if (lResult == ERROR_SUCCESS)
  673. lResult = lResultClose;
  674. }
  675. return(lResult);
  676. }
  677. /*
  678. ** GetRegKeyValue()
  679. **
  680. ** Retrieves the data from a registry key's value.
  681. **
  682. ** Arguments:
  683. **
  684. ** Returns:
  685. **
  686. ** Side Effects: none
  687. */
  688. PUBLIC_CODE LONG GetRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey,
  689. PCSTR pcszValue, PDWORD pdwValueType,
  690. PBYTE pbyteBuf, PDWORD pdwcbBufLen)
  691. {
  692. LONG lResult;
  693. HKEY hkeySubKey;
  694. ASSERT(IS_VALID_HANDLE(hkeyParent, KEY));
  695. ASSERT(! pcszSubKey ||
  696. IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  697. ASSERT(! pcszValue ||
  698. IS_VALID_STRING_PTR(pcszValue, CSTR));
  699. ASSERT(! pdwValueType ||
  700. IS_VALID_WRITE_PTR(pdwValueType, DWORD));
  701. ASSERT(! pbyteBuf ||
  702. IS_VALID_WRITE_BUFFER_PTR(pbyteBuf, BYTE, *pdwcbBufLen));
  703. lResult = RegOpenKeyEx(hkeyParent, pcszSubKey, 0, KEY_QUERY_VALUE,
  704. &hkeySubKey);
  705. if (lResult == ERROR_SUCCESS)
  706. {
  707. LONG lResultClose;
  708. lResult = RegQueryValueEx(hkeySubKey, pcszValue, NULL, pdwValueType,
  709. pbyteBuf, pdwcbBufLen);
  710. lResultClose = RegCloseKey(hkeySubKey);
  711. if (lResult == ERROR_SUCCESS)
  712. lResult = lResultClose;
  713. }
  714. return(lResult);
  715. }
  716. /*
  717. ** GetRegKeyStringValue()
  718. **
  719. ** Retrieves the data from a registry key's string value.
  720. **
  721. ** Arguments:
  722. **
  723. ** Returns:
  724. **
  725. ** Side Effects: none
  726. */
  727. PUBLIC_CODE LONG GetRegKeyStringValue(HKEY hkeyParent, PCSTR pcszSubKey,
  728. PCSTR pcszValue, PSTR pszBuf,
  729. PDWORD pdwcbBufLen)
  730. {
  731. LONG lResult;
  732. DWORD dwValueType;
  733. /* GetRegKeyValue() will verify the parameters. */
  734. lResult = GetRegKeyValue(hkeyParent, pcszSubKey, pcszValue, &dwValueType,
  735. (PBYTE)pszBuf, pdwcbBufLen);
  736. if (lResult == ERROR_SUCCESS &&
  737. dwValueType != REG_SZ)
  738. lResult = ERROR_CANTREAD;
  739. return(lResult);
  740. }
  741. /*
  742. ** GetDefaultRegKeyValue()
  743. **
  744. ** Retrieves the data from a registry key's default string value.
  745. **
  746. ** Arguments:
  747. **
  748. ** Returns:
  749. **
  750. ** Side Effects: none
  751. */
  752. PUBLIC_CODE LONG GetDefaultRegKeyValue(HKEY hkeyParent, PCSTR pcszSubKey,
  753. PSTR pszBuf, PDWORD pdwcbBufLen)
  754. {
  755. /* GetRegKeyStringValue() will verify the parameters. */
  756. return(GetRegKeyStringValue(hkeyParent, pcszSubKey, NULL, pszBuf,
  757. pdwcbBufLen));
  758. }
  759. /*
  760. ** FullyQualifyPath()
  761. **
  762. ** Fully qualifies a path.
  763. **
  764. ** Arguments:
  765. **
  766. ** Returns: S_OK
  767. **
  768. ** E_FILE_NOT_FOUND
  769. **
  770. ** Side Effects: none
  771. */
  772. PUBLIC_CODE HRESULT FullyQualifyPath(PCSTR pcszPath,
  773. PSTR pszFullyQualifiedPath,
  774. UINT ucFullyQualifiedPathBufLen)
  775. {
  776. HRESULT hr = E_FILE_NOT_FOUND;
  777. PSTR pszFileName;
  778. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  779. /* Any path separators? */
  780. if (! strpbrk(pcszPath, g_cszPathSeparators))
  781. {
  782. /* No. Search for file. */
  783. TRACE_OUT(("FullyQualifyPath(): Searching PATH for %s.",
  784. pcszPath));
  785. if (SearchPath(NULL, pcszPath, NULL, ucFullyQualifiedPathBufLen,
  786. pszFullyQualifiedPath, &pszFileName) > 0)
  787. hr = S_OK;
  788. else
  789. TRACE_OUT(("FullyQualifyPath(): %s not found on PATH.",
  790. pcszPath));
  791. }
  792. if (hr != S_OK &&
  793. GetFullPathName(pcszPath, ucFullyQualifiedPathBufLen,
  794. pszFullyQualifiedPath, &pszFileName) > 0)
  795. hr = S_OK;
  796. if (hr == S_OK)
  797. TRACE_OUT(("FullyQualifyPath(): %s qualified as %s.",
  798. pcszPath,
  799. pszFullyQualifiedPath));
  800. else
  801. {
  802. if (ucFullyQualifiedPathBufLen > 0)
  803. pszFullyQualifiedPath = '\0';
  804. WARNING_OUT(("FullyQualifyPath(): Failed to qualify %s.",
  805. pcszPath));
  806. }
  807. ASSERT((hr == S_OK &&
  808. EVAL(IsFullPath(pszFullyQualifiedPath))) ||
  809. (hr == E_FILE_NOT_FOUND &&
  810. (! ucFullyQualifiedPathBufLen ||
  811. ! *pszFullyQualifiedPath)));
  812. return(hr);
  813. }
  814. /*
  815. ** MyExecute()
  816. **
  817. ** Calls CreateProcess() politely.
  818. **
  819. ** Arguments:
  820. **
  821. ** Returns: S_OK
  822. **
  823. ** E_FAIL
  824. ** E_FILE_NOT_FOUND
  825. ** E_OUTOFMEMORY
  826. **
  827. ** Side Effects: none
  828. */
  829. PUBLIC_CODE HRESULT MyExecute(PCSTR pcszApp, PCSTR pcszArgs, DWORD dwInFlags)
  830. {
  831. HRESULT hr;
  832. char szFullApp[MAX_PATH_LEN];
  833. ASSERT(IS_VALID_STRING_PTR(pcszApp, CSTR));
  834. ASSERT(IS_VALID_STRING_PTR(pcszArgs, CSTR));
  835. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_ME_IN_FLAGS));
  836. hr = FullyQualifyPath(pcszApp, szFullApp, sizeof(szFullApp));
  837. if (hr == S_OK)
  838. {
  839. DWORD dwcbCmdLineLen;
  840. PSTR pszCmdLine;
  841. /* (+ 1) for null terminator. */
  842. dwcbCmdLineLen = max(sizeof(s_cszAppCmdLineFmt),
  843. sizeof(s_cszQuotesAppCmdLineFmt)) +
  844. + lstrlen(pcszArgs) + 1;
  845. if (AllocateMemory(dwcbCmdLineLen * sizeof(*pszCmdLine), &pszCmdLine))
  846. {
  847. PCSTR pcszFmt;
  848. STARTUPINFO si;
  849. PROCESS_INFORMATION pi;
  850. /* Execute URL via one-shot app. */
  851. pcszFmt = (IS_FLAG_SET(dwInFlags, ME_IFL_QUOTE_ARGS) &&
  852. strpbrk(pcszArgs, g_cszWhiteSpace) != NULL)
  853. ? s_cszQuotesAppCmdLineFmt : s_cszAppCmdLineFmt;
  854. EVAL((DWORD)wsprintf(pszCmdLine, pcszFmt, pcszArgs)
  855. < dwcbCmdLineLen);
  856. ZeroMemory(&si, sizeof(si));
  857. si.cb = sizeof(si);
  858. /* Specify command line exactly as given to app. */
  859. if (CreateProcess(szFullApp, pszCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
  860. &si, &pi))
  861. {
  862. CloseHandle(pi.hProcess);
  863. CloseHandle(pi.hThread);
  864. hr = S_OK;
  865. TRACE_OUT(("MyExecute(): CreateProcess() \"%s %s\" succeeded.",
  866. szFullApp, pszCmdLine));
  867. }
  868. else
  869. {
  870. hr = E_FAIL;
  871. WARNING_OUT(("MyExecute(): CreateProcess() \"%s %s\" failed.",
  872. szFullApp, pszCmdLine));
  873. }
  874. FreeMemory(pszCmdLine);
  875. pszCmdLine = NULL;
  876. }
  877. else
  878. hr = E_OUTOFMEMORY;
  879. }
  880. else
  881. WARNING_OUT(("MyExecute(): Unable to find app %s.",
  882. pcszApp));
  883. return(hr);
  884. }
  885. PUBLIC_CODE BOOL GetClassDefaultVerb(PCSTR pcszClass, PSTR pszDefaultVerbBuf,
  886. UINT ucDefaultVerbBufLen)
  887. {
  888. BOOL bResult;
  889. char szDefaultVerbSubKey[MAX_PATH_LEN];
  890. ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR));
  891. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDefaultVerbBuf, STR, ucDefaultVerbBufLen));
  892. ASSERT(lstrlen(pcszClass) > 0);
  893. if (sizeof(s_cszDefaultVerbSubKeyFmt) + lstrlen(pcszClass)
  894. < sizeof(szDefaultVerbSubKey))
  895. {
  896. DWORD dwValueType;
  897. DWORD dwcbBufLen = ucDefaultVerbBufLen;
  898. EVAL(wsprintf(szDefaultVerbSubKey, s_cszDefaultVerbSubKeyFmt,
  899. pcszClass) < sizeof(szDefaultVerbSubKey));
  900. bResult = (GetRegKeyValue(HKEY_CLASSES_ROOT, szDefaultVerbSubKey, NULL,
  901. &dwValueType, (PBYTE)pszDefaultVerbBuf,
  902. &dwcbBufLen) == ERROR_SUCCESS &&
  903. dwValueType == REG_SZ &&
  904. *pszDefaultVerbBuf);
  905. }
  906. else
  907. bResult = FALSE;
  908. if (! bResult)
  909. {
  910. if (ucDefaultVerbBufLen > 0)
  911. *pszDefaultVerbBuf = '\0';
  912. }
  913. if (bResult)
  914. TRACE_OUT(("GetClassDefaultVerb(): Default verb for %s class is %s.",
  915. pcszClass,
  916. pszDefaultVerbBuf));
  917. else
  918. TRACE_OUT(("GetClassDefaultVerb(): No default verb for %s class.",
  919. pcszClass));
  920. ASSERT(! ucDefaultVerbBufLen ||
  921. (IS_VALID_STRING_PTR(pszDefaultVerbBuf, STR) &&
  922. EVAL((UINT)lstrlen(pszDefaultVerbBuf) < ucDefaultVerbBufLen)));
  923. ASSERT(bResult ||
  924. ! ucDefaultVerbBufLen ||
  925. ! *pszDefaultVerbBuf);
  926. return(bResult);
  927. }
  928. /*
  929. * APPCOMPAT: The need for this function should be obviated by a ShellExecuteEx()
  930. * flag indicating that the default verb, rather than the open verb, should be
  931. * executed. This is broken for folders, for compound document files, for
  932. * files whose extensions are registered without a file class, for files whose
  933. * extensions are not unregistered, etc.
  934. */
  935. PUBLIC_CODE BOOL GetPathDefaultVerb(PCSTR pcszPath, PSTR pszDefaultVerbBuf,
  936. UINT ucDefaultVerbBufLen)
  937. {
  938. BOOL bResult = FALSE;
  939. PCSTR pcszExtension;
  940. char szClass[MAX_PATH_LEN];
  941. DWORD dwcbLen = ucDefaultVerbBufLen;
  942. ASSERT(IsValidPath(pcszPath));
  943. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszDefaultVerbBuf, STR, ucDefaultVerbBufLen));
  944. pcszExtension = ExtractExtension(pcszPath);
  945. bResult = (*pcszExtension &&
  946. GetDefaultRegKeyValue(HKEY_CLASSES_ROOT, pcszExtension,
  947. szClass, &dwcbLen) == ERROR_SUCCESS &&
  948. *szClass &&
  949. GetClassDefaultVerb(szClass, pszDefaultVerbBuf,
  950. ucDefaultVerbBufLen));
  951. if (! bResult)
  952. {
  953. if (ucDefaultVerbBufLen > 0)
  954. *pszDefaultVerbBuf = '\0';
  955. }
  956. ASSERT(! ucDefaultVerbBufLen ||
  957. (IS_VALID_STRING_PTR(pszDefaultVerbBuf, STR) &&
  958. EVAL((UINT)lstrlen(pszDefaultVerbBuf) < ucDefaultVerbBufLen)));
  959. ASSERT(bResult ||
  960. ! ucDefaultVerbBufLen ||
  961. ! *pszDefaultVerbBuf);
  962. return(bResult);
  963. }
  964. /*
  965. ** ClassIsSafeToOpen()
  966. **
  967. ** Determines whether or not a file class is known safe to open.
  968. **
  969. ** Arguments:
  970. **
  971. ** Returns:
  972. **
  973. ** Side Effects: none
  974. */
  975. PUBLIC_CODE BOOL ClassIsSafeToOpen(PCSTR pcszClass)
  976. {
  977. BOOL bSafe;
  978. DWORD dwValueType;
  979. DWORD dwEditFlags;
  980. DWORD dwcbLen = sizeof(dwEditFlags);
  981. ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR));
  982. bSafe = (GetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags,
  983. &dwValueType, (PBYTE)&dwEditFlags, &dwcbLen) == ERROR_SUCCESS &&
  984. (dwValueType == REG_BINARY ||
  985. dwValueType == REG_DWORD) &&
  986. IS_FLAG_SET(dwEditFlags, FTA_OpenIsSafe));
  987. TRACE_OUT(("ClassIsSafeToOpen(): Class %s %s safe to open.",
  988. pcszClass,
  989. bSafe ? "is" : "is not"));
  990. return(bSafe);
  991. }
  992. /*
  993. ** SetClassEditFlags()
  994. **
  995. ** Sets or clears EditFlags for a file class.
  996. **
  997. ** Arguments:
  998. **
  999. ** Returns:
  1000. **
  1001. ** Side Effects: none
  1002. */
  1003. PUBLIC_CODE BOOL SetClassEditFlags(PCSTR pcszClass, DWORD dwFlags, BOOL bSet)
  1004. {
  1005. BOOL bResult = FALSE;
  1006. DWORD dwValueType;
  1007. DWORD dwEditFlags;
  1008. DWORD dwcbLen = sizeof(dwEditFlags);
  1009. ASSERT(IS_VALID_STRING_PTR(pcszClass, CSTR));
  1010. /* Get current file class flags. */
  1011. if (GetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags,
  1012. &dwValueType, (PBYTE)&dwEditFlags, &dwcbLen) != ERROR_SUCCESS ||
  1013. (dwValueType != REG_BINARY &&
  1014. dwValueType != REG_DWORD))
  1015. dwEditFlags = 0;
  1016. /* Set or clear SafeOpen flag for file class. */
  1017. if (bSet)
  1018. SET_FLAG(dwEditFlags, dwFlags);
  1019. else
  1020. CLEAR_FLAG(dwEditFlags, dwFlags);
  1021. /*
  1022. * N.b., we must set this as REG_BINARY because the base Win95 shell32.dll
  1023. * only accepts REG_BINARY EditFlags.
  1024. */
  1025. bResult = (SetRegKeyValue(HKEY_CLASSES_ROOT, pcszClass, g_cszEditFlags,
  1026. REG_BINARY, (PCBYTE)&dwEditFlags,
  1027. sizeof(dwEditFlags)) == ERROR_SUCCESS);
  1028. if (bResult)
  1029. TRACE_OUT(("SetClassEditFlags(): Class %s flags %lu %s.",
  1030. pcszClass,
  1031. dwFlags,
  1032. bSet ? "set" : "cleared"));
  1033. else
  1034. WARNING_OUT(("SetClassEditFlags(): Failed to %s class %s flags %lu.",
  1035. bSet ? "set" : "clear",
  1036. pcszClass,
  1037. dwFlags));
  1038. return(bResult);
  1039. }
  1040. #ifdef DEBUG
  1041. PUBLIC_CODE BOOL IsFullPath(PCSTR pcszPath)
  1042. {
  1043. BOOL bResult = FALSE;
  1044. char rgchFullPath[MAX_PATH_LEN];
  1045. if (IS_VALID_STRING_PTR(pcszPath, CSTR) &&
  1046. EVAL(lstrlen(pcszPath) < MAX_PATH_LEN))
  1047. {
  1048. DWORD dwPathLen;
  1049. PSTR pszFileName;
  1050. dwPathLen = GetFullPathName(pcszPath, sizeof(rgchFullPath), rgchFullPath,
  1051. &pszFileName);
  1052. if (EVAL(dwPathLen > 0) &&
  1053. EVAL(dwPathLen < sizeof(rgchFullPath)))
  1054. bResult = EVAL(! lstrcmpi(pcszPath, rgchFullPath));
  1055. }
  1056. return(bResult);
  1057. }
  1058. #endif /* DEBUG */