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.

1034 lines
27 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 msi installer information
  7. Author:
  8. vadimb created sometime in 2000
  9. Revision History:
  10. --*/
  11. #include "sdbp.h"
  12. /*++
  13. // Local function prototype
  14. //
  15. //
  16. --*/
  17. PDB
  18. SdbpGetNextMsiDatabase(
  19. IN HSDB hSDB,
  20. IN LPCTSTR lpszLocalDB,
  21. IN OUT PSDBMSIFINDINFO pFindInfo
  22. );
  23. TAGID
  24. SdbpFindPlatformMatch(
  25. IN HSDB hSDB,
  26. IN PDB pdb,
  27. IN TAGID tiMatch, // current match using the GUID index
  28. IN PSDBMSIFINDINFO pFindInfo
  29. )
  30. {
  31. TAGID tiRuntimePlatform;
  32. DWORD dwRuntimePlatform;
  33. LPCTSTR pszGuid = NULL;
  34. #ifndef WIN32A_MODE
  35. UNICODE_STRING ustrGUID = { 0 };
  36. NTSTATUS Status;
  37. #else
  38. TCHAR szGUID[64]; // guid is about 38 chars + 0
  39. #endif // WIN32A_MODE
  40. TAGID tiOSSKU;
  41. DWORD dwOSSKU;
  42. if (tiMatch != TAGID_NULL) {
  43. #ifndef WIN32A_MODE
  44. GUID_TO_UNICODE_STRING(&pFindInfo->guidID, &ustrGUID);
  45. pszGuid = ustrGUID.Buffer;
  46. #else // WIN32A_MODE
  47. GUID_TO_STRING(&pFindInfo->guidID, szGUID);
  48. pszGuid = szGUID;
  49. #endif // WIN32A_MODE
  50. }
  51. while (tiMatch != TAGID_NULL) {
  52. tiRuntimePlatform = SdbFindFirstTag(pdb, tiMatch, TAG_RUNTIME_PLATFORM);
  53. if (tiRuntimePlatform != TAGID_NULL) {
  54. dwRuntimePlatform = SdbReadDWORDTag(pdb, tiRuntimePlatform, RUNTIME_PLATFORM_ANY);
  55. //
  56. // Check for the platform match
  57. //
  58. if (!SdbpCheckRuntimePlatform(hSDB, pszGuid, dwRuntimePlatform)) {
  59. goto CheckNextMatch;
  60. }
  61. }
  62. // check for SKU match
  63. tiOSSKU = SdbFindFirstTag(pdb, tiMatch, TAG_OS_SKU);
  64. if (tiOSSKU != TAGID_NULL) {
  65. dwOSSKU = SdbReadDWORDTag(pdb, tiOSSKU, OS_SKU_ALL);
  66. if (dwOSSKU != OS_SKU_ALL) {
  67. PSDBCONTEXT pDBContext = (PSDBCONTEXT)hSDB;
  68. //
  69. // Check for the OS SKU match
  70. //
  71. if (!(dwOSSKU & pDBContext->dwOSSKU)) {
  72. DBGPRINT((sdlInfo,
  73. "SdbpCheckExe",
  74. "MSI OS SKU Mismatch %s Database(0x%lx) vs 0x%lx\n",
  75. (pszGuid ? pszGuid : TEXT("Unknown")),
  76. dwOSSKU,
  77. pDBContext->dwOSSKU));
  78. goto CheckNextMatch;
  79. }
  80. }
  81. }
  82. break; // if we are here -- both sku and platform match
  83. CheckNextMatch:
  84. tiMatch = SdbFindNextGUIDIndexedTag(pdb, &pFindInfo->sdbFindInfo);
  85. }
  86. #ifndef WIN32A_MODE
  87. FREE_GUID_STRING(&ustrGUID);
  88. #endif // WIN32A_MODE
  89. return tiMatch;
  90. }
  91. TAGREF
  92. SDBAPI
  93. SdbpFindFirstMsiMatch(
  94. IN HSDB hSDB,
  95. IN LPCTSTR lpszLocalDB,
  96. OUT PSDBMSIFINDINFO pFindInfo
  97. )
  98. /*++
  99. Return: TAGREF of a matching MSI transform in whatever database we have found to be valid
  100. the state of the search is updated (pFindInfo->sdbLookupState) or TAGREF_NULL if
  101. there were no matches in any of the remaining databases
  102. Desc: When this function is called first, the state is set to LOOKUP_NONE - the local
  103. db is up for lookup first, followed by arbitrary number of other lookup states.
  104. --*/
  105. {
  106. TAGREF trMatch = TAGREF_NULL;
  107. TAGID tiMatch = TAGID_NULL;
  108. PDB pdb;
  109. do {
  110. //
  111. // If we have a database to look into first, use it, otherwise grab the
  112. // next database from the list of things we use.
  113. //
  114. pdb = SdbpGetNextMsiDatabase(hSDB, lpszLocalDB, pFindInfo);
  115. //
  116. // There is no database for us to look at - get out
  117. //
  118. if (pdb == NULL) {
  119. //
  120. // All options are out -- get out now
  121. //
  122. break;
  123. }
  124. tiMatch = SdbFindFirstGUIDIndexedTag(pdb,
  125. TAG_MSI_PACKAGE,
  126. TAG_MSI_PACKAGE_ID,
  127. &pFindInfo->guidID,
  128. &pFindInfo->sdbFindInfo);
  129. //
  130. // Skip entries that do not match our runtime platform
  131. //
  132. tiMatch = SdbpFindPlatformMatch(hSDB, pdb, tiMatch, pFindInfo);
  133. } while (tiMatch == TAGID_NULL);
  134. if (tiMatch != TAGID_NULL) {
  135. //
  136. // We have a match if we are here, state information is stored in pFindInfo with
  137. // sdbLookupState containing the NEXT search state for us to feast on.
  138. //
  139. if (!SdbTagIDToTagRef(hSDB, pdb, tiMatch, &trMatch)) {
  140. DBGPRINT((sdlError,
  141. "SdbpFindFirstMsiMatch",
  142. "Failed to convert tagid 0x%x to tagref\n",
  143. tiMatch));
  144. return TAGREF_NULL;
  145. }
  146. }
  147. return trMatch;
  148. }
  149. TAGREF
  150. SDBAPI
  151. SdbpFindNextMsiMatch(
  152. IN HSDB hSDB,
  153. IN PDB pdb,
  154. OUT PSDBMSIFINDINFO pFindInfo
  155. )
  156. {
  157. TAGREF trMatch = TAGREF_NULL;
  158. TAGID tiMatch = TAGID_NULL;
  159. tiMatch = SdbFindNextGUIDIndexedTag(pdb, &pFindInfo->sdbFindInfo);
  160. if (tiMatch == TAGID_NULL) {
  161. return TAGREF_NULL;
  162. }
  163. tiMatch = SdbpFindPlatformMatch(hSDB, pdb, tiMatch, pFindInfo);
  164. if (tiMatch == TAGID_NULL) {
  165. return TAGREF_NULL;
  166. }
  167. if (!SdbTagIDToTagRef(hSDB, pdb, tiMatch, &trMatch)) {
  168. DBGPRINT((sdlError,
  169. "SdbpFindFirstMsiMatch",
  170. "Failed to convert tagid 0x%x to tagref\n",
  171. tiMatch));
  172. return TAGREF_NULL;
  173. }
  174. return trMatch;
  175. }
  176. TAGREF
  177. SDBAPI
  178. SdbFindFirstMsiPackage_Str(
  179. IN HSDB hSDB,
  180. IN LPCTSTR lpszGuid,
  181. IN LPCTSTR lpszLocalDB,
  182. OUT PSDBMSIFINDINFO pFindInfo
  183. )
  184. /*++
  185. Return: BUGBUG: ?
  186. Desc: BUGBUG: ?
  187. --*/
  188. {
  189. GUID guidID;
  190. if (!SdbGUIDFromString(lpszGuid, &guidID)) {
  191. DBGPRINT((sdlError,
  192. "SdbFindFirstMsiPackage_Str",
  193. "Failed to convert guid from string %s\n",
  194. lpszGuid));
  195. return TAGREF_NULL;
  196. }
  197. return SdbFindFirstMsiPackage(hSDB, &guidID, lpszLocalDB, pFindInfo);
  198. }
  199. //
  200. // The workings of MSI database search:
  201. //
  202. // 1. Function SdbpGetNextMsiDatabase returns the database corresponding to the
  203. // state stored in sdbLookupState
  204. // 2. Only non-null values are returned and the state is advanced to the next
  205. // valid value. For instance, if we were not able to open a local (supplied) database
  206. // we try main database - if that was a no-show, we try test db, if that is not available,
  207. // we try custom dbs
  208. // 3. When function returns NULL - it means that no more dbs are available for lookup
  209. PDB
  210. SdbpGetNextMsiDatabase(
  211. IN HSDB hSDB,
  212. IN LPCTSTR lpszLocalDB,
  213. IN OUT PSDBMSIFINDINFO pFindInfo
  214. )
  215. /*++
  216. Func: SdbpGetNextMsiDatabase
  217. Returns the next database to be looked at
  218. or NULL if no more databases are availalble
  219. Uses pFindInfo->sdbLookupState and updates it upon exit
  220. --*/
  221. {
  222. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  223. PDB pdbRet;
  224. LPTSTR pszGuid;
  225. SDBMSILOOKUPSTATE LookupState = LOOKUP_DONE;
  226. #ifndef WIN32A_MODE
  227. UNICODE_STRING ustrGUID = { 0 };
  228. NTSTATUS Status;
  229. #else
  230. TCHAR szGUID[64]; // guid is about 38 chars + 0
  231. #endif
  232. do {
  233. pdbRet = NULL;
  234. switch (pFindInfo->sdbLookupState) {
  235. case LOOKUP_DONE: // no next state
  236. break;
  237. case LOOKUP_NONE: // initial state, start with local db
  238. LookupState = LOOKUP_LOCAL;
  239. break;
  240. case LOOKUP_LOCAL:
  241. SdbCloseLocalDatabase(hSDB);
  242. if (lpszLocalDB != NULL) {
  243. if (!SdbOpenLocalDatabase(hSDB, lpszLocalDB)) {
  244. DBGPRINT((sdlWarning,
  245. "SdbpGetNextMsiDatabase",
  246. "Cannot open database \"%s\"\n",
  247. lpszLocalDB));
  248. } else {
  249. pdbRet = pContext->pdbLocal;
  250. }
  251. }
  252. LookupState = LOOKUP_CUSTOM;
  253. break;
  254. case LOOKUP_CUSTOM:
  255. #ifndef WIN32A_MODE
  256. Status = GUID_TO_UNICODE_STRING(&pFindInfo->guidID, &ustrGUID);
  257. if (!NT_SUCCESS(Status)) {
  258. DBGPRINT((sdlError,
  259. "SdbGetNextMsiDatabase",
  260. "Failed to convert guid to string, status 0x%lx\n",
  261. Status));
  262. break;
  263. }
  264. pszGuid = ustrGUID.Buffer;
  265. #else
  266. GUID_TO_STRING(&pFindInfo->guidID, szGUID);
  267. pszGuid = szGUID;
  268. #endif
  269. SdbCloseLocalDatabase(hSDB);
  270. if (SdbOpenNthLocalDatabase(hSDB, pszGuid, &pFindInfo->dwCustomIndex, FALSE)) {
  271. pdbRet = pContext->pdbLocal;
  272. //
  273. // The state does not change when we have a match
  274. //
  275. assert(pdbRet != NULL);
  276. } else {
  277. LookupState = LOOKUP_TEST;
  278. }
  279. break;
  280. case LOOKUP_TEST:
  281. pdbRet = pContext->pdbTest;
  282. //
  283. // Next one is custom
  284. //
  285. LookupState = LOOKUP_MAIN;
  286. break;
  287. case LOOKUP_MAIN:
  288. pdbRet = pContext->pdbMain;
  289. LookupState = LOOKUP_DONE;
  290. break;
  291. default:
  292. DBGPRINT((sdlError,
  293. "SdbGetNextMsiDatabase",
  294. "Unknown MSI Lookup State 0x%lx\n",
  295. pFindInfo->sdbLookupState));
  296. LookupState = LOOKUP_DONE;
  297. break;
  298. }
  299. pFindInfo->sdbLookupState = LookupState;
  300. } while (pdbRet == NULL && pFindInfo->sdbLookupState != LOOKUP_DONE);
  301. #ifndef WIN32A_MODE
  302. FREE_GUID_STRING(&ustrGUID);
  303. #endif
  304. return pdbRet;
  305. }
  306. TAGREF
  307. SDBAPI
  308. SdbFindFirstMsiPackage(
  309. IN HSDB hSDB, // HSDB context
  310. IN GUID* pGuidID, // GUID that we're looking for
  311. IN LPCTSTR lpszLocalDB, // optional path to local db, dos path style
  312. OUT PSDBMSIFINDINFO pFindInfo // pointer to our search context
  313. )
  314. /*++
  315. Return: BUGBUG: ?
  316. Desc: BUGBUG: ?
  317. --*/
  318. {
  319. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  320. LPTSTR pszGuid;
  321. //
  322. // Initialize MSI search structure
  323. //
  324. RtlZeroMemory(pFindInfo, sizeof(*pFindInfo));
  325. pFindInfo->guidID = *pGuidID; // store the guid ptr in the context
  326. pFindInfo->sdbLookupState = LOOKUP_NONE;
  327. pFindInfo->trMatch = SdbpFindFirstMsiMatch(hSDB, lpszLocalDB, pFindInfo);
  328. return pFindInfo->trMatch;
  329. }
  330. TAGREF
  331. SDBAPI
  332. SdbFindNextMsiPackage(
  333. IN HSDB hSDB,
  334. IN OUT PSDBMSIFINDINFO pFindInfo
  335. )
  336. /*++
  337. Return: BUGBUG: ?
  338. Desc: BUGBUG: ?
  339. --*/
  340. {
  341. PDB pdb = NULL;
  342. TAGID tiMatch;
  343. TAGREF trMatch = TAGREF_NULL;
  344. assert(hSDB != NULL && pFindInfo != NULL);
  345. if (pFindInfo->trMatch == TAGREF_NULL) {
  346. DBGPRINT((sdlError, "SdbFindNextMsiPackage", "No more matches\n"));
  347. return trMatch;
  348. }
  349. //
  350. // Take the last match and look in the same database
  351. //
  352. if (!SdbTagRefToTagID(hSDB, pFindInfo->trMatch, &pdb, &tiMatch)) {
  353. DBGPRINT((sdlError,
  354. "SdbFindNextMsiPackage",
  355. "Failed to convert tagref 0x%x to tagid\n",
  356. pFindInfo->trMatch));
  357. return trMatch;
  358. }
  359. //
  360. // Call to find the next match in this (current) database
  361. //
  362. trMatch = SdbpFindNextMsiMatch(hSDB, pdb, pFindInfo);
  363. if (trMatch != TAGREF_NULL) {
  364. pFindInfo->trMatch = trMatch;
  365. return trMatch;
  366. }
  367. //
  368. // So in this (current) database we have no further matches, look for the first match
  369. // in the next db
  370. //
  371. trMatch = SdbpFindFirstMsiMatch(hSDB, NULL, pFindInfo);
  372. //
  373. // We have found a match -- or not, store supplemental information and return.
  374. //
  375. pFindInfo->trMatch = trMatch;
  376. return trMatch;
  377. }
  378. DWORD
  379. SDBAPI
  380. SdbEnumMsiTransforms(
  381. IN HSDB hSDB,
  382. IN TAGREF trMatch,
  383. OUT TAGREF* ptrBuffer,
  384. IN OUT DWORD* pdwBufferSize
  385. )
  386. /*++
  387. Return: BUGBUG: ?
  388. Desc: Enumerate fixes for a given MSI package.
  389. --*/
  390. {
  391. TAGID tiMatch = TAGID_NULL;
  392. TAGID tiTransform;
  393. DWORD nTransforms = 0;
  394. DWORD dwError = ERROR_SUCCESS;
  395. PDB pdb;
  396. //
  397. // Get a list of transforms available for this entry
  398. //
  399. if (!SdbTagRefToTagID(hSDB, trMatch, &pdb, &tiMatch)) {
  400. DBGPRINT((sdlError,
  401. "SdbEnumerateMsiTransforms",
  402. "Failed to convert tagref 0x%x to tagid\n",
  403. trMatch));
  404. return ERROR_INTERNAL_DB_CORRUPTION;
  405. }
  406. if (ptrBuffer == NULL) {
  407. //
  408. // We should have the pdwBufferSize not NULL in this case.
  409. //
  410. if (pdwBufferSize == NULL) {
  411. DBGPRINT((sdlError,
  412. "SdbEnumerateMsiTransforms",
  413. "when ptrBuffer is not specified, pdwBufferSize should not be NULL\n"));
  414. return ERROR_INVALID_PARAMETER;
  415. }
  416. }
  417. //
  418. // Now start enumerating transforms. Count them first.
  419. //
  420. if (pdwBufferSize != NULL) {
  421. tiTransform = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_TRANSFORM_REF);
  422. while (tiTransform != TAGID_NULL) {
  423. nTransforms++;
  424. tiTransform = SdbFindNextTag(pdb, tiMatch, tiTransform);
  425. }
  426. //
  427. // Both buffer size and buffer specified, see if we fit in.
  428. //
  429. if (ptrBuffer == NULL || *pdwBufferSize < nTransforms * sizeof(TAGREF)) {
  430. *pdwBufferSize = nTransforms * sizeof(TAGREF);
  431. DBGPRINT((sdlInfo,
  432. "SdbEnumerateMsiTransforms",
  433. "Buffer specified is too small\n"));
  434. return ERROR_INSUFFICIENT_BUFFER;
  435. }
  436. }
  437. //
  438. // Now we have counted them all and either the buffer size is not supplied
  439. // or it has enough room, do it again now
  440. // The only case when we are here is ptrBuffer != NULL
  441. //
  442. assert(ptrBuffer != NULL);
  443. __try {
  444. tiTransform = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_TRANSFORM_REF);
  445. while (tiTransform != TAGID_NULL) {
  446. if (!SdbTagIDToTagRef(hSDB, pdb, tiTransform, ptrBuffer)) {
  447. DBGPRINT((sdlError,
  448. "SdbEnumerateMsiTransforms",
  449. "Failed to convert tagid 0x%x to tagref\n",
  450. tiTransform));
  451. return ERROR_INTERNAL_DB_CORRUPTION;
  452. }
  453. //
  454. // Advance the pointer
  455. //
  456. ++ptrBuffer;
  457. //
  458. // Lookup next transform
  459. //
  460. tiTransform = SdbFindNextTag(pdb, tiMatch, tiTransform);
  461. }
  462. if (pdwBufferSize != NULL) {
  463. *pdwBufferSize = nTransforms * sizeof(TAGREF);
  464. }
  465. } __except(EXCEPTION_EXECUTE_HANDLER) {
  466. dwError = ERROR_INVALID_DATA;
  467. }
  468. return dwError;
  469. }
  470. BOOL
  471. SDBAPI
  472. SdbReadMsiTransformInfo(
  473. IN HSDB hSDB,
  474. IN TAGREF trTransformRef,
  475. OUT PSDBMSITRANSFORMINFO pTransformInfo
  476. )
  477. /*++
  478. Return: BUGBUG: ?
  479. Desc: BUGBUG: ?
  480. --*/
  481. {
  482. TAGID tiTransformRef = TAGID_NULL;
  483. TAGID tiName = TAGID_NULL;
  484. TAGID tiFile = TAGID_NULL;
  485. PDB pdb = NULL;
  486. TAGREF trTransform = TAGREF_NULL;
  487. TAGREF trFileTag = TAGREF_NULL;
  488. TAGREF trFile = TAGREF_NULL;
  489. TAGREF trFileName = TAGREF_NULL;
  490. DWORD dwLength;
  491. LPTSTR pszFileName = NULL;
  492. RtlZeroMemory(pTransformInfo, sizeof(*pTransformInfo));
  493. if (!SdbTagRefToTagID(hSDB, trTransformRef, &pdb, &tiTransformRef)) {
  494. DBGPRINT((sdlError,
  495. "SdbReadMsiTransformInfo",
  496. "Failed to convert tagref 0x%lx to tagid\n",
  497. trTransformRef));
  498. return FALSE;
  499. }
  500. if (SdbGetTagFromTagID(pdb, tiTransformRef) != TAG_MSI_TRANSFORM_REF) {
  501. DBGPRINT((sdlError,
  502. "SdbReadMsiTransformInfo",
  503. "Bad Transform reference 0x%lx\n",
  504. trTransformRef));
  505. return FALSE;
  506. }
  507. //
  508. // First find the name.
  509. //
  510. tiName = SdbFindFirstTag(pdb, tiTransformRef, TAG_NAME);
  511. if (tiName) {
  512. pTransformInfo->lpszTransformName = SdbGetStringTagPtr(pdb, tiName);
  513. }
  514. //
  515. // Then locate the transform itself.
  516. //
  517. trTransform = SdbGetItemFromItemRef(hSDB,
  518. trTransformRef,
  519. TAG_NAME,
  520. TAG_MSI_TRANSFORM_TAGID,
  521. TAG_MSI_TRANSFORM);
  522. if (trTransform == TAGREF_NULL) {
  523. //
  524. // We can't do it, return TRUE however.
  525. // Reason: Caller will have the name of the transform
  526. // and should know what to do.
  527. //
  528. return TRUE;
  529. }
  530. pTransformInfo->trTransform = trTransform;
  531. //
  532. // Now that we have the transform entry get the description and the bits.
  533. //
  534. trFileTag = SdbFindFirstTagRef(hSDB, trTransform, TAG_MSI_TRANSFORM_TAGID);
  535. if (trFileTag != TAGREF_NULL) {
  536. //
  537. // Read the reference to an actual file within this db
  538. //
  539. tiFile = SdbReadDWORDTagRef(hSDB, trFileTag, (DWORD)TAGID_NULL);
  540. //
  541. // If we attained the tiFile - note that it is an id within
  542. // the current database, so make a trFile out of it.
  543. //
  544. if (tiFile) {
  545. if (!SdbTagIDToTagRef(hSDB, pdb, tiFile, &trFile)) {
  546. DBGPRINT((sdlError,
  547. "SdbReadMsiTransformInfo",
  548. "Failed to convert File tag to tagref 0x%lx\n",
  549. tiFile));
  550. trFile = TAGREF_NULL;
  551. }
  552. }
  553. }
  554. if (trFile == TAGREF_NULL) {
  555. //
  556. // We wil have to look by (file) name.
  557. //
  558. trFileName = SdbFindFirstTagRef(hSDB, trTransform, TAG_MSI_TRANSFORM_FILE);
  559. if (trFileName == TAGREF_NULL) {
  560. DBGPRINT((sdlError,
  561. "SdbReadMsiTransformInfo",
  562. "Failed to get MSI Transform for tag 0x%x\n",
  563. trTransform));
  564. return FALSE;
  565. }
  566. dwLength = SdbpGetStringRefLength(hSDB, trFileName);
  567. STACK_ALLOC(pszFileName, (dwLength + 1) * sizeof(TCHAR));
  568. if (pszFileName == NULL) {
  569. DBGPRINT((sdlError,
  570. "SdbReadMsiTransformInfo",
  571. "Failed to allocate buffer for %ld characters tag 0x%lx\n",
  572. dwLength,
  573. trFileName));
  574. return FALSE;
  575. }
  576. //
  577. // Now read the filename.
  578. //
  579. if (!SdbReadStringTagRef(hSDB, trFileName, pszFileName, dwLength + 1)) {
  580. DBGPRINT((sdlError,
  581. "SdbReadMsiTransformInfo",
  582. "Failed to read filename string tag, length %d characters, tag 0x%x\n",
  583. dwLength,
  584. trFileName));
  585. STACK_FREE(pszFileName);
  586. return FALSE;
  587. }
  588. //
  589. // Locate the transform in the library (of the current file first, if
  590. // not found -- in the main db then).
  591. //
  592. trFile = SdbpGetLibraryFile(pdb, pszFileName);
  593. if (trFile == TAGREF_NULL) {
  594. trFile = SdbpGetMainLibraryFile(hSDB, pszFileName);
  595. }
  596. STACK_FREE(pszFileName);
  597. }
  598. pTransformInfo->trFile = trFile;
  599. return TRUE;
  600. }
  601. BOOL
  602. SDBAPI
  603. SdbCreateMsiTransformFile(
  604. IN HSDB hSDB,
  605. IN LPCTSTR lpszFileName,
  606. OUT PSDBMSITRANSFORMINFO pTransformInfo
  607. )
  608. /*++
  609. Return: BUGBUG: ?
  610. Desc: BUGBUG: ?
  611. --*/
  612. {
  613. TAGREF trBits;
  614. DWORD dwSize;
  615. PBYTE pBuffer = NULL;
  616. BOOL bSuccess = FALSE;
  617. if (pTransformInfo->trFile == TAGREF_NULL) {
  618. DBGPRINT((sdlError,
  619. "SdbCreateMsiTransformFile",
  620. "File for transform \"%s\" was not found\n",
  621. pTransformInfo->lpszTransformName));
  622. goto out;
  623. }
  624. trBits = SdbFindFirstTagRef(hSDB, pTransformInfo->trFile, TAG_FILE_BITS);
  625. if (trBits == TAGREF_NULL) {
  626. DBGPRINT((sdlError,
  627. "SdbCreateMsiTransformFile",
  628. "File bits not found tag 0x%x\n",
  629. trBits));
  630. goto out;
  631. }
  632. dwSize = SdbpGetTagRefDataSize(hSDB, trBits);
  633. pBuffer = (PBYTE)SdbAlloc(dwSize);
  634. if (pBuffer == NULL) {
  635. DBGPRINT((sdlError,
  636. "SdbCreateMsiTransformFile",
  637. "Failed to allocate %d bytes.\n",
  638. dwSize));
  639. goto out;
  640. }
  641. //
  642. // Now read the DLL's bits.
  643. //
  644. if (!SdbpReadBinaryTagRef(hSDB, trBits, pBuffer, dwSize)) {
  645. DBGPRINT((sdlError,
  646. "SdbCreateMsiTransformFile",
  647. "Can't read transform bits.\n"));
  648. goto out;
  649. }
  650. if (!SdbpWriteBitsToFile(lpszFileName, pBuffer, dwSize)) {
  651. DBGPRINT((sdlError,
  652. "SdbCreateMsiTransformFile",
  653. "Can't write transform bits to disk.\n"));
  654. goto out;
  655. }
  656. bSuccess = TRUE;
  657. out:
  658. if (pBuffer != NULL) {
  659. SdbFree(pBuffer);
  660. }
  661. return bSuccess;
  662. }
  663. BOOL
  664. SDBAPI
  665. SdbGetMsiPackageInformation(
  666. IN HSDB hSDB,
  667. IN TAGREF trMatch,
  668. OUT PMSIPACKAGEINFO pPackageInfo
  669. )
  670. {
  671. PDB pdb = NULL;
  672. TAGID tiMatch;
  673. TAGID tiPackageID;
  674. TAGID tiExeID;
  675. TAGID tiApphelp;
  676. TAGID tiCustomAction;
  677. BOOL bSuccess;
  678. RtlZeroMemory(pPackageInfo, sizeof(*pPackageInfo));
  679. if (!SdbTagRefToTagID(hSDB, trMatch, &pdb, &tiMatch)) {
  680. DBGPRINT((sdlError,
  681. "SdbGetMsiPackageInformation",
  682. "Failed to convert tagref 0x%lx to tagid\n",
  683. trMatch));
  684. return FALSE;
  685. }
  686. //
  687. // Fill in important id's
  688. //
  689. if (!SdbGetDatabaseID(pdb, &pPackageInfo->guidDatabaseID)) {
  690. DBGPRINT((sdlError,
  691. "SdbGetMsiPackageInformation",
  692. "Failed to get database id, tagref 0x%lx\n",
  693. trMatch));
  694. return FALSE;
  695. }
  696. //
  697. // Retrieve match id (unique one)
  698. //
  699. tiPackageID = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_PACKAGE_ID);
  700. if (tiPackageID == TAGID_NULL) {
  701. DBGPRINT((sdlError,
  702. "SdbGetMsiPackageInformation",
  703. "Failed to get msi package id, tagref = 0x%lx\n",
  704. trMatch));
  705. return FALSE;
  706. }
  707. bSuccess = SdbReadBinaryTag(pdb,
  708. tiPackageID,
  709. (PBYTE)&pPackageInfo->guidMsiPackageID,
  710. sizeof(pPackageInfo->guidMsiPackageID));
  711. if (!bSuccess) {
  712. DBGPRINT((sdlError,
  713. "SdbGetMsiPackageInformation",
  714. "Failed to read MSI Package ID referenced by 0x%x\n",
  715. trMatch));
  716. return FALSE;
  717. }
  718. tiExeID = SdbFindFirstTag(pdb, tiMatch, TAG_EXE_ID);
  719. if (tiExeID == TAGID_NULL) {
  720. DBGPRINT((sdlError,
  721. "SdbGetMsiPackageInformation",
  722. "Failed to read TAG_EXE_ID for tagref 0x%x\n",
  723. trMatch));
  724. return FALSE;
  725. }
  726. bSuccess = SdbReadBinaryTag(pdb,
  727. tiExeID,
  728. (PBYTE)&pPackageInfo->guidID,
  729. sizeof(pPackageInfo->guidID));
  730. if (!bSuccess) {
  731. DBGPRINT((sdlError,
  732. "SdbGetMsiPackageInformation",
  733. "Failed to read EXE ID referenced by tagref 0x%x\n",
  734. trMatch));
  735. return FALSE;
  736. }
  737. //
  738. // Set the flags to indicate whether apphelp or shims are available for
  739. // this package
  740. // note that shims/layers might be set for the subordinate actions and not
  741. // for the package itself. If custom_action tag exists however -- we need to check
  742. // with the full api later.
  743. //
  744. tiApphelp = SdbFindFirstTag(pdb, tiMatch, TAG_APPHELP);
  745. if (tiApphelp != TAGID_NULL) {
  746. pPackageInfo->dwPackageFlags |= MSI_PACKAGE_HAS_APPHELP;
  747. }
  748. //
  749. // Check to see whether we have any shims/layers
  750. //
  751. tiCustomAction = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_CUSTOM_ACTION);
  752. if (tiCustomAction != TAGID_NULL) {
  753. pPackageInfo->dwPackageFlags |= MSI_PACKAGE_HAS_SHIMS;
  754. }
  755. return TRUE;
  756. }
  757. TAGREF
  758. SDBAPI
  759. SdbFindMsiPackageByID(
  760. IN HSDB hSDB,
  761. IN GUID* pguidID
  762. )
  763. {
  764. TAGID tiMatch;
  765. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  766. FIND_INFO FindInfo;
  767. TAGREF trMatch = TAGREF_NULL;
  768. //
  769. // We search only the LOCAL database in this case
  770. //
  771. tiMatch = SdbFindFirstGUIDIndexedTag(pContext->pdbLocal,
  772. TAG_MSI_PACKAGE,
  773. TAG_EXE_ID,
  774. pguidID,
  775. &FindInfo);
  776. if (tiMatch == TAGID_NULL) {
  777. return trMatch;
  778. }
  779. if (!SdbTagIDToTagRef(hSDB, pContext->pdbLocal, tiMatch, &trMatch)) {
  780. DBGPRINT((sdlError,
  781. "SdbFindMsiPackageByID",
  782. "Failed to convert tagid 0x%lx to tagref\n",
  783. tiMatch));
  784. }
  785. return trMatch;
  786. }
  787. TAGREF
  788. SDBAPI
  789. SdbFindCustomActionForPackage(
  790. IN HSDB hSDB,
  791. IN TAGREF trPackage,
  792. IN LPCTSTR lpszCustomAction
  793. )
  794. {
  795. PDB pdb = NULL;
  796. TAGID tiMatch = TAGID_NULL;
  797. TAGREF trReturn = TAGREF_NULL;
  798. TAGID tiCustomAction;
  799. if (!SdbTagRefToTagID(hSDB, trPackage, &pdb, &tiMatch)) {
  800. DBGPRINT((sdlError,
  801. "SdbFindCustomActionForPackage",
  802. "Failed to convert tagref 0x%lx to tagid\n",
  803. trPackage));
  804. return TAGREF_NULL;
  805. }
  806. //
  807. // Now, for this tiMatch look for a custom action
  808. //
  809. tiCustomAction = SdbFindFirstNamedTag(pdb,
  810. tiMatch,
  811. TAG_MSI_CUSTOM_ACTION,
  812. TAG_NAME,
  813. lpszCustomAction);
  814. if (tiCustomAction != TAGID_NULL) {
  815. if (!SdbTagIDToTagRef(hSDB, pdb, tiCustomAction, &trReturn)) {
  816. DBGPRINT((sdlError,
  817. "SdbFindCustomActionForPackage",
  818. "Failed to convert tagid 0x%lx to tagref\n",
  819. tiCustomAction));
  820. trReturn = TAGREF_NULL;
  821. }
  822. }
  823. return trReturn;
  824. }