windows-nt/Source/XPSP1/NT/windows/appcompat/sdbapi/msitransform.c
2020-09-26 16:20:57 +08:00

1035 lines
27 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
apphelp.c
Abstract:
This module implements high-level functions to access msi installer information
Author:
vadimb created sometime in 2000
Revision History:
--*/
#include "sdbp.h"
/*++
// Local function prototype
//
//
--*/
PDB
SdbpGetNextMsiDatabase(
IN HSDB hSDB,
IN LPCTSTR lpszLocalDB,
IN OUT PSDBMSIFINDINFO pFindInfo
);
TAGID
SdbpFindPlatformMatch(
IN HSDB hSDB,
IN PDB pdb,
IN TAGID tiMatch, // current match using the GUID index
IN PSDBMSIFINDINFO pFindInfo
)
{
TAGID tiRuntimePlatform;
DWORD dwRuntimePlatform;
LPCTSTR pszGuid = NULL;
#ifndef WIN32A_MODE
UNICODE_STRING ustrGUID = { 0 };
NTSTATUS Status;
#else
TCHAR szGUID[64]; // guid is about 38 chars + 0
#endif // WIN32A_MODE
TAGID tiOSSKU;
DWORD dwOSSKU;
if (tiMatch != TAGID_NULL) {
#ifndef WIN32A_MODE
GUID_TO_UNICODE_STRING(&pFindInfo->guidID, &ustrGUID);
pszGuid = ustrGUID.Buffer;
#else // WIN32A_MODE
GUID_TO_STRING(&pFindInfo->guidID, szGUID);
pszGuid = szGUID;
#endif // WIN32A_MODE
}
while (tiMatch != TAGID_NULL) {
tiRuntimePlatform = SdbFindFirstTag(pdb, tiMatch, TAG_RUNTIME_PLATFORM);
if (tiRuntimePlatform != TAGID_NULL) {
dwRuntimePlatform = SdbReadDWORDTag(pdb, tiRuntimePlatform, RUNTIME_PLATFORM_ANY);
//
// Check for the platform match
//
if (!SdbpCheckRuntimePlatform(hSDB, pszGuid, dwRuntimePlatform)) {
goto CheckNextMatch;
}
}
// check for SKU match
tiOSSKU = SdbFindFirstTag(pdb, tiMatch, TAG_OS_SKU);
if (tiOSSKU != TAGID_NULL) {
dwOSSKU = SdbReadDWORDTag(pdb, tiOSSKU, OS_SKU_ALL);
if (dwOSSKU != OS_SKU_ALL) {
PSDBCONTEXT pDBContext = (PSDBCONTEXT)hSDB;
//
// Check for the OS SKU match
//
if (!(dwOSSKU & pDBContext->dwOSSKU)) {
DBGPRINT((sdlInfo,
"SdbpCheckExe",
"MSI OS SKU Mismatch %s Database(0x%lx) vs 0x%lx\n",
(pszGuid ? pszGuid : TEXT("Unknown")),
dwOSSKU,
pDBContext->dwOSSKU));
goto CheckNextMatch;
}
}
}
break; // if we are here -- both sku and platform match
CheckNextMatch:
tiMatch = SdbFindNextGUIDIndexedTag(pdb, &pFindInfo->sdbFindInfo);
}
#ifndef WIN32A_MODE
FREE_GUID_STRING(&ustrGUID);
#endif // WIN32A_MODE
return tiMatch;
}
TAGREF
SDBAPI
SdbpFindFirstMsiMatch(
IN HSDB hSDB,
IN LPCTSTR lpszLocalDB,
OUT PSDBMSIFINDINFO pFindInfo
)
/*++
Return: TAGREF of a matching MSI transform in whatever database we have found to be valid
the state of the search is updated (pFindInfo->sdbLookupState) or TAGREF_NULL if
there were no matches in any of the remaining databases
Desc: When this function is called first, the state is set to LOOKUP_NONE - the local
db is up for lookup first, followed by arbitrary number of other lookup states.
--*/
{
TAGREF trMatch = TAGREF_NULL;
TAGID tiMatch = TAGID_NULL;
PDB pdb;
do {
//
// If we have a database to look into first, use it, otherwise grab the
// next database from the list of things we use.
//
pdb = SdbpGetNextMsiDatabase(hSDB, lpszLocalDB, pFindInfo);
//
// There is no database for us to look at - get out
//
if (pdb == NULL) {
//
// All options are out -- get out now
//
break;
}
tiMatch = SdbFindFirstGUIDIndexedTag(pdb,
TAG_MSI_PACKAGE,
TAG_MSI_PACKAGE_ID,
&pFindInfo->guidID,
&pFindInfo->sdbFindInfo);
//
// Skip entries that do not match our runtime platform
//
tiMatch = SdbpFindPlatformMatch(hSDB, pdb, tiMatch, pFindInfo);
} while (tiMatch == TAGID_NULL);
if (tiMatch != TAGID_NULL) {
//
// We have a match if we are here, state information is stored in pFindInfo with
// sdbLookupState containing the NEXT search state for us to feast on.
//
if (!SdbTagIDToTagRef(hSDB, pdb, tiMatch, &trMatch)) {
DBGPRINT((sdlError,
"SdbpFindFirstMsiMatch",
"Failed to convert tagid 0x%x to tagref\n",
tiMatch));
return TAGREF_NULL;
}
}
return trMatch;
}
TAGREF
SDBAPI
SdbpFindNextMsiMatch(
IN HSDB hSDB,
IN PDB pdb,
OUT PSDBMSIFINDINFO pFindInfo
)
{
TAGREF trMatch = TAGREF_NULL;
TAGID tiMatch = TAGID_NULL;
tiMatch = SdbFindNextGUIDIndexedTag(pdb, &pFindInfo->sdbFindInfo);
if (tiMatch == TAGID_NULL) {
return TAGREF_NULL;
}
tiMatch = SdbpFindPlatformMatch(hSDB, pdb, tiMatch, pFindInfo);
if (tiMatch == TAGID_NULL) {
return TAGREF_NULL;
}
if (!SdbTagIDToTagRef(hSDB, pdb, tiMatch, &trMatch)) {
DBGPRINT((sdlError,
"SdbpFindFirstMsiMatch",
"Failed to convert tagid 0x%x to tagref\n",
tiMatch));
return TAGREF_NULL;
}
return trMatch;
}
TAGREF
SDBAPI
SdbFindFirstMsiPackage_Str(
IN HSDB hSDB,
IN LPCTSTR lpszGuid,
IN LPCTSTR lpszLocalDB,
OUT PSDBMSIFINDINFO pFindInfo
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
GUID guidID;
if (!SdbGUIDFromString(lpszGuid, &guidID)) {
DBGPRINT((sdlError,
"SdbFindFirstMsiPackage_Str",
"Failed to convert guid from string %s\n",
lpszGuid));
return TAGREF_NULL;
}
return SdbFindFirstMsiPackage(hSDB, &guidID, lpszLocalDB, pFindInfo);
}
//
// The workings of MSI database search:
//
// 1. Function SdbpGetNextMsiDatabase returns the database corresponding to the
// state stored in sdbLookupState
// 2. Only non-null values are returned and the state is advanced to the next
// valid value. For instance, if we were not able to open a local (supplied) database
// we try main database - if that was a no-show, we try test db, if that is not available,
// we try custom dbs
// 3. When function returns NULL - it means that no more dbs are available for lookup
PDB
SdbpGetNextMsiDatabase(
IN HSDB hSDB,
IN LPCTSTR lpszLocalDB,
IN OUT PSDBMSIFINDINFO pFindInfo
)
/*++
Func: SdbpGetNextMsiDatabase
Returns the next database to be looked at
or NULL if no more databases are availalble
Uses pFindInfo->sdbLookupState and updates it upon exit
--*/
{
PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
PDB pdbRet;
LPTSTR pszGuid;
SDBMSILOOKUPSTATE LookupState = LOOKUP_DONE;
#ifndef WIN32A_MODE
UNICODE_STRING ustrGUID = { 0 };
NTSTATUS Status;
#else
TCHAR szGUID[64]; // guid is about 38 chars + 0
#endif
do {
pdbRet = NULL;
switch (pFindInfo->sdbLookupState) {
case LOOKUP_DONE: // no next state
break;
case LOOKUP_NONE: // initial state, start with local db
LookupState = LOOKUP_LOCAL;
break;
case LOOKUP_LOCAL:
SdbCloseLocalDatabase(hSDB);
if (lpszLocalDB != NULL) {
if (!SdbOpenLocalDatabase(hSDB, lpszLocalDB)) {
DBGPRINT((sdlWarning,
"SdbpGetNextMsiDatabase",
"Cannot open database \"%s\"\n",
lpszLocalDB));
} else {
pdbRet = pContext->pdbLocal;
}
}
LookupState = LOOKUP_CUSTOM;
break;
case LOOKUP_CUSTOM:
#ifndef WIN32A_MODE
Status = GUID_TO_UNICODE_STRING(&pFindInfo->guidID, &ustrGUID);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbGetNextMsiDatabase",
"Failed to convert guid to string, status 0x%lx\n",
Status));
break;
}
pszGuid = ustrGUID.Buffer;
#else
GUID_TO_STRING(&pFindInfo->guidID, szGUID);
pszGuid = szGUID;
#endif
SdbCloseLocalDatabase(hSDB);
if (SdbOpenNthLocalDatabase(hSDB, pszGuid, &pFindInfo->dwCustomIndex, FALSE)) {
pdbRet = pContext->pdbLocal;
//
// The state does not change when we have a match
//
assert(pdbRet != NULL);
} else {
LookupState = LOOKUP_TEST;
}
break;
case LOOKUP_TEST:
pdbRet = pContext->pdbTest;
//
// Next one is custom
//
LookupState = LOOKUP_MAIN;
break;
case LOOKUP_MAIN:
pdbRet = pContext->pdbMain;
LookupState = LOOKUP_DONE;
break;
default:
DBGPRINT((sdlError,
"SdbGetNextMsiDatabase",
"Unknown MSI Lookup State 0x%lx\n",
pFindInfo->sdbLookupState));
LookupState = LOOKUP_DONE;
break;
}
pFindInfo->sdbLookupState = LookupState;
} while (pdbRet == NULL && pFindInfo->sdbLookupState != LOOKUP_DONE);
#ifndef WIN32A_MODE
FREE_GUID_STRING(&ustrGUID);
#endif
return pdbRet;
}
TAGREF
SDBAPI
SdbFindFirstMsiPackage(
IN HSDB hSDB, // HSDB context
IN GUID* pGuidID, // GUID that we're looking for
IN LPCTSTR lpszLocalDB, // optional path to local db, dos path style
OUT PSDBMSIFINDINFO pFindInfo // pointer to our search context
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
LPTSTR pszGuid;
//
// Initialize MSI search structure
//
RtlZeroMemory(pFindInfo, sizeof(*pFindInfo));
pFindInfo->guidID = *pGuidID; // store the guid ptr in the context
pFindInfo->sdbLookupState = LOOKUP_NONE;
pFindInfo->trMatch = SdbpFindFirstMsiMatch(hSDB, lpszLocalDB, pFindInfo);
return pFindInfo->trMatch;
}
TAGREF
SDBAPI
SdbFindNextMsiPackage(
IN HSDB hSDB,
IN OUT PSDBMSIFINDINFO pFindInfo
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
PDB pdb = NULL;
TAGID tiMatch;
TAGREF trMatch = TAGREF_NULL;
assert(hSDB != NULL && pFindInfo != NULL);
if (pFindInfo->trMatch == TAGREF_NULL) {
DBGPRINT((sdlError, "SdbFindNextMsiPackage", "No more matches\n"));
return trMatch;
}
//
// Take the last match and look in the same database
//
if (!SdbTagRefToTagID(hSDB, pFindInfo->trMatch, &pdb, &tiMatch)) {
DBGPRINT((sdlError,
"SdbFindNextMsiPackage",
"Failed to convert tagref 0x%x to tagid\n",
pFindInfo->trMatch));
return trMatch;
}
//
// Call to find the next match in this (current) database
//
trMatch = SdbpFindNextMsiMatch(hSDB, pdb, pFindInfo);
if (trMatch != TAGREF_NULL) {
pFindInfo->trMatch = trMatch;
return trMatch;
}
//
// So in this (current) database we have no further matches, look for the first match
// in the next db
//
trMatch = SdbpFindFirstMsiMatch(hSDB, NULL, pFindInfo);
//
// We have found a match -- or not, store supplemental information and return.
//
pFindInfo->trMatch = trMatch;
return trMatch;
}
DWORD
SDBAPI
SdbEnumMsiTransforms(
IN HSDB hSDB,
IN TAGREF trMatch,
OUT TAGREF* ptrBuffer,
IN OUT DWORD* pdwBufferSize
)
/*++
Return: BUGBUG: ?
Desc: Enumerate fixes for a given MSI package.
--*/
{
TAGID tiMatch = TAGID_NULL;
TAGID tiTransform;
DWORD nTransforms = 0;
DWORD dwError = ERROR_SUCCESS;
PDB pdb;
//
// Get a list of transforms available for this entry
//
if (!SdbTagRefToTagID(hSDB, trMatch, &pdb, &tiMatch)) {
DBGPRINT((sdlError,
"SdbEnumerateMsiTransforms",
"Failed to convert tagref 0x%x to tagid\n",
trMatch));
return ERROR_INTERNAL_DB_CORRUPTION;
}
if (ptrBuffer == NULL) {
//
// We should have the pdwBufferSize not NULL in this case.
//
if (pdwBufferSize == NULL) {
DBGPRINT((sdlError,
"SdbEnumerateMsiTransforms",
"when ptrBuffer is not specified, pdwBufferSize should not be NULL\n"));
return ERROR_INVALID_PARAMETER;
}
}
//
// Now start enumerating transforms. Count them first.
//
if (pdwBufferSize != NULL) {
tiTransform = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_TRANSFORM_REF);
while (tiTransform != TAGID_NULL) {
nTransforms++;
tiTransform = SdbFindNextTag(pdb, tiMatch, tiTransform);
}
//
// Both buffer size and buffer specified, see if we fit in.
//
if (ptrBuffer == NULL || *pdwBufferSize < nTransforms * sizeof(TAGREF)) {
*pdwBufferSize = nTransforms * sizeof(TAGREF);
DBGPRINT((sdlInfo,
"SdbEnumerateMsiTransforms",
"Buffer specified is too small\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
}
//
// Now we have counted them all and either the buffer size is not supplied
// or it has enough room, do it again now
// The only case when we are here is ptrBuffer != NULL
//
assert(ptrBuffer != NULL);
__try {
tiTransform = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_TRANSFORM_REF);
while (tiTransform != TAGID_NULL) {
if (!SdbTagIDToTagRef(hSDB, pdb, tiTransform, ptrBuffer)) {
DBGPRINT((sdlError,
"SdbEnumerateMsiTransforms",
"Failed to convert tagid 0x%x to tagref\n",
tiTransform));
return ERROR_INTERNAL_DB_CORRUPTION;
}
//
// Advance the pointer
//
++ptrBuffer;
//
// Lookup next transform
//
tiTransform = SdbFindNextTag(pdb, tiMatch, tiTransform);
}
if (pdwBufferSize != NULL) {
*pdwBufferSize = nTransforms * sizeof(TAGREF);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_DATA;
}
return dwError;
}
BOOL
SDBAPI
SdbReadMsiTransformInfo(
IN HSDB hSDB,
IN TAGREF trTransformRef,
OUT PSDBMSITRANSFORMINFO pTransformInfo
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
TAGID tiTransformRef = TAGID_NULL;
TAGID tiName = TAGID_NULL;
TAGID tiFile = TAGID_NULL;
PDB pdb = NULL;
TAGREF trTransform = TAGREF_NULL;
TAGREF trFileTag = TAGREF_NULL;
TAGREF trFile = TAGREF_NULL;
TAGREF trFileName = TAGREF_NULL;
DWORD dwLength;
LPTSTR pszFileName = NULL;
RtlZeroMemory(pTransformInfo, sizeof(*pTransformInfo));
if (!SdbTagRefToTagID(hSDB, trTransformRef, &pdb, &tiTransformRef)) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Failed to convert tagref 0x%lx to tagid\n",
trTransformRef));
return FALSE;
}
if (SdbGetTagFromTagID(pdb, tiTransformRef) != TAG_MSI_TRANSFORM_REF) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Bad Transform reference 0x%lx\n",
trTransformRef));
return FALSE;
}
//
// First find the name.
//
tiName = SdbFindFirstTag(pdb, tiTransformRef, TAG_NAME);
if (tiName) {
pTransformInfo->lpszTransformName = SdbGetStringTagPtr(pdb, tiName);
}
//
// Then locate the transform itself.
//
trTransform = SdbGetItemFromItemRef(hSDB,
trTransformRef,
TAG_NAME,
TAG_MSI_TRANSFORM_TAGID,
TAG_MSI_TRANSFORM);
if (trTransform == TAGREF_NULL) {
//
// We can't do it, return TRUE however.
// Reason: Caller will have the name of the transform
// and should know what to do.
//
return TRUE;
}
pTransformInfo->trTransform = trTransform;
//
// Now that we have the transform entry get the description and the bits.
//
trFileTag = SdbFindFirstTagRef(hSDB, trTransform, TAG_MSI_TRANSFORM_TAGID);
if (trFileTag != TAGREF_NULL) {
//
// Read the reference to an actual file within this db
//
tiFile = SdbReadDWORDTagRef(hSDB, trFileTag, (DWORD)TAGID_NULL);
//
// If we attained the tiFile - note that it is an id within
// the current database, so make a trFile out of it.
//
if (tiFile) {
if (!SdbTagIDToTagRef(hSDB, pdb, tiFile, &trFile)) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Failed to convert File tag to tagref 0x%lx\n",
tiFile));
trFile = TAGREF_NULL;
}
}
}
if (trFile == TAGREF_NULL) {
//
// We wil have to look by (file) name.
//
trFileName = SdbFindFirstTagRef(hSDB, trTransform, TAG_MSI_TRANSFORM_FILE);
if (trFileName == TAGREF_NULL) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Failed to get MSI Transform for tag 0x%x\n",
trTransform));
return FALSE;
}
dwLength = SdbpGetStringRefLength(hSDB, trFileName);
STACK_ALLOC(pszFileName, (dwLength + 1) * sizeof(TCHAR));
if (pszFileName == NULL) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Failed to allocate buffer for %ld characters tag 0x%lx\n",
dwLength,
trFileName));
return FALSE;
}
//
// Now read the filename.
//
if (!SdbReadStringTagRef(hSDB, trFileName, pszFileName, dwLength + 1)) {
DBGPRINT((sdlError,
"SdbReadMsiTransformInfo",
"Failed to read filename string tag, length %d characters, tag 0x%x\n",
dwLength,
trFileName));
STACK_FREE(pszFileName);
return FALSE;
}
//
// Locate the transform in the library (of the current file first, if
// not found -- in the main db then).
//
trFile = SdbpGetLibraryFile(pdb, pszFileName);
if (trFile == TAGREF_NULL) {
trFile = SdbpGetMainLibraryFile(hSDB, pszFileName);
}
STACK_FREE(pszFileName);
}
pTransformInfo->trFile = trFile;
return TRUE;
}
BOOL
SDBAPI
SdbCreateMsiTransformFile(
IN HSDB hSDB,
IN LPCTSTR lpszFileName,
OUT PSDBMSITRANSFORMINFO pTransformInfo
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
TAGREF trBits;
DWORD dwSize;
PBYTE pBuffer = NULL;
BOOL bSuccess = FALSE;
if (pTransformInfo->trFile == TAGREF_NULL) {
DBGPRINT((sdlError,
"SdbCreateMsiTransformFile",
"File for transform \"%s\" was not found\n",
pTransformInfo->lpszTransformName));
goto out;
}
trBits = SdbFindFirstTagRef(hSDB, pTransformInfo->trFile, TAG_FILE_BITS);
if (trBits == TAGREF_NULL) {
DBGPRINT((sdlError,
"SdbCreateMsiTransformFile",
"File bits not found tag 0x%x\n",
trBits));
goto out;
}
dwSize = SdbpGetTagRefDataSize(hSDB, trBits);
pBuffer = (PBYTE)SdbAlloc(dwSize);
if (pBuffer == NULL) {
DBGPRINT((sdlError,
"SdbCreateMsiTransformFile",
"Failed to allocate %d bytes.\n",
dwSize));
goto out;
}
//
// Now read the DLL's bits.
//
if (!SdbpReadBinaryTagRef(hSDB, trBits, pBuffer, dwSize)) {
DBGPRINT((sdlError,
"SdbCreateMsiTransformFile",
"Can't read transform bits.\n"));
goto out;
}
if (!SdbpWriteBitsToFile(lpszFileName, pBuffer, dwSize)) {
DBGPRINT((sdlError,
"SdbCreateMsiTransformFile",
"Can't write transform bits to disk.\n"));
goto out;
}
bSuccess = TRUE;
out:
if (pBuffer != NULL) {
SdbFree(pBuffer);
}
return bSuccess;
}
BOOL
SDBAPI
SdbGetMsiPackageInformation(
IN HSDB hSDB,
IN TAGREF trMatch,
OUT PMSIPACKAGEINFO pPackageInfo
)
{
PDB pdb = NULL;
TAGID tiMatch;
TAGID tiPackageID;
TAGID tiExeID;
TAGID tiApphelp;
TAGID tiCustomAction;
BOOL bSuccess;
RtlZeroMemory(pPackageInfo, sizeof(*pPackageInfo));
if (!SdbTagRefToTagID(hSDB, trMatch, &pdb, &tiMatch)) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to convert tagref 0x%lx to tagid\n",
trMatch));
return FALSE;
}
//
// Fill in important id's
//
if (!SdbGetDatabaseID(pdb, &pPackageInfo->guidDatabaseID)) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to get database id, tagref 0x%lx\n",
trMatch));
return FALSE;
}
//
// Retrieve match id (unique one)
//
tiPackageID = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_PACKAGE_ID);
if (tiPackageID == TAGID_NULL) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to get msi package id, tagref = 0x%lx\n",
trMatch));
return FALSE;
}
bSuccess = SdbReadBinaryTag(pdb,
tiPackageID,
(PBYTE)&pPackageInfo->guidMsiPackageID,
sizeof(pPackageInfo->guidMsiPackageID));
if (!bSuccess) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to read MSI Package ID referenced by 0x%x\n",
trMatch));
return FALSE;
}
tiExeID = SdbFindFirstTag(pdb, tiMatch, TAG_EXE_ID);
if (tiExeID == TAGID_NULL) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to read TAG_EXE_ID for tagref 0x%x\n",
trMatch));
return FALSE;
}
bSuccess = SdbReadBinaryTag(pdb,
tiExeID,
(PBYTE)&pPackageInfo->guidID,
sizeof(pPackageInfo->guidID));
if (!bSuccess) {
DBGPRINT((sdlError,
"SdbGetMsiPackageInformation",
"Failed to read EXE ID referenced by tagref 0x%x\n",
trMatch));
return FALSE;
}
//
// Set the flags to indicate whether apphelp or shims are available for
// this package
// note that shims/layers might be set for the subordinate actions and not
// for the package itself. If custom_action tag exists however -- we need to check
// with the full api later.
//
tiApphelp = SdbFindFirstTag(pdb, tiMatch, TAG_APPHELP);
if (tiApphelp != TAGID_NULL) {
pPackageInfo->dwPackageFlags |= MSI_PACKAGE_HAS_APPHELP;
}
//
// Check to see whether we have any shims/layers
//
tiCustomAction = SdbFindFirstTag(pdb, tiMatch, TAG_MSI_CUSTOM_ACTION);
if (tiCustomAction != TAGID_NULL) {
pPackageInfo->dwPackageFlags |= MSI_PACKAGE_HAS_SHIMS;
}
return TRUE;
}
TAGREF
SDBAPI
SdbFindMsiPackageByID(
IN HSDB hSDB,
IN GUID* pguidID
)
{
TAGID tiMatch;
PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
FIND_INFO FindInfo;
TAGREF trMatch = TAGREF_NULL;
//
// We search only the LOCAL database in this case
//
tiMatch = SdbFindFirstGUIDIndexedTag(pContext->pdbLocal,
TAG_MSI_PACKAGE,
TAG_EXE_ID,
pguidID,
&FindInfo);
if (tiMatch == TAGID_NULL) {
return trMatch;
}
if (!SdbTagIDToTagRef(hSDB, pContext->pdbLocal, tiMatch, &trMatch)) {
DBGPRINT((sdlError,
"SdbFindMsiPackageByID",
"Failed to convert tagid 0x%lx to tagref\n",
tiMatch));
}
return trMatch;
}
TAGREF
SDBAPI
SdbFindCustomActionForPackage(
IN HSDB hSDB,
IN TAGREF trPackage,
IN LPCTSTR lpszCustomAction
)
{
PDB pdb = NULL;
TAGID tiMatch = TAGID_NULL;
TAGREF trReturn = TAGREF_NULL;
TAGID tiCustomAction;
if (!SdbTagRefToTagID(hSDB, trPackage, &pdb, &tiMatch)) {
DBGPRINT((sdlError,
"SdbFindCustomActionForPackage",
"Failed to convert tagref 0x%lx to tagid\n",
trPackage));
return TAGREF_NULL;
}
//
// Now, for this tiMatch look for a custom action
//
tiCustomAction = SdbFindFirstNamedTag(pdb,
tiMatch,
TAG_MSI_CUSTOM_ACTION,
TAG_NAME,
lpszCustomAction);
if (tiCustomAction != TAGID_NULL) {
if (!SdbTagIDToTagRef(hSDB, pdb, tiCustomAction, &trReturn)) {
DBGPRINT((sdlError,
"SdbFindCustomActionForPackage",
"Failed to convert tagid 0x%lx to tagref\n",
tiCustomAction));
trReturn = TAGREF_NULL;
}
}
return trReturn;
}