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.

1449 lines
43 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. apphelp.c
  5. Abstract:
  6. This module implements high-level functions to access apphelp information
  7. Author:
  8. dmunsil created sometime in 1999
  9. Revision History:
  10. --*/
  11. #include "sdbp.h"
  12. #define SIZE_WSTRING(pwsz) \
  13. (pwsz == NULL ? 0 : (wcslen((LPCWSTR)(pwsz)) * sizeof(WCHAR) + sizeof(UNICODE_NULL)))
  14. BOOL
  15. SdbReadApphelpDetailsData(
  16. IN PDB pdb, // apphelp.sdb handle
  17. OUT PAPPHELP_DATA pData // apphelp data, which is filled with various bits of information
  18. )
  19. /*++
  20. Return: TRUE if the string was read, FALSE if not.
  21. Desc: This function retrieves APPHELP details from apphelp.sdb. The database
  22. should have a valid index on HTMLHELPID. In addition, we assume that
  23. the compiler generated unique entries for the htmlhelpids. Tthat means,
  24. no two items have identical indexes. The logic to do so has been
  25. specifically built into shimdbc. If this ever changes, this function will
  26. have to be changed as well.
  27. --*/
  28. {
  29. BOOL bSuccess = FALSE;
  30. TAGID tiApphelp;
  31. TAGID tiAppTitle;
  32. TAGID tiContact;
  33. TAGID tiDetails;
  34. TAGID tiLink;
  35. TAGID tiURL;
  36. TAGID tiLinkText;
  37. FIND_INFO FindInfo;
  38. if (!SdbIsIndexAvailable(pdb, TAG_APPHELP, TAG_HTMLHELPID)) {
  39. DBGPRINT((sdlError,
  40. "SdbReadApphelpDetailsData",
  41. "HTMLHELPID index in details database is not available.\n"));
  42. return FALSE;
  43. }
  44. tiApphelp = SdbFindFirstDWORDIndexedTag(pdb,
  45. TAG_APPHELP,
  46. TAG_HTMLHELPID,
  47. pData->dwHTMLHelpID,
  48. &FindInfo);
  49. if (!tiApphelp) {
  50. DBGPRINT((sdlError,
  51. "SdbReadApphelpDetailsData",
  52. "Failed to find HTMLHELPID 0x%x in the details database.\n",
  53. pData->dwHTMLHelpID));
  54. return FALSE;
  55. }
  56. //
  57. // Now find the link. We support multiple links but use only one for now.
  58. //
  59. tiLink = SdbFindFirstTag(pdb, tiApphelp, TAG_LINK);
  60. if (tiLink) {
  61. tiURL = SdbFindFirstTag(pdb, tiLink, TAG_LINK_URL);
  62. if (tiURL) {
  63. pData->szURL = SdbGetStringTagPtr(pdb, tiURL);
  64. }
  65. tiLinkText = SdbFindFirstTag(pdb, tiLink, TAG_LINK_TEXT);
  66. if (tiLinkText) {
  67. pData->szLink = SdbGetStringTagPtr(pdb, tiLinkText);
  68. }
  69. }
  70. tiDetails = SdbFindFirstTag(pdb, tiApphelp, TAG_APPHELP_DETAILS);
  71. if (tiDetails) {
  72. pData->szDetails = SdbGetStringTagPtr(pdb, tiDetails);
  73. }
  74. tiContact = SdbFindFirstTag(pdb, tiApphelp, TAG_APPHELP_CONTACT);
  75. if (tiContact) {
  76. pData->szContact = SdbGetStringTagPtr(pdb, tiContact);
  77. }
  78. tiAppTitle = SdbFindFirstTag(pdb, tiApphelp, TAG_APPHELP_TITLE);
  79. if (tiAppTitle) {
  80. pData->szAppTitle = SdbGetStringTagPtr(pdb, tiAppTitle);
  81. }
  82. bSuccess = TRUE;
  83. return bSuccess;
  84. }
  85. BOOL
  86. SdbReadApphelpData(
  87. IN HSDB hSDB, // handle to the database channel
  88. IN TAGREF trExe, // TAGREF of the EXE with data to read
  89. OUT PAPPHELP_DATA pData // data that we read
  90. )
  91. /*++
  92. Return: TRUE if the string was read, FALSE if not.
  93. Desc: Read the data associated with the apphelp entry
  94. into APPHELP_DATA structure. If there are no apphelp data
  95. for this exe, then the function returns FALSE.
  96. One or more members of the APPHELP_DATA structure may
  97. be 0.
  98. --*/
  99. {
  100. TAGID tiAppHelp,
  101. tiAppName,
  102. tiProblemSeverity,
  103. tiFlags,
  104. tiHtmlHelpID;
  105. TAGID tiExe;
  106. PDB pdb;
  107. if (pData != NULL) {
  108. RtlZeroMemory(pData, sizeof(APPHELP_DATA));
  109. }
  110. if (!SdbTagRefToTagID(hSDB, trExe, &pdb, &tiExe)) {
  111. DBGPRINT((sdlError,
  112. "SdbReadApphelpData",
  113. "Failed to get the TAGID for TAGREF 0x%x.\n",
  114. trExe));
  115. return FALSE;
  116. }
  117. tiAppHelp = SdbFindFirstTag(pdb, tiExe, TAG_APPHELP);
  118. if (tiAppHelp == TAGID_NULL) {
  119. //
  120. // This is not an apphelp entry
  121. //
  122. DBGPRINT((sdlInfo,
  123. "SdbReadApphelpData",
  124. "This is not an apphelp entry tiExe 0x%x.\n",
  125. tiExe));
  126. return FALSE;
  127. }
  128. if (pData == NULL) {
  129. return TRUE;
  130. }
  131. pData->trExe = trExe;
  132. //
  133. // Read supplemental flags.
  134. //
  135. tiFlags = SdbFindFirstTag(pdb, tiAppHelp, TAG_FLAGS);
  136. if (tiFlags != TAGID_NULL) {
  137. pData->dwFlags = SdbReadDWORDTag(pdb, tiFlags, 0);
  138. }
  139. //
  140. // Read problem severity for this app.
  141. //
  142. tiProblemSeverity = SdbFindFirstTag(pdb, tiAppHelp, TAG_PROBLEMSEVERITY);
  143. if (tiProblemSeverity != TAGID_NULL) {
  144. pData->dwSeverity = SdbReadDWORDTag(pdb, tiProblemSeverity, 0);
  145. }
  146. if (pData->dwSeverity == 0) {
  147. DBGPRINT((sdlError,
  148. "SdbReadApphelpData",
  149. "Problem severity for tiExe 0x%x missing.\n",
  150. tiExe));
  151. return FALSE;
  152. }
  153. //
  154. // We should have html help id here.
  155. //
  156. tiHtmlHelpID = SdbFindFirstTag(pdb, tiAppHelp, TAG_HTMLHELPID);
  157. if (tiHtmlHelpID != TAGID_NULL) {
  158. pData->dwHTMLHelpID = SdbReadDWORDTag(pdb, tiHtmlHelpID, 0);
  159. }
  160. //
  161. // While we are at it, include app's name for now. We might need it.
  162. //
  163. tiAppName = SdbFindFirstTag(pdb, tiExe, TAG_APP_NAME);
  164. if (tiAppName != TAGID_NULL) {
  165. pData->szAppName = SdbGetStringTagPtr(pdb, tiAppName);
  166. }
  167. return TRUE;
  168. }
  169. BOOL
  170. SDBAPI
  171. SdbEscapeApphelpURL(
  172. LPWSTR szResult, // escaped string (output)
  173. LPDWORD pdwCount, // count of tchars in the buffer pointed to by szResult
  174. LPCWSTR szToEscape // string to escape
  175. )
  176. {
  177. static const BYTE s_grfbitEscape[] =
  178. {
  179. 0xFF, 0xFF, // 00 - 0F
  180. 0xFF, 0xFF, // 10 - 1F
  181. 0xFF, 0x13, // 20 - 2F
  182. 0x00, 0xFC, // 30 - 3F
  183. 0x00, 0x00, // 40 - 4F
  184. 0x00, 0x78, // 50 - 5F
  185. 0x01, 0x00, // 60 - 6F
  186. 0x00, 0xF8, // 70 - 7F
  187. 0xFF, 0xFF, // 80 - 8F
  188. 0xFF, 0xFF, // 90 - 9F
  189. 0xFF, 0xFF, // A0 - AF
  190. 0xFF, 0xFF, // B0 - BF
  191. 0xFF, 0xFF, // C0 - CF
  192. 0xFF, 0xFF, // D0 - DF
  193. 0xFF, 0xFF, // E0 - EF
  194. 0xFF, 0xFF, // F0 - FF
  195. };
  196. static const WCHAR s_rgchHex[] = L"0123456789ABCDEF";
  197. WCHAR ch;
  198. DWORD nch = 0;
  199. LPCWSTR lpszURL = szToEscape;
  200. DWORD dwCount = *pdwCount;
  201. // part one -- measure length
  202. while ((ch = *lpszURL++) != L'\0') {
  203. if ((ch & 0xFF00) != 0) { // a unicode char ?
  204. nch += 6;
  205. } else if(s_grfbitEscape[ch >> 3] & (1 << (ch & 7))) {
  206. nch += 3;
  207. } else {
  208. nch += 1;
  209. }
  210. }
  211. nch++; // one more for the final \0
  212. if (dwCount < nch) {
  213. DBGPRINT((sdlError,
  214. "SdbEscapeApphelpURL",
  215. "Not enough storage to escape URL \"%S\" need %ld got %ld\n",
  216. szToEscape,
  217. nch,
  218. dwCount));
  219. *pdwCount = nch;
  220. return FALSE;
  221. }
  222. lpszURL = szToEscape;
  223. while ((ch = *lpszURL++) != L'\0') {
  224. if (ch == L' ') {
  225. *szResult++ = L'+';
  226. } else if ((ch & 0xFF00) != 0) { // a unicode char ?
  227. *szResult++ = L'%';
  228. *szResult++ = L'u';
  229. *szResult++ = s_rgchHex[(ch >> 12) & 0x0F];
  230. *szResult++ = s_rgchHex[(ch >> 8) & 0x0F];
  231. *szResult++ = s_rgchHex[(ch >> 4) & 0x0F];
  232. *szResult++ = s_rgchHex[ ch & 0x0F];
  233. } else if(s_grfbitEscape[ch >> 3] & (1 << (ch & 7))) {
  234. *szResult++ = L'%';
  235. *szResult++ = s_rgchHex[(ch >> 4) & 0x0F];
  236. *szResult++ = s_rgchHex[ ch & 0x0F];
  237. } else {
  238. *szResult++ = ch;
  239. }
  240. }
  241. *szResult = L'\0';
  242. *pdwCount = nch - 1; // do not include the term \0 into a char count
  243. return TRUE;
  244. }
  245. /////////////////////////////////////////////////////////////////////////////////////////////
  246. //
  247. //
  248. // Retrieving apphelp information
  249. //
  250. //
  251. //
  252. PDB
  253. SDBAPI
  254. SdbOpenApphelpDetailsDatabase(
  255. LPCWSTR pwszDetailsDatabasePath
  256. )
  257. {
  258. PDB pdbDetails = NULL;
  259. DWORD dwLength;
  260. WCHAR wszAppHelpSdb[MAX_PATH];
  261. if (pwszDetailsDatabasePath == NULL) {
  262. //
  263. // By default the details database is in %windir%\AppPatch\apphelp.sdb
  264. //
  265. dwLength = SdbpGetStandardDatabasePath(NULL,
  266. SDB_DATABASE_MAIN_DETAILS,
  267. 0, // retrieve NT_PATH
  268. wszAppHelpSdb,
  269. CHARCOUNT(wszAppHelpSdb));
  270. if (dwLength != 0 && dwLength < CHARCOUNT(wszAppHelpSdb)) {
  271. pdbDetails = SdbOpenDatabase(wszAppHelpSdb, NT_PATH);
  272. }
  273. } else {
  274. pdbDetails = SdbOpenDatabase(pwszDetailsDatabasePath, DOS_PATH);
  275. }
  276. if (pdbDetails == NULL) {
  277. DBGPRINT((sdlError, "SdbOpenApphelpDetailsDatabase", "Failed to open the details database.\n"));
  278. }
  279. return pdbDetails;
  280. }
  281. BOOL
  282. SdbpReadApphelpBasicInfo(
  283. IN PDB pdb,
  284. IN TAGID tiEntry,
  285. OUT TAGID* ptiApphelp,
  286. OUT LPDWORD lpdwHtmlHelpID,
  287. OUT LPDWORD lpdwProblemSeverity,
  288. OUT LPDWORD lpdwFlags
  289. )
  290. {
  291. TAGID tiAppHelp = TAGID_NULL;
  292. TAGID tiHtmlHelpID = TAGID_NULL;
  293. TAGID tiSeverity = TAGID_NULL;
  294. TAGID tiFlags = TAGID_NULL;
  295. DWORD dwHtmlHelpID = 0;
  296. DWORD dwSeverity = 0;
  297. DWORD dwFlags = 0;
  298. BOOL bReturn = FALSE;
  299. if (tiEntry == TAGID_NULL) {
  300. goto out;
  301. }
  302. assert(ptiApphelp != NULL);
  303. tiAppHelp = SdbFindFirstTag(pdb, tiEntry, TAG_APPHELP);
  304. if (tiAppHelp == TAGID_NULL) {
  305. //
  306. // This is not an apphelp entry
  307. //
  308. DBGPRINT((sdlError, "SdbpReadApphelpBasicInfo",
  309. "This is not an apphelp entry tiExe 0x%x.\n", tiEntry));
  310. goto out;
  311. }
  312. if (lpdwHtmlHelpID != NULL) {
  313. tiHtmlHelpID = SdbFindFirstTag(pdb, tiAppHelp, TAG_HTMLHELPID);
  314. if (tiHtmlHelpID != TAGID_NULL) {
  315. dwHtmlHelpID = SdbReadDWORDTag(pdb, tiHtmlHelpID, 0);
  316. }
  317. *lpdwHtmlHelpID = dwHtmlHelpID;
  318. }
  319. if (lpdwProblemSeverity != NULL) {
  320. tiSeverity = SdbFindFirstTag(pdb, tiAppHelp, TAG_PROBLEMSEVERITY);
  321. if (tiSeverity != TAGID_NULL) {
  322. dwSeverity = SdbReadDWORDTag(pdb, tiSeverity, 0);
  323. }
  324. *lpdwProblemSeverity = dwSeverity;
  325. }
  326. //
  327. // Read supplemental flags.
  328. //
  329. if (lpdwFlags != NULL) {
  330. tiFlags = SdbFindFirstTag(pdb, tiAppHelp, TAG_FLAGS);
  331. if (tiFlags != TAGID_NULL) {
  332. dwFlags = SdbReadDWORDTag(pdb, tiFlags, 0);
  333. }
  334. *lpdwFlags = dwFlags;
  335. }
  336. bReturn = TRUE;
  337. out:
  338. // always set the tiApphelp
  339. *ptiApphelp = tiAppHelp;
  340. return bReturn;
  341. }
  342. HAPPHELPINFOCONTEXT
  343. SDBAPI
  344. SdbOpenApphelpInformationByID(
  345. IN HSDB hSDB,
  346. IN TAGREF trEntry,
  347. IN DWORD dwDatabaseType // pass the type of db you are using
  348. )
  349. {
  350. PAPPHELPINFOCONTEXT pApphelpInfoContext = NULL;
  351. PDB pdb = NULL;
  352. TAGID tiExe = TAGID_NULL;
  353. BOOL bSuccess = FALSE;
  354. if (trEntry == TAGREF_NULL) {
  355. return NULL;
  356. }
  357. //
  358. // if we are here, it is apphelp for sure, so we create the context
  359. //
  360. pApphelpInfoContext = (PAPPHELPINFOCONTEXT)SdbAlloc(sizeof(APPHELPINFOCONTEXT));
  361. if (pApphelpInfoContext == NULL) {
  362. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  363. "Error allocating memory for apphelp info context\n"));
  364. goto out;
  365. }
  366. pApphelpInfoContext->hSDB = hSDB;
  367. pApphelpInfoContext->pdb = pdb;
  368. pApphelpInfoContext->dwContextFlags |= AHC_HSDB_NOCLOSE; // external hsdb, do not touch it
  369. //
  370. // all we care for -- is whether it's "main" database or not
  371. //
  372. pApphelpInfoContext->dwDatabaseType = dwDatabaseType;
  373. // get the guid for this db
  374. if (!SdbTagRefToTagID(hSDB, trEntry, &pdb, &tiExe)) {
  375. DBGPRINT((sdlError, "SdbOpenApphelpInformationByID",
  376. "Error converting tagref to tagref 0x%lx\n", trEntry));
  377. goto out;
  378. }
  379. pApphelpInfoContext->tiExe = tiExe;
  380. if (!SdbGetDatabaseGUID(hSDB, pdb, &pApphelpInfoContext->guidDB)) {
  381. DBGPRINT((sdlError, "SdbOpenApphelpInformationByID",
  382. "Error reading database guid for tagref 0x%lx\n", trEntry));
  383. goto out;
  384. }
  385. if (!SdbpReadApphelpBasicInfo(pdb,
  386. tiExe,
  387. &pApphelpInfoContext->tiApphelpExe,
  388. &pApphelpInfoContext->dwHtmlHelpID,
  389. &pApphelpInfoContext->dwSeverity,
  390. &pApphelpInfoContext->dwFlags)) {
  391. DBGPRINT((sdlError, "SdbOpenApphelpInformationByID",
  392. "Error reading apphelp basic information, apphelp may not be present for 0x%lx\n", trEntry));
  393. goto out;
  394. }
  395. bSuccess = TRUE;
  396. //
  397. out:
  398. if (!bSuccess) {
  399. if (pApphelpInfoContext != NULL) {
  400. SdbFree(pApphelpInfoContext);
  401. pApphelpInfoContext = NULL;
  402. }
  403. }
  404. return pApphelpInfoContext;
  405. }
  406. HAPPHELPINFOCONTEXT
  407. SDBAPI
  408. SdbOpenApphelpInformation(
  409. IN GUID* pguidDB,
  410. IN GUID* pguidID
  411. )
  412. {
  413. WCHAR szDatabasePath[MAX_PATH];
  414. DWORD dwDatabaseType = 0;
  415. DWORD dwLength;
  416. HSDB hSDB = NULL;
  417. PDB pdb = NULL;
  418. TAGID tiMatch = TAGID_NULL;
  419. FIND_INFO FindInfo;
  420. PAPPHELPINFOCONTEXT pApphelpInfoContext = NULL;
  421. BOOL bSuccess = FALSE;
  422. //
  423. // Resolve and open the database.
  424. //
  425. // NOTE: For now pass the IMAGE_FILE_MACHINE_I386 flag.
  426. // We'll only look into the 32 bit database.
  427. //
  428. hSDB = SdbInitDatabaseEx(HID_NO_DATABASE, NULL, IMAGE_FILE_MACHINE_I386);
  429. if (hSDB == NULL) {
  430. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  431. "Failed to initialize database\n"));
  432. goto out;
  433. }
  434. //
  435. // First, we need to resolve a db
  436. //
  437. dwLength = SdbResolveDatabase(hSDB,
  438. pguidDB,
  439. &dwDatabaseType,
  440. szDatabasePath,
  441. CHARCOUNT(szDatabasePath));
  442. if (dwLength == 0 || dwLength > CHARCOUNT(szDatabasePath)) {
  443. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  444. "Failed to resolve database path\n"));
  445. goto out;
  446. }
  447. //
  448. // open database
  449. //
  450. if (!SdbOpenLocalDatabase(hSDB, szDatabasePath)) {
  451. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  452. "Failed to open database \"%s\"\n", szDatabasePath));
  453. goto out;
  454. }
  455. //
  456. // we have database opened, I presume
  457. //
  458. pdb = ((PSDBCONTEXT)hSDB)->pdbLocal;
  459. //
  460. // we search only the LOCAL database in this case
  461. //
  462. tiMatch = SdbFindFirstGUIDIndexedTag(pdb,
  463. TAG_EXE,
  464. TAG_EXE_ID,
  465. pguidID,
  466. &FindInfo);
  467. // if we have a match...
  468. if (tiMatch == TAGID_NULL) {
  469. DBGPRINT((sdlWarning, "SdbOpenApphelpInformation", "guid was not found in the database\n"));
  470. goto out;
  471. }
  472. //
  473. // if we are here, it is apphelp for sure, so we create the context
  474. //
  475. pApphelpInfoContext = (PAPPHELPINFOCONTEXT)SdbAlloc(sizeof(APPHELPINFOCONTEXT));
  476. if (pApphelpInfoContext == NULL) {
  477. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  478. "Error allocating memory for apphelp info context\n"));
  479. goto out;
  480. }
  481. pApphelpInfoContext->hSDB = hSDB;
  482. pApphelpInfoContext->pdb = pdb;
  483. pApphelpInfoContext->guidID = *pguidID;
  484. pApphelpInfoContext->guidDB = *pguidDB;
  485. pApphelpInfoContext->tiExe = tiMatch;
  486. pApphelpInfoContext->dwDatabaseType = dwDatabaseType;
  487. if (!SdbpReadApphelpBasicInfo(pdb,
  488. tiMatch,
  489. &pApphelpInfoContext->tiApphelpExe,
  490. &pApphelpInfoContext->dwHtmlHelpID,
  491. &pApphelpInfoContext->dwSeverity,
  492. &pApphelpInfoContext->dwFlags)) {
  493. DBGPRINT((sdlError, "SdbOpenApphelpInformation",
  494. "Error reading apphelp basic information, apphelp may not be present for tagid 0x%lx\n", tiMatch));
  495. goto out;
  496. }
  497. bSuccess = TRUE;
  498. //
  499. // we are done now
  500. //
  501. out:
  502. if (!bSuccess) {
  503. if (hSDB != NULL) {
  504. SdbReleaseDatabase(hSDB);
  505. }
  506. if (pApphelpInfoContext != NULL) {
  507. SdbFree(pApphelpInfoContext);
  508. pApphelpInfoContext = NULL;
  509. }
  510. }
  511. return (HAPPHELPINFOCONTEXT)pApphelpInfoContext;
  512. }
  513. BOOL
  514. SDBAPI
  515. SdbCloseApphelpInformation(
  516. HAPPHELPINFOCONTEXT hctx
  517. )
  518. {
  519. PAPPHELPINFOCONTEXT pApphelpInfoContext = (PAPPHELPINFOCONTEXT)hctx;
  520. if (pApphelpInfoContext != NULL) {
  521. if (pApphelpInfoContext->hSDB != NULL &&
  522. !(pApphelpInfoContext->dwContextFlags & AHC_HSDB_NOCLOSE)) {
  523. SdbReleaseDatabase(pApphelpInfoContext->hSDB);
  524. }
  525. if (pApphelpInfoContext->pdbDetails != NULL &&
  526. !(pApphelpInfoContext->dwContextFlags & AHC_DBDETAILS_NOCLOSE)) {
  527. SdbCloseDatabaseRead(pApphelpInfoContext->pdbDetails);
  528. }
  529. if (pApphelpInfoContext->pwszHelpCtrURL != NULL) {
  530. SdbFree(pApphelpInfoContext->pwszHelpCtrURL);
  531. }
  532. RtlFreeUnicodeString(&pApphelpInfoContext->ustrChmFile);
  533. RtlFreeUnicodeString(&pApphelpInfoContext->ustrDetailsDatabase);
  534. SdbFree(pApphelpInfoContext);
  535. }
  536. return TRUE;
  537. }
  538. DWORD
  539. SDBAPI
  540. SdbpReadApphelpString(
  541. PDB pdb,
  542. TAGID tiParent,
  543. TAG tItem,
  544. LPCWSTR* ppwszCache,
  545. LPVOID* ppResult
  546. )
  547. {
  548. DWORD cbResult = 0;
  549. TAGID tiItem;
  550. LPCWSTR pwszItem = NULL;
  551. if (*ppwszCache != NULL) {
  552. pwszItem = *ppwszCache;
  553. } else {
  554. tiItem = SdbFindFirstTag(pdb, tiParent, tItem);
  555. if (tiItem != TAGID_NULL) {
  556. pwszItem = SdbGetStringTagPtr(pdb, tiItem);
  557. if (pwszItem != NULL) {
  558. *ppwszCache = pwszItem;
  559. }
  560. }
  561. }
  562. cbResult = (DWORD)SIZE_WSTRING(pwszItem);
  563. *ppResult = (LPVOID)pwszItem;
  564. return cbResult;
  565. }
  566. BOOL
  567. SDBAPI
  568. SdbpReadApphelpLinkInformation(
  569. PAPPHELPINFOCONTEXT pApphelpInfoContext
  570. )
  571. {
  572. TAGID tiLink;
  573. TAGID tiApphelp = pApphelpInfoContext->tiApphelpDetails;
  574. PDB pdb = pApphelpInfoContext->pdbDetails;
  575. TAGID tiURL;
  576. TAGID tiLinkText;
  577. if (pApphelpInfoContext->tiLink != TAGID_NULL) {
  578. return TRUE;
  579. }
  580. //
  581. // Now find the link. We support multiple links but use only one for now.
  582. //
  583. tiLink = SdbFindFirstTag(pdb, tiApphelp, TAG_LINK);
  584. if (tiLink == TAGID_NULL) {
  585. return FALSE;
  586. }
  587. tiURL = SdbFindFirstTag(pdb, tiLink, TAG_LINK_URL);
  588. if (tiURL) {
  589. pApphelpInfoContext->pwszLinkURL = SdbGetStringTagPtr(pdb, tiURL);
  590. }
  591. tiLinkText = SdbFindFirstTag(pdb, tiLink, TAG_LINK_TEXT);
  592. if (tiLinkText) {
  593. pApphelpInfoContext->pwszLinkText = SdbGetStringTagPtr(pdb, tiLinkText);
  594. }
  595. pApphelpInfoContext->tiLink = tiLink;
  596. return TRUE;
  597. }
  598. BOOL
  599. SDBAPI
  600. SdbpCreateHelpCenterURL(
  601. IN HAPPHELPINFOCONTEXT hctx,
  602. IN BOOL bOfflineContent OPTIONAL, // pass FALSE
  603. IN BOOL bUseHtmlHelp OPTIONAL, // pass FALSE
  604. IN LPCWSTR pwszChmFile OPTIONAL // pass NULL
  605. );
  606. BOOL
  607. SDBAPI
  608. SdbSetApphelpDebugParameters(
  609. IN HAPPHELPINFOCONTEXT hctx,
  610. IN LPCWSTR pszDetailsDatabase OPTIONAL,
  611. IN BOOL bOfflineContent OPTIONAL, // pass FALSE
  612. IN BOOL bUseHtmlHelp OPTIONAL, // pass FALSE
  613. IN LPCWSTR pszChmFile OPTIONAL // pass NULL
  614. )
  615. {
  616. PAPPHELPINFOCONTEXT pApphelpInfoContext = (PAPPHELPINFOCONTEXT)hctx;
  617. if (pApphelpInfoContext == NULL) {
  618. return FALSE;
  619. }
  620. if (bUseHtmlHelp && !bOfflineContent) {
  621. DBGPRINT((sdlError, "SdbSetApphelpDebugParameters",
  622. "Inconsistent parameters: when using html help -- offline content flag should also be set\n"));
  623. bOfflineContent = TRUE;
  624. }
  625. RtlFreeUnicodeString(&pApphelpInfoContext->ustrDetailsDatabase);
  626. RtlFreeUnicodeString(&pApphelpInfoContext->ustrChmFile);
  627. pApphelpInfoContext->bOfflineContent = bOfflineContent;
  628. pApphelpInfoContext->bUseHtmlHelp = bUseHtmlHelp;
  629. if (pszDetailsDatabase != NULL) {
  630. if (!RtlCreateUnicodeString(&pApphelpInfoContext->ustrDetailsDatabase, pszDetailsDatabase)) {
  631. DBGPRINT((sdlError, "SdbSetApphelpDebugParameters",
  632. "Failed to create unicode string from \"%S\"\n", pszDetailsDatabase));
  633. return FALSE;
  634. }
  635. }
  636. if (pszChmFile != NULL) {
  637. if (!RtlCreateUnicodeString(&pApphelpInfoContext->ustrChmFile, pszChmFile)) {
  638. DBGPRINT((sdlError, "SdbSetApphelpDebugParameters",
  639. "Failed to create unicode string from \"%S\"\n", pszChmFile));
  640. return FALSE;
  641. }
  642. }
  643. return TRUE;
  644. }
  645. DWORD
  646. SDBAPI
  647. SdbQueryApphelpInformation(
  648. HAPPHELPINFOCONTEXT hctx,
  649. APPHELPINFORMATIONCLASS InfoClass,
  650. LPVOID pBuffer, // may be NULL
  651. DWORD cbSize // may be 0 if pBuffer is NULL
  652. )
  653. {
  654. PAPPHELPINFOCONTEXT pApphelpInfoContext = (PAPPHELPINFOCONTEXT)hctx;
  655. LPCWSTR *ppwsz;
  656. TAG tag;
  657. TAGID tiParent;
  658. LPVOID pResult = NULL;
  659. DWORD cbResult = 0;
  660. PDB pdb = NULL;
  661. PDB pdbDetails = NULL;
  662. TAGID tiApphelpDetails = TAGID_NULL;
  663. FIND_INFO FindInfo;
  664. switch (InfoClass) {
  665. case ApphelpLinkURL:
  666. case ApphelpLinkText:
  667. case ApphelpTitle:
  668. case ApphelpDetails:
  669. case ApphelpContact:
  670. pdbDetails = pApphelpInfoContext->pdbDetails;
  671. if (pApphelpInfoContext->pdbDetails == NULL) {
  672. //
  673. // see which db we should open
  674. //
  675. if ((pApphelpInfoContext->ustrDetailsDatabase.Buffer != NULL) ||
  676. (pApphelpInfoContext->dwDatabaseType & SDB_DATABASE_MAIN)) {
  677. pdbDetails = SdbOpenApphelpDetailsDatabase(pApphelpInfoContext->ustrDetailsDatabase.Buffer);
  678. } else {
  679. // we have a case when the apphelp details should be in main db
  680. pApphelpInfoContext->dwContextFlags |= AHC_DBDETAILS_NOCLOSE;
  681. pdbDetails = pApphelpInfoContext->pdb;
  682. }
  683. if (pdbDetails == NULL) {
  684. return cbResult; // apphelp db is not available
  685. }
  686. pApphelpInfoContext->pdbDetails = pdbDetails;
  687. }
  688. tiApphelpDetails = pApphelpInfoContext->tiApphelpDetails;
  689. if (tiApphelpDetails == TAGID_NULL) {
  690. if (!SdbIsIndexAvailable(pdbDetails, TAG_APPHELP, TAG_HTMLHELPID)) {
  691. DBGPRINT((sdlError,
  692. "SdbQueryApphelpInformation",
  693. "HTMLHELPID index in details database is not available.\n"));
  694. return cbResult;
  695. }
  696. tiApphelpDetails = SdbFindFirstDWORDIndexedTag(pdbDetails,
  697. TAG_APPHELP,
  698. TAG_HTMLHELPID,
  699. pApphelpInfoContext->dwHtmlHelpID,
  700. &FindInfo);
  701. if (tiApphelpDetails == TAGID_NULL) {
  702. DBGPRINT((sdlError,
  703. "SdbQueryApphelpInformation",
  704. "Failed to find HTMLHELPID 0x%x in the details database.\n",
  705. pApphelpInfoContext->dwHtmlHelpID));
  706. return cbResult;
  707. }
  708. pApphelpInfoContext->tiApphelpDetails = tiApphelpDetails;
  709. }
  710. break;
  711. default:
  712. break;
  713. }
  714. switch(InfoClass) {
  715. case ApphelpExeTagID:
  716. pResult = &pApphelpInfoContext->tiExe;
  717. cbResult = sizeof(pApphelpInfoContext->tiExe);
  718. break;
  719. case ApphelpExeName:
  720. pdb = pApphelpInfoContext->pdb; // main db
  721. tiParent = pApphelpInfoContext->tiExe;
  722. ppwsz = &pApphelpInfoContext->pwszExeName;
  723. tag = TAG_NAME;
  724. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  725. break;
  726. case ApphelpAppName:
  727. pdb = pApphelpInfoContext->pdb; // main db
  728. tiParent = pApphelpInfoContext->tiExe;
  729. ppwsz = &pApphelpInfoContext->pwszAppName;
  730. tag = TAG_APP_NAME;
  731. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  732. break;
  733. case ApphelpVendorName:
  734. pdb = pApphelpInfoContext->pdb; // main db
  735. tiParent = pApphelpInfoContext->tiExe;
  736. ppwsz = &pApphelpInfoContext->pwszVendorName;
  737. tag = TAG_VENDOR;
  738. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  739. break;
  740. case ApphelpHtmlHelpID:
  741. pResult = &pApphelpInfoContext->dwHtmlHelpID;
  742. cbResult = sizeof(pApphelpInfoContext->dwHtmlHelpID);
  743. break;
  744. case ApphelpProblemSeverity:
  745. pResult = &pApphelpInfoContext->dwSeverity;
  746. cbResult = sizeof(pApphelpInfoContext->dwSeverity);
  747. break;
  748. case ApphelpFlags:
  749. pResult = &pApphelpInfoContext->dwFlags;
  750. cbResult = sizeof(pApphelpInfoContext->dwFlags);
  751. break;
  752. case ApphelpLinkURL:
  753. if (!SdbpReadApphelpLinkInformation(pApphelpInfoContext)) {
  754. break;
  755. }
  756. pResult = (LPWSTR)pApphelpInfoContext->pwszLinkURL;
  757. cbResult = (DWORD)SIZE_WSTRING(pResult);
  758. break;
  759. case ApphelpLinkText:
  760. if (!SdbpReadApphelpLinkInformation(pApphelpInfoContext)) {
  761. break;
  762. }
  763. pResult = (LPWSTR)pApphelpInfoContext->pwszLinkText;
  764. cbResult = (DWORD)SIZE_WSTRING(pResult);
  765. break;
  766. case ApphelpTitle:
  767. pdb = pdbDetails;
  768. tiParent = tiApphelpDetails;
  769. ppwsz = &pApphelpInfoContext->pwszTitle;
  770. tag = TAG_APPHELP_TITLE;
  771. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  772. break;
  773. case ApphelpDetails:
  774. pdb = pdbDetails;
  775. tiParent = tiApphelpDetails;
  776. ppwsz = &pApphelpInfoContext->pwszDetails;
  777. tag = TAG_APPHELP_DETAILS;
  778. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  779. break;
  780. case ApphelpContact:
  781. pdb = pdbDetails;
  782. tiParent = tiApphelpDetails;
  783. ppwsz = &pApphelpInfoContext->pwszContact;
  784. tag = TAG_APPHELP_CONTACT;
  785. cbResult = SdbpReadApphelpString(pdb, tiParent, tag, ppwsz, &pResult);
  786. break;
  787. case ApphelpHelpCenterURL:
  788. if (!SdbpCreateHelpCenterURL(hctx,
  789. pApphelpInfoContext->bOfflineContent,
  790. pApphelpInfoContext->bUseHtmlHelp,
  791. pApphelpInfoContext->ustrChmFile.Buffer)) {
  792. break;
  793. }
  794. pResult = pApphelpInfoContext->pwszHelpCtrURL;
  795. cbResult = (DWORD)SIZE_WSTRING(pResult);
  796. break;
  797. case ApphelpDatabaseGUID:
  798. pResult = &pApphelpInfoContext->guidDB;
  799. cbResult = sizeof(pApphelpInfoContext->guidDB);
  800. break;
  801. default:
  802. DBGPRINT((sdlError, "SdbQueryApphelpInformation",
  803. "Bad Apphelp Information class 0x%lx\n", InfoClass));
  804. return 0;
  805. break;
  806. }
  807. if (pBuffer == NULL || cbResult > cbSize) {
  808. return cbResult;
  809. }
  810. if (pResult != NULL && cbResult > 0) {
  811. RtlCopyMemory(pBuffer, pResult, cbResult);
  812. }
  813. return cbResult;
  814. }
  815. typedef HRESULT (STDAPICALLTYPE *PFNUrlUnescapeW)(
  816. LPWSTR pszUrl,
  817. LPWSTR pszUnescaped,
  818. LPDWORD pcchUnescaped,
  819. DWORD dwFlags);
  820. typedef HRESULT (STDAPICALLTYPE *PFNUrlEscapeW)(
  821. LPCWSTR pszURL,
  822. LPWSTR pszEscaped,
  823. LPDWORD pcchEscaped,
  824. DWORD dwFlags
  825. );
  826. //
  827. // if bUseHtmlHelp is set -- then bOfflineContent is also set to TRUE
  828. //
  829. BOOL
  830. SDBAPI
  831. SdbpCreateHelpCenterURL(
  832. IN HAPPHELPINFOCONTEXT hctx,
  833. IN BOOL bOfflineContent OPTIONAL, // pass FALSE
  834. IN BOOL bUseHtmlHelp OPTIONAL, // pass FALSE
  835. IN LPCWSTR pwszChmFile OPTIONAL // pass NULL
  836. )
  837. {
  838. WCHAR szAppHelpURL[2048];
  839. WCHAR szChmURL[1024];
  840. PAPPHELPINFOCONTEXT pApphelpInfo = (PAPPHELPINFOCONTEXT)hctx;
  841. HMODULE hModShlwapi = NULL;
  842. PFNUrlUnescapeW pfnUnescape;
  843. PFNUrlEscapeW pfnEscape;
  844. BOOL bSuccess = FALSE;
  845. int nChURL = 0; // counts used bytes
  846. int cch = 0;
  847. int nch;
  848. size_t cchRemaining;
  849. LPWSTR lpwszUnescaped = NULL;
  850. HRESULT hr;
  851. DWORD nChars;
  852. WCHAR szWindowsDir[MAX_PATH];
  853. BOOL bCustom;
  854. if (pApphelpInfo->pwszHelpCtrURL != NULL) {
  855. return TRUE;
  856. }
  857. if (bUseHtmlHelp) {
  858. bOfflineContent = TRUE;
  859. }
  860. // ping the database
  861. if (0 == SdbQueryApphelpInformation(hctx, ApphelpLinkURL, NULL, 0)) {
  862. return FALSE;
  863. }
  864. //
  865. // check and see whether it's custom apphelp or not
  866. //
  867. bCustom = !(pApphelpInfo->dwDatabaseType & SDB_DATABASE_MAIN);
  868. if (bCustom) {
  869. if (pApphelpInfo->pwszLinkURL != NULL) {
  870. hr = StringCchPrintf(szAppHelpURL,
  871. CHARCOUNT(szAppHelpURL),
  872. L"%ls",
  873. pApphelpInfo->pwszLinkURL);
  874. if (FAILED(hr)) {
  875. DBGPRINT((sdlError, "SdbpCreateHelpCenterURL",
  876. "Custom apphelp URL %s is too long\n", pApphelpInfo->pwszLinkURL));
  877. goto out;
  878. }
  879. // now we are done
  880. goto createApphelpURL;
  881. } else {
  882. // custom apphelp will not fly without a link
  883. DBGPRINT((sdlError, "SdbpCreateHelpCenterURL", "Custom apphelp without a url link\n"));
  884. goto out;
  885. }
  886. }
  887. // unescape the URL
  888. hModShlwapi = LoadLibraryW(L"shlwapi.dll");
  889. if (hModShlwapi == NULL) {
  890. return FALSE;
  891. }
  892. pfnUnescape = (PFNUrlUnescapeW)GetProcAddress(hModShlwapi, "UrlUnescapeW");
  893. pfnEscape = (PFNUrlEscapeW) GetProcAddress(hModShlwapi, "UrlEscapeW");
  894. if (pfnUnescape == NULL || pfnEscape == NULL) {
  895. DBGPRINT((sdlError, "SdbpCreateHelpCenterURL", "Cannot get shlwapi functions\n"));
  896. goto out;
  897. }
  898. if (!bUseHtmlHelp) {
  899. StringCchPrintfEx(szAppHelpURL,
  900. CHARCOUNT(szAppHelpURL),
  901. NULL,
  902. &cchRemaining,
  903. 0,
  904. L"hcp://services/redirect?online=");
  905. nChURL = CHARCOUNT(szAppHelpURL) - (int)cchRemaining;
  906. }
  907. if (!bOfflineContent && pApphelpInfo->pwszLinkURL != NULL) {
  908. // unescape the url first using shell
  909. cch = (int)wcslen(pApphelpInfo->pwszLinkURL) + 1;
  910. STACK_ALLOC(lpwszUnescaped, cch * sizeof(WCHAR));
  911. if (lpwszUnescaped == NULL) {
  912. DBGPRINT((sdlError, "SdbpCreateHelpCenterURL",
  913. "Error trying to allocate memory for \"%S\"\n", pApphelpInfo->pwszLinkURL));
  914. goto out;
  915. }
  916. //
  917. // Unescape round 1 - use the shell function (same as used to encode it for xml/database)
  918. //
  919. hr = pfnUnescape((LPTSTR)pApphelpInfo->pwszLinkURL, lpwszUnescaped, (LPDWORD)&cch, 0);
  920. if (!SUCCEEDED(hr)) {
  921. DBGPRINT((sdlError, "SdbCreateHelpCenterURL", "UrlUnescapeW failed on \"%S\"\n", pApphelpInfo->pwszLinkURL));
  922. goto out;
  923. }
  924. //
  925. // round 2 - use our function borrowed from help center
  926. //
  927. cch = (DWORD)(CHARCOUNT(szAppHelpURL) - nChURL);
  928. if (!SdbEscapeApphelpURL(szAppHelpURL + nChURL, (LPDWORD)&cch, lpwszUnescaped)) {
  929. DBGPRINT((sdlError, "SdbCreateHelpCenterURL", "Error escaping URL \"%S\"\n", lpwszUnescaped));
  930. goto out;
  931. }
  932. nChURL += (int)cch;
  933. }
  934. //
  935. // Retrieve the Windows directory.
  936. //
  937. nChars = GetWindowsDirectoryW(szWindowsDir, CHARCOUNT(szWindowsDir));
  938. if (!nChars || nChars > CHARCOUNT(szWindowsDir)) {
  939. DBGPRINT((sdlError, "SdbCreateHelpCenterURL",
  940. "Error trying to retrieve Windows Directory %d.\n", GetLastError()));
  941. goto out;
  942. }
  943. if (pwszChmFile != NULL) {
  944. StringCchPrintf(szChmURL,
  945. CHARCOUNT(szChmURL),
  946. L"mk:@msitstore:%ls::/idh_w2_%d.htm",
  947. pwszChmFile,
  948. pApphelpInfo->dwHtmlHelpID);
  949. } else { // standard chm file
  950. //
  951. // Attention: if we use hDlg here then, upon exit we will need to clean
  952. // up the window.
  953. //
  954. StringCchPrintf(szChmURL,
  955. CHARCOUNT(szChmURL),
  956. L"mk:@msitstore:%ls\\help\\apps.chm::/idh_w2_%d.htm",
  957. szWindowsDir,
  958. pApphelpInfo->dwHtmlHelpID);
  959. }
  960. if (bOfflineContent) {
  961. if (bUseHtmlHelp) {
  962. cch = CHARCOUNT(szAppHelpURL);
  963. hr = pfnEscape(szChmURL, szAppHelpURL, (LPDWORD)&cch, 0);
  964. if (SUCCEEDED(hr)) {
  965. nChURL += (INT)cch;
  966. }
  967. } else { // do not use html help
  968. cch = (DWORD)(CHARCOUNT(szAppHelpURL) - nChURL);
  969. if (!SdbEscapeApphelpURL(szAppHelpURL+nChURL, (LPDWORD)&cch, szChmURL)) {
  970. DBGPRINT((sdlError, "SdbCreateHelpCenterURL", "Error escaping URL \"%S\"\n", szChmURL));
  971. goto out;
  972. }
  973. nChURL += (INT)cch;
  974. }
  975. }
  976. if (!bUseHtmlHelp) {
  977. //
  978. // now offline sequence
  979. //
  980. cch = (DWORD)(CHARCOUNT(szAppHelpURL) - nChURL);
  981. hr = StringCchPrintfEx(szAppHelpURL + nChURL,
  982. cch,
  983. NULL,
  984. &cchRemaining,
  985. 0,
  986. L"&offline=");
  987. if (FAILED(hr)) {
  988. goto out;
  989. }
  990. nch = cch - (int)cchRemaining;
  991. nChURL += nch;
  992. cch = (DWORD)(CHARCOUNT(szAppHelpURL) - nChURL);
  993. if (!SdbEscapeApphelpURL(szAppHelpURL+nChURL, (LPDWORD)&cch, szChmURL)) {
  994. DBGPRINT((sdlError, "SdbCreateHelpCenterURL", "Error escaping URL \"%S\"\n", szChmURL));
  995. goto out;
  996. }
  997. nChURL += (int)cch;
  998. }
  999. *(szAppHelpURL + nChURL) = L'\0';
  1000. // we are done
  1001. // copy data now
  1002. createApphelpURL:
  1003. pApphelpInfo->pwszHelpCtrURL = (LPWSTR)SdbAlloc(nChURL * sizeof(WCHAR) + sizeof(UNICODE_NULL));
  1004. if (pApphelpInfo->pwszHelpCtrURL == NULL) {
  1005. DBGPRINT((sdlError, "SdbCreateHelpCenterURL", "Error allocating memory for the URL 0x%lx chars\n", nChURL));
  1006. goto out;
  1007. }
  1008. StringCchCopy(pApphelpInfo->pwszHelpCtrURL, nChURL + sizeof(UNICODE_NULL), szAppHelpURL);
  1009. bSuccess = TRUE;
  1010. out:
  1011. if (lpwszUnescaped != NULL) {
  1012. STACK_FREE(lpwszUnescaped);
  1013. }
  1014. if (hModShlwapi) {
  1015. FreeLibrary(hModShlwapi);
  1016. }
  1017. return bSuccess;
  1018. }
  1019. //
  1020. // returns TRUE if dialog was shown
  1021. // if there was an error, input parameter (pRunApp) will NOT
  1022. // be touched
  1023. BOOL
  1024. SdbShowApphelpDialog( // returns TRUE if success, whether we should run the app is in pRunApp
  1025. IN PAPPHELP_INFO pAHInfo, // the info necessary to find the apphelp data
  1026. IN PHANDLE phProcess, // [optional] returns the process handle of
  1027. // the process displaying the apphelp.
  1028. // When the process completes, the return value
  1029. // (from GetExitCodeProcess()) will be zero
  1030. // if the app should not run, or non-zero
  1031. // if it should run.
  1032. IN OUT BOOL* pRunApp
  1033. )
  1034. {
  1035. //
  1036. // basically just launch the apphelp.exe and wait for it to return
  1037. //
  1038. TCHAR szGuid[64];
  1039. TCHAR szCommandLine[MAX_PATH * 2 + 64];
  1040. LPTSTR pszEnd = szCommandLine;
  1041. STARTUPINFO StartupInfo;
  1042. PROCESS_INFORMATION ProcessInfo;
  1043. DWORD dwExit = 1; // by default and in case of failure, we allow to run the app
  1044. BOOL bReturn = FALSE;
  1045. BOOL bRunApp = TRUE; // by default we run the app ?
  1046. size_t cchRemaining;
  1047. UINT unChars;
  1048. cchRemaining = CHARCOUNT(szCommandLine);
  1049. unChars = GetSystemDirectory(pszEnd, (UINT)cchRemaining);
  1050. //
  1051. // if we couldn't get the system directory, we'll just look for it on the path
  1052. //
  1053. if (unChars > cchRemaining || unChars == 0) {
  1054. unChars = 0;
  1055. }
  1056. pszEnd += unChars;
  1057. cchRemaining -= unChars;
  1058. if (unChars != 0) {
  1059. StringCchCopy(pszEnd, cchRemaining, TEXT("\\ahui.exe"));
  1060. } else {
  1061. StringCchCopy(pszEnd, cchRemaining, TEXT("ahui.exe"));
  1062. }
  1063. unChars = (UINT)_tcslen(pszEnd);
  1064. pszEnd += unChars;
  1065. cchRemaining -= unChars;
  1066. RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
  1067. RtlZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
  1068. StartupInfo.cb = sizeof(StartupInfo);
  1069. if (pAHInfo->tiExe != TAGID_NULL) {
  1070. //
  1071. // Figure out what the default return value should be
  1072. //
  1073. if (!SdbGUIDToString(&pAHInfo->guidDB, szGuid, CHARCOUNT(szGuid))) {
  1074. DBGPRINT((sdlError, "SdbShowApphelpDialog",
  1075. "Failed to convert guid to string.\n"));
  1076. goto cleanup;
  1077. }
  1078. StringCchPrintfEx(pszEnd,
  1079. cchRemaining,
  1080. &pszEnd,
  1081. &cchRemaining,
  1082. 0,
  1083. TEXT(" %s 0x%lX"),
  1084. szGuid,
  1085. pAHInfo->tiExe);
  1086. } else {
  1087. if (!pAHInfo->dwHtmlHelpID) {
  1088. DBGPRINT((sdlError, "SdbShowApphelpDialog",
  1089. "Neither HTMLHELPID nor tiExe provided\n"));
  1090. goto cleanup;
  1091. }
  1092. StringCchPrintfEx(pszEnd,
  1093. cchRemaining,
  1094. &pszEnd,
  1095. &cchRemaining,
  1096. 0,
  1097. TEXT(" /HTMLHELPID:0x%lx"),
  1098. pAHInfo->dwHtmlHelpID);
  1099. StringCchPrintfEx(pszEnd,
  1100. cchRemaining,
  1101. &pszEnd,
  1102. &cchRemaining,
  1103. 0,
  1104. TEXT(" /SEVERITY:0x%lx"),
  1105. pAHInfo->dwSeverity);
  1106. if (!SdbIsNullGUID(&pAHInfo->guidID)) {
  1107. if (SdbGUIDToString(&pAHInfo->guidID, szGuid, CHARCOUNT(szGuid))) {
  1108. StringCchPrintfEx(pszEnd,
  1109. cchRemaining,
  1110. &pszEnd,
  1111. &cchRemaining,
  1112. 0,
  1113. TEXT(" /GUID:%s"),
  1114. szGuid);
  1115. }
  1116. }
  1117. if (pAHInfo->lpszAppName != NULL) {
  1118. StringCchPrintfEx(pszEnd,
  1119. cchRemaining,
  1120. &pszEnd,
  1121. &cchRemaining,
  1122. 0,
  1123. TEXT(" /APPNAME:\"%s\""),
  1124. pAHInfo->lpszAppName);
  1125. }
  1126. }
  1127. if (pAHInfo->bPreserveChoice) {
  1128. StringCchPrintfEx(pszEnd,
  1129. cchRemaining,
  1130. &pszEnd,
  1131. &cchRemaining,
  1132. 0,
  1133. TEXT(" /PRESERVECHOICE"));
  1134. }
  1135. if (pAHInfo->bMSI) {
  1136. StringCchPrintfEx(pszEnd,
  1137. cchRemaining,
  1138. &pszEnd,
  1139. &cchRemaining,
  1140. 0,
  1141. TEXT(" /MSI"));
  1142. }
  1143. if (!CreateProcessW(NULL,
  1144. szCommandLine,
  1145. NULL,
  1146. NULL,
  1147. FALSE,
  1148. 0,
  1149. NULL,
  1150. NULL,
  1151. &StartupInfo, &ProcessInfo)) {
  1152. DBGPRINT((sdlError, "SdbShowApphelpDialog",
  1153. "Failed to launch apphelp process.\n"));
  1154. goto cleanup;
  1155. }
  1156. //
  1157. // check to see if they want to monitor the process themselves
  1158. //
  1159. if (phProcess) {
  1160. bReturn = TRUE;
  1161. pRunApp = NULL; // we do this so that we don't touch the bRunApp
  1162. *phProcess = ProcessInfo.hProcess;
  1163. goto cleanup;
  1164. }
  1165. //
  1166. // otherwise, we'll do the waiting.
  1167. //
  1168. WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
  1169. bReturn = GetExitCodeProcess(ProcessInfo.hProcess, &dwExit);
  1170. if (bReturn) {
  1171. bRunApp = (0 != dwExit);
  1172. }
  1173. cleanup:
  1174. if (bReturn && pRunApp != NULL) {
  1175. *pRunApp = bRunApp;
  1176. }
  1177. //
  1178. // process handle is to be closed only when phProcess is NULL
  1179. //
  1180. if (phProcess == NULL && ProcessInfo.hProcess) {
  1181. CloseHandle(ProcessInfo.hProcess);
  1182. }
  1183. if (ProcessInfo.hThread) {
  1184. CloseHandle(ProcessInfo.hThread);
  1185. }
  1186. return bReturn;
  1187. }