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.
463 lines
15 KiB
463 lines
15 KiB
#include "stdinc.h"
|
|
#include "macros.h"
|
|
|
|
#include <msi.h>
|
|
#include <msiquery.h>
|
|
|
|
#include "common.h"
|
|
|
|
HRESULT MSI_GetInstallerState(const MSIHANDLE & hInstall, enum CA_MIGRATION_MSI_INSTALL_MODE &fmode)
|
|
{
|
|
WCHAR szbuf[MAX_PATH];
|
|
DWORD cchbuf = NUMBER_OF(szbuf);
|
|
HRESULT hr = S_OK;
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiGetPropertyW(hInstall, L"REMOVE", szbuf, &cchbuf));
|
|
if (cchbuf != 0) // remove mode
|
|
fmode = eRemoveProduct;
|
|
else
|
|
fmode = eInstallProduct;
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
VOID ResetCallbackInfo(CA_ENM_ASSEMBLY_CALLBACK_INFO &info)
|
|
{
|
|
info.pszComponentID = NULL;
|
|
info.pszAssemblyUniqueDir = NULL;
|
|
info.pszDestFolderID = NULL;
|
|
info.pszManifestFileID = NULL;
|
|
info.pszFileName = NULL;
|
|
info.pszFileID = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// basically, this func first lookup MsiAssembly Table,
|
|
//
|
|
HRESULT MSI_EnumWinFuseAssembly(DWORD dwFlags, const MSIHANDLE & hInstall, PCA_ENUM_FUSION_WIN32_ASSEMBLY_CALLBACK pfnCallback)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR bufSQL[CA_MAX_BUF];
|
|
WCHAR szManifestFileID[256];
|
|
WCHAR szComponentID[128];
|
|
UINT iRet;
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
DWORD cchManifestFileID, cchComponentID;
|
|
BOOL fFusionWin32Component;
|
|
BOOL fExist = FALSE;
|
|
CA_ENM_ASSEMBLY_CALLBACK_INFO info;
|
|
|
|
MSIHANDLE hdb = NULL;
|
|
|
|
PARAMETER_CHECK_NTC((dwFlags & ~(ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY |
|
|
ENUM_ASSEMBLY_FLAG_CHECK_POLICY_ONLY)) == 0);
|
|
|
|
PARAMETER_CHECK_NTC(hInstall != NULL);
|
|
PARAMETER_CHECK_NTC(pfnCallback != NULL);
|
|
|
|
if (dwFlags == 0)
|
|
dwFlags = (ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY | ENUM_ASSEMBLY_FLAG_CHECK_POLICY_ONLY);
|
|
|
|
hdb = MsiGetActiveDatabase(hInstall);
|
|
INTERNAL_ERROR_CHECK_NTC(hdb != 0);
|
|
|
|
IFFAILED_EXIT(MSI_IsTableExist(hdb, L"MsiAssembly", fExist));
|
|
if ( fExist == FALSE)
|
|
goto Exit;
|
|
|
|
|
|
//
|
|
// initialize info structure
|
|
//
|
|
ZeroMemory(&info, sizeof(info));
|
|
IFFAILED_EXIT(MSI_IsTableExist(hdb, WIN32_ASSEMBLY_MIGRATE_TABLE, fExist));
|
|
if (!fExist)
|
|
info.dwFlags = CA_ENM_ASSEMBLY_CALLBACK_INFO_FLAG_IGNORE_MIGRATE_DENY_CHECK;
|
|
|
|
info.hInstall = hInstall;
|
|
info.hdb = hdb;
|
|
|
|
//
|
|
// Query Fusion Win32 Assembly, exclude private assembly
|
|
//
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, ca_sqlQuery[CA_SQL_QUERY_MSIASSEMBLY], &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// reset info structure for component-related fields
|
|
// except handles ( hInstall and hdb) and dwflags
|
|
//
|
|
ResetCallbackInfo(info);
|
|
|
|
//
|
|
// for each entry in MsiAssembly Table
|
|
//
|
|
iRet = MsiViewFetch(hView, &hRecord);
|
|
if (iRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (iRet != ERROR_SUCCESS )
|
|
SET_HRERR_AND_EXIT(iRet);
|
|
|
|
iRet = MsiRecordGetInteger(hRecord, 1);
|
|
if ( iRet != MSI_FUSION_WIN32_ASSEMBLY)
|
|
continue;
|
|
|
|
//
|
|
// get manifest-filename ID
|
|
//
|
|
cchManifestFileID = NUMBER_OF(szManifestFileID);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(hRecord, 2, szManifestFileID, &cchManifestFileID));
|
|
|
|
//
|
|
// get componentID
|
|
//
|
|
cchComponentID = NUMBER_OF(szComponentID);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(hRecord, 3, szComponentID, &cchComponentID));
|
|
MsiCloseHandle(hRecord);
|
|
|
|
//
|
|
// check whether it is policy by searching MsiAssemblyName::type = "win32" or "win32-policy"
|
|
//
|
|
if (dwFlags != (ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY | ENUM_ASSEMBLY_FLAG_CHECK_POLICY_ONLY)) // otherwise, no check is needed
|
|
{
|
|
PMSIHANDLE local_hView = NULL;
|
|
PMSIHANDLE local_hRecord = NULL;
|
|
WCHAR bufType[64];
|
|
DWORD cchType = NUMBER_OF(bufType);
|
|
|
|
swprintf(bufSQL, ca_sqlQuery[CA_SQL_QUERY_MSIASSEMBLYNAME], szComponentID);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, bufSQL, &local_hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(local_hView, 0));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewFetch(local_hView, &local_hRecord));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(local_hRecord, 1, bufType, &cchType));
|
|
|
|
fFusionWin32Component = FALSE;
|
|
if (dwFlags & ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY)
|
|
{
|
|
if (_wcsicmp(bufType, CA_FUSION_WIN32_ASSEMBLY_TYPE) == 0)
|
|
fFusionWin32Component = TRUE;
|
|
}
|
|
|
|
if (dwFlags & ENUM_ASSEMBLY_FLAG_CHECK_POLICY_ONLY)
|
|
{
|
|
if (_wcsicmp(bufType, CA_FUSION_WIN32_POLICY_TYPE) == 0)
|
|
fFusionWin32Component = TRUE;
|
|
}
|
|
|
|
if (fFusionWin32Component == FALSE)
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// OK, we got ComponentID of a fusion-win32 component now; callback would have a show
|
|
//
|
|
ASSERT_NTC(szComponentID != NULL);
|
|
ASSERT_NTC(szManifestFileID != NULL);
|
|
|
|
info.pszComponentID = szComponentID;
|
|
info.pszManifestFileID = szManifestFileID;
|
|
|
|
IFFAILED_EXIT(pfnCallback(&info));
|
|
}
|
|
|
|
Exit:
|
|
|
|
if(hdb != NULL)
|
|
MsiCloseHandle(hdb);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT MSI_GetSourceFileFullPathName(DWORD dwFlags, const MSIHANDLE & hInstall, const MSIHANDLE & hdb, PCWSTR szComponentDirectory, PCWSTR pszFile, CStringBuffer &sbFileName, PCWSTR pszComponent)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR szFileNameInTable[CA_MAX_BUF];
|
|
DWORD cchFileNameInTable = NUMBER_OF(szFileNameInTable);
|
|
PWSTR pszFileNameInTable = NULL;
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
WCHAR szDirectory[MAX_PATH];
|
|
DWORD cchDirectory = NUMBER_OF(szDirectory);
|
|
PWSTR pszComponentDirectory = NULL;
|
|
|
|
PARAMETER_CHECK_NTC((dwFlags == CA_FILEFULLPATHNAME_FILENAME_IN_FILE_TABLE) || (dwFlags == CA_FILEFULLPATHNAME_FILEID_IN_FILE_TABLE));
|
|
PARAMETER_CHECK_NTC(hInstall != NULL);
|
|
PARAMETER_CHECK_NTC(pszFile != NULL);
|
|
PARAMETER_CHECK_NTC((szComponentDirectory != NULL) || ((hInstall != NULL) && (pszComponent != NULL)));
|
|
PARAMETER_CHECK_NTC((dwFlags != CA_FILEFULLPATHNAME_FILEID_IN_FILE_TABLE) || (pszComponent != NULL));
|
|
|
|
if ( dwFlags == CA_FILEFULLPATHNAME_FILEID_IN_FILE_TABLE)
|
|
{
|
|
|
|
WCHAR sqlbuf[CA_MAX_BUF];
|
|
|
|
swprintf(sqlbuf, ca_sqlQuery[CA_SQL_QUERY_FILENAME_USING_FILEID], pszFile, pszComponent);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlbuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiViewFetch(hView, &hRecord)); // this call should succeed otherwise fail
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(hRecord, 1, szFileNameInTable, &cchFileNameInTable));
|
|
pszFileNameInTable = szFileNameInTable;
|
|
}
|
|
else
|
|
pszFileNameInTable = const_cast<PWSTR>(pszFile);
|
|
|
|
if (szComponentDirectory == NULL)
|
|
{
|
|
IFFAILED_EXIT(MSI_GetComponentSourceDirectory(hInstall, hdb, pszComponent, szDirectory, cchDirectory));
|
|
pszComponentDirectory = szDirectory;
|
|
}
|
|
else
|
|
pszComponentDirectory = const_cast<PWSTR>(szComponentDirectory);
|
|
|
|
|
|
|
|
IFFALSE_EXIT(sbFileName.Win32Assign(pszComponentDirectory, wcslen(pszComponentDirectory)));
|
|
IFFALSE_EXIT(sbFileName.Win32EnsureTrailingPathSeparator());
|
|
|
|
PWSTR p = wcschr(pszFileNameInTable, L'|');
|
|
if ( p != NULL)
|
|
{
|
|
p++; // skip '|'
|
|
IFFALSE_EXIT(sbFileName.Win32Append(p, wcslen(p)));
|
|
}else
|
|
{
|
|
WCHAR szLongPathName[MAX_PATH];
|
|
CStringBuffer FullPathShortFileName;
|
|
WCHAR szShortPathName[MAX_PATH];
|
|
DWORD ret = 0;
|
|
|
|
//
|
|
// get short name of the directory
|
|
//
|
|
ret = GetShortPathNameW(sbFileName, szShortPathName, NUMBER_OF(szShortPathName));
|
|
if (( ret == 0) || (ret > NUMBER_OF(szShortPathName)))
|
|
{
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
}
|
|
|
|
IFFALSE_EXIT(FullPathShortFileName.Win32Assign(szShortPathName, wcslen(szShortPathName)));
|
|
IFFALSE_EXIT(FullPathShortFileName.Win32Append(pszFileNameInTable, wcslen(pszFileNameInTable)));
|
|
|
|
ret = GetLongPathNameW(FullPathShortFileName, szLongPathName, NUMBER_OF(szLongPathName));
|
|
if (( ret == 0) || (ret > NUMBER_OF(szLongPathName)))
|
|
{
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
}
|
|
IFFALSE_EXIT(sbFileName.Win32Assign(szLongPathName, wcslen(szLongPathName)));
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSI_GetComponentSourceDirectory(const MSIHANDLE & hInstall, const MSIHANDLE & hdb, PCWSTR pszComponentID, PWSTR szDirectory, DWORD cchDirectory)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR sqlBuf[CA_MAX_BUF];
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
WCHAR szDirectoryID[128];
|
|
DWORD cchDirectoryID = NUMBER_OF(szDirectoryID);
|
|
|
|
PARAMETER_CHECK_NTC(hInstall != NULL);
|
|
PARAMETER_CHECK_NTC((pszComponentID != NULL) && (szDirectory!= NULL) && (cchDirectory != 0));
|
|
|
|
swprintf(sqlBuf, ca_sqlQuery[CA_SQL_QUERY_COMPONENT], pszComponentID);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlBuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiViewFetch(hView, &hRecord)); // this call should succeed otherwise fail
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(hRecord, 1, szDirectoryID, &cchDirectoryID));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiGetSourcePath(hInstall, szDirectoryID, szDirectory, &cchDirectory));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSI_EnumComponentFiles(CA_ENM_ASSEMBLY_CALLBACK_INFO * info, PCA_ENUM_COMPONENT_FILES_CALLBACK pfnCallback)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR bufFileName[CA_MAX_BUF];
|
|
WCHAR bufFileID[CA_MAX_BUF];
|
|
WCHAR sqlbuf[CA_MAX_BUF];
|
|
DWORD cchbuf;
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
UINT iRet;
|
|
|
|
PARAMETER_CHECK_NTC((info != NULL) && (info->pszComponentID != (PCWSTR)NULL) && (info->hInstall != NULL));
|
|
PARAMETER_CHECK_NTC(pfnCallback != NULL);
|
|
|
|
swprintf(sqlbuf, ca_sqlQuery[CA_SQL_QUERY_FILETABLE_USING_COMPONENTID], info->pszComponentID);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info->hdb, sqlbuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// for each entry in MsiAssembly Table
|
|
//
|
|
iRet = MsiViewFetch(hView, &hRecord);
|
|
if (iRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (iRet != ERROR_SUCCESS )
|
|
SET_HRERR_AND_EXIT(iRet);
|
|
|
|
cchbuf = NUMBER_OF(bufFileID);
|
|
bufFileID[0] = L'\0';
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 1, bufFileID, &cchbuf));
|
|
|
|
cchbuf = NUMBER_OF(bufFileName);
|
|
bufFileName[0] = L'\0';
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 2, bufFileName, &cchbuf));
|
|
|
|
info->pszFileName = bufFileName;
|
|
info->pszFileID = bufFileID;
|
|
IFFAILED_EXIT(pfnCallback(info));
|
|
}
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSI_IsTableExist(const MSIHANDLE & hdb, PCWSTR pszTableName, BOOL & fExist)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR sqlbuf[CA_MAX_BUF];
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
DWORD iRet;
|
|
|
|
PARAMETER_CHECK_NTC((hdb != NULL) && (pszTableName != NULL));
|
|
fExist = FALSE;
|
|
|
|
swprintf(sqlbuf, L"SELECT * FROM `_Tables` WHERE `Name`='%s'", pszTableName);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlbuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
iRet = MsiViewFetch(hView, &hRecord);
|
|
if (iRet == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
else
|
|
if (iRet != ERROR_SUCCESS)
|
|
{
|
|
SET_HRERR_AND_EXIT(iRet);
|
|
}
|
|
fExist = TRUE;
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Msi_CreateTableIfNotExist(const MSIHANDLE & hdb, PCWSTR pwszTableName, PCWSTR pwszTableSchema, BOOL & fExistAlready)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hView = NULL;
|
|
|
|
PARAMETER_CHECK_NTC((pwszTableSchema != NULL) && (pwszTableName != NULL));
|
|
fExistAlready = FALSE;
|
|
|
|
IFFAILED_EXIT(MSI_IsTableExist(hdb, pwszTableName, fExistAlready));
|
|
if (fExistAlready == TRUE)
|
|
goto Exit;
|
|
|
|
//
|
|
// create the table
|
|
//
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, pwszTableSchema, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
typedef enum _FUSION_MSI_OS_VERSION
|
|
{
|
|
E_OS_UNKNOWN,
|
|
E_WIN95,
|
|
E_WIN_ME,
|
|
E_WIN_NT,
|
|
E_WIN98,
|
|
E_WIN2K,
|
|
E_WHISTLER,
|
|
E_WIN32_OTHERS
|
|
}FUSION_MSI_OS_VERSION;
|
|
|
|
typedef enum _FUSION_MSI_OS_TYPE
|
|
{
|
|
E_PERSONAL,
|
|
E_PROFESSIONAL,
|
|
E_DATA_CENTER,
|
|
E_STD_SERVER,
|
|
E_ADV_SERVER,
|
|
E_WORKSTATION,
|
|
E_SERVER
|
|
}FUSION_MSI_OS_TYPE;
|
|
|
|
HRESULT GetOSVersion(FUSION_MSI_OS_VERSION & osv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
OSVERSIONINFO osvi;
|
|
BOOL bOsVersionInfoEx;
|
|
|
|
osv = E_OS_UNKNOWN;
|
|
|
|
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
|
|
{
|
|
// If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
switch (osvi.dwPlatformId)
|
|
{
|
|
case VER_PLATFORM_WIN32_NT:
|
|
if ( osvi.dwMajorVersion <= 4 )
|
|
osv = E_WIN_NT;
|
|
else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
|
|
osv = E_WIN2K;
|
|
else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
|
|
osv = E_WHISTLER;
|
|
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
|
|
osv = E_WIN95;
|
|
else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
|
|
osv = E_WIN98;
|
|
else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
|
|
osv = E_WIN_ME;
|
|
break;
|
|
case VER_PLATFORM_WIN32s:
|
|
osv = E_WIN32_OTHERS;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsDownlevel()
|
|
{
|
|
FUSION_MSI_OS_VERSION osv = E_OS_UNKNOWN;
|
|
|
|
if (SUCCEEDED(GetOSVersion(osv)))
|
|
{
|
|
return ((osv == E_WIN2K) || (osv == E_WIN98));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|