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.
1116 lines
37 KiB
1116 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
db.cpp
|
|
|
|
Abstract:
|
|
|
|
Database calls for msm generation
|
|
|
|
Author:
|
|
|
|
Xiaoyu Wu(xiaoyuw) 01-Aug-2001
|
|
|
|
--*/
|
|
#include "msmgen.h"
|
|
#include "msidefs.h"
|
|
#include "Msiquery.h"
|
|
|
|
#include "objbase.h"
|
|
#include "coguid.h"
|
|
|
|
#define NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY 6
|
|
#define NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS 5
|
|
#define NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB 3
|
|
|
|
static PWSTR s_InsertTableSQL[] =
|
|
{
|
|
L"INSERT INTO Directory (Directory, Directory_Parent, DefaultDir) VALUES (?, ?, ?)",
|
|
L"INSERT INTO Component (Component, ComponentId, Directory_, KeyPath, Attributes, Condition) VALUES (?, ?, ?, ?, 0, '')",
|
|
L"INSERT INTO File (File, Component_, FileName, Sequence, FileSize, Version, Language, Attributes) VALUES (?, ?, ?, ?, '0', '1.0.0.0', '0', 0)",
|
|
L"INSERT INTO MsiAssembly (Component_, Feature_, File_Manifest, File_Application, Attributes) VALUES (?, ?, ?, '', 1)",
|
|
L"INSERT INTO MsiAssemblyName (Component_, Name, Value) VALUES (?, ?, ?)",
|
|
L"INSERT INTO ModuleSignature (ModuleID, Version, Language) VALUES (?, ?, 0)",
|
|
L"INSERT INTO ModuleComponents (Component, ModuleID, Language) VALUES (?, ?, 0)",
|
|
L"INSERT INTO Property (Property, Value) VALUES (?, ?)",
|
|
L"INSERT INTO ProgId (ProgId, Class_, Description, ProgId_Parent, Icon_, IconIndex) VALUES (?, ?, ?, NULL, NULL, NULL)",
|
|
L"INSERT INTO Class (CLSID, Component_, ProgId_Default, Description, Feature_, Context, AppId_, FileTypeMask, Icon_, IconIndex, DefInprocHandler, Argument, Attributes)"
|
|
L"VALUES (?, ?, ?, ?, ?, 'InprocServer32', NULL, NULL, NULL, NULL, NULL, NULL, 0)",
|
|
L"INSERT INTO TypeLib (LibID, Component_, Version, Feature_, Language, Description, Directory_, Cost)"
|
|
L"VALUES (?, ?, ?, ?, 0, NULL, NULL, 0)"
|
|
};
|
|
|
|
HRESULT ExecuteDeleteFromSQL(PCWSTR szTablename, PCWSTR szId, PCWSTR szValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR pwszSQL[MAX_PATH];
|
|
PMSIHANDLE hView = NULL;
|
|
|
|
swprintf(pwszSQL, L"DELETE FROM `%s` WHERE `%s`='%s'", szTablename, szId, szValue);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
}
|
|
|
|
DWORD g_FileSequenceNumber = 0;
|
|
|
|
HRESULT ExecuteDropTableSQL(PCWSTR pszTableName)
|
|
{
|
|
WCHAR pwszSQL[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hView = NULL;
|
|
MSICONDITION con;
|
|
|
|
con = MsiDatabaseIsTablePersistent(g_MsmInfo.m_hdb, pszTableName);
|
|
if (con == MSICONDITION_NONE)
|
|
{
|
|
hr = S_OK; // the table does not exist in DB, so do not need to drop the table at all
|
|
goto Exit;
|
|
}
|
|
else if (con != MSICONDITION_TRUE)
|
|
SETFAIL_AND_EXIT;
|
|
|
|
//
|
|
// drop the table
|
|
//
|
|
|
|
swprintf(pwszSQL, L"DROP TABLE `%s`", pszTableName);
|
|
|
|
//
|
|
// ignore the error for drop table because this table maybe non-exist at all
|
|
//
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ExecuteInsertTableSQL(DWORD tableIndex, UINT cRecords, ...)
|
|
{
|
|
PMSIHANDLE hView;
|
|
PMSIHANDLE hRecord = NULL;
|
|
PCWSTR pwszRecord = NULL;
|
|
va_list ap;
|
|
HRESULT hr = S_OK;
|
|
PWSTR pwszSQL = NULL;
|
|
|
|
pwszSQL = s_InsertTableSQL[tableIndex];
|
|
|
|
//
|
|
// create records
|
|
//
|
|
switch (tableIndex){
|
|
case OPT_FILE:
|
|
hRecord = ::MsiCreateRecord(cRecords + 1);
|
|
break;
|
|
case OPT_DIRECTORY:
|
|
case OPT_COMPONENT:
|
|
case OPT_MSIASSEMBLY:
|
|
case OPT_MSIASSEMBLYNAME:
|
|
case OPT_MODULESIGNATURE:
|
|
case OPT_MODULECOMPONENTS:
|
|
case OPT_PROPERTY:
|
|
case OPT_PROGID:
|
|
case OPT_CLASS:
|
|
case OPT_TYPELIB:
|
|
hRecord = ::MsiCreateRecord(cRecords);
|
|
break;
|
|
default:
|
|
SETFAIL_AND_EXIT;
|
|
}
|
|
|
|
if (hRecord == NULL)
|
|
SETFAIL_AND_EXIT;
|
|
|
|
//
|
|
// get parameters
|
|
//
|
|
va_start(ap, cRecords);
|
|
|
|
for (DWORD i=0; i<cRecords; i++)
|
|
{
|
|
pwszRecord = va_arg(ap, PCWSTR);
|
|
if ((tableIndex == OPT_TYPELIB) && (i == 2)) // set version for typelib
|
|
{
|
|
UINT x = _wtoi(pwszRecord);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetInteger(hRecord, i+1, x));
|
|
}
|
|
else
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStringW(hRecord, i+1, pwszRecord));
|
|
}
|
|
|
|
//
|
|
// for fileTable, add a sequence number here
|
|
//
|
|
if (tableIndex == OPT_FILE)
|
|
{
|
|
g_FileSequenceNumber ++;
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetInteger(hRecord, cRecords + 1 , g_FileSequenceNumber));
|
|
}
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
|
|
|
|
Exit:
|
|
va_end(ap);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// check a table with a name-value pair of its identifier
|
|
//
|
|
HRESULT ExecuteQuerySQL(PCWSTR szTableName, PCWSTR szKeyName, PCWSTR szKeyValue, BOOL & fExist, MSIHANDLE * hOutRecord)
|
|
{
|
|
|
|
WCHAR pwszSQL[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hView = NULL;
|
|
MSIHANDLE hRecord;
|
|
MSIHANDLE * phRecord = hOutRecord;
|
|
|
|
if (phRecord == NULL)
|
|
phRecord = &hRecord;
|
|
|
|
fExist = FALSE;
|
|
swprintf(pwszSQL, L"SELECT * FROM `%s` WHERE `%s`='%s'", szTableName, szKeyName, szKeyValue);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
|
|
UINT err = ::MsiViewFetch(hView, phRecord);
|
|
if ((err == ERROR_NO_MORE_ITEMS) || ((err == ERROR_SUCCESS) && (phRecord == NULL)))
|
|
fExist = FALSE;
|
|
else if (err != ERROR_SUCCESS)
|
|
SET_HRERR_AND_EXIT(err);
|
|
else
|
|
fExist = TRUE;
|
|
Exit:
|
|
if (phRecord == &hRecord)
|
|
MsiCloseHandle(hRecord);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ExecuteUpdateSQL(PCWSTR szTableName, PCWSTR KeyName, PCWSTR KeyValue, PCWSTR ColumnName, PCWSTR NewValue)
|
|
{
|
|
WCHAR pwszSQL[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hView = NULL;
|
|
MSIHANDLE * hRecord = NULL;
|
|
BOOL fExist = FALSE;
|
|
|
|
swprintf(pwszSQL, L"UPDATE '%s' SET `%s` = '%s' WHERE '%s'='%s'",
|
|
szTableName, ColumnName, NewValue, KeyName, KeyValue);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetShortLongFileNamePair(PCWSTR fullpath, SIZE_T cch, CStringBuffer & namepair)
|
|
{
|
|
WCHAR shortname[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
PWSTR p = NULL;
|
|
DWORD ret = GetShortPathNameW(
|
|
fullpath,
|
|
shortname,
|
|
NUMBER_OF(shortname));
|
|
if ( ret == 0 )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
goto Exit;
|
|
}
|
|
if (ret > NUMBER_OF(shortname))
|
|
{
|
|
hr = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Exit;
|
|
}
|
|
p = wcsrchr(shortname, L'\\');
|
|
p ++ ;
|
|
|
|
IFFALSE_EXIT(namepair.Win32Assign(p, wcslen(p)));
|
|
IFFALSE_EXIT(namepair.Win32Append(L"|", 1));
|
|
|
|
p = wcsrchr(fullpath, L'\\');
|
|
p++;
|
|
IFFALSE_EXIT(namepair.Win32Append(p, wcslen(p)));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Function:
|
|
// - Directory Table could be set without open the manifest
|
|
// - write 2 entry to Directory Table for downlevel
|
|
// - only write the record when they are not exist in the DB
|
|
//
|
|
HRESULT SetDirectoryTable()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fExist;
|
|
CStringBuffer sbSystemFolder;
|
|
|
|
IFFAILED_EXIT(ExecuteQuerySQL(L"Directory", L"Directory", L"TARGETDIR", fExist, NULL));
|
|
if (!fExist)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(L"TARGETDIR"), // the re-cast is necessary for va_list
|
|
MAKE_PCWSTR(L""),
|
|
MAKE_PCWSTR(L"SourceDir")));
|
|
}
|
|
|
|
// for downlevel installation : copy files into SystemFolders
|
|
IFFALSE_EXIT(sbSystemFolder.Win32Assign(SYSTEM_FOLDER, NUMBER_OF(SYSTEM_FOLDER)-1));
|
|
IFFALSE_EXIT(sbSystemFolder.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
IFFAILED_EXIT(ExecuteQuerySQL(L"Directory", L"Directory", sbSystemFolder, fExist, NULL));
|
|
if (!fExist)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(sbSystemFolder), // the re-cast is necessary for va_list
|
|
MAKE_PCWSTR(L"TARGETDIR"),
|
|
MAKE_PCWSTR(L"System:.")));
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function:
|
|
// - add manifest and catalog into the cabinet
|
|
// - add manifest and catalog into FileTable
|
|
//
|
|
// because this function used ComponentIdentifier, it has to wait until ComponentIdentifier is set
|
|
// and it is set to be the name of the assembly
|
|
//
|
|
HRESULT SetManifestAndCatalog()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CStringBuffer sbBakFileName;
|
|
CStringBuffer sbNamePair;
|
|
|
|
CurrentAssemblyReset;
|
|
//
|
|
// add manifest into FileTable and Cabinet
|
|
//
|
|
IFFALSE_EXIT(sbBakFileName.Win32Assign(curAsmInfo.m_sbManifestFileName));
|
|
IFFALSE_EXIT(curAsmInfo.m_sbManifestFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
curAsmInfo.m_sbAssemblyPath.Left(curAsmInfo.m_CchAssemblyPath);
|
|
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(sbBakFileName));
|
|
IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), sbNamePair));
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_FILE,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbManifestFileName), // sfp.manifest.123434545
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(sbNamePair))); // sfp.manifest
|
|
|
|
// add manifest to the cabinet
|
|
IFFAILED_EXIT(AddFileToCabinetW( curAsmInfo.m_sbAssemblyPath, // fullpath : c:\tests\sfp\sfp.manifest
|
|
curAsmInfo.m_sbAssemblyPath.Cch(),
|
|
curAsmInfo.m_sbManifestFileName, // identifier in FILE : sfp.manifest.1234234234234234
|
|
curAsmInfo.m_sbManifestFileName.Cch()));
|
|
//
|
|
// add catalog into FileTable and Cabinet
|
|
//
|
|
IFFALSE_EXIT(sbBakFileName.Win32ChangePathExtension(CATALOG_FILE_EXT, NUMBER_OF(CATALOG_FILE_EXT) -1, eAddIfNoExtension));
|
|
IFFALSE_EXIT(curAsmInfo.m_sbCatalogFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
curAsmInfo.m_sbAssemblyPath.Left(curAsmInfo.m_CchAssemblyPath);
|
|
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(sbBakFileName));
|
|
|
|
IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), sbNamePair));
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_FILE,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbCatalogFileName), // sfp.cat.123434345345
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(sbNamePair))); // sfp.cat
|
|
|
|
// add catalog to the cabinet
|
|
IFFAILED_EXIT(AddFileToCabinetW(curAsmInfo.m_sbAssemblyPath, // fullpath : c:\tests\sfp\sfp.cat
|
|
curAsmInfo.m_sbAssemblyPath.Cch(),
|
|
curAsmInfo.m_sbCatalogFileName, //
|
|
curAsmInfo.m_sbCatalogFileName.Cch()));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function:
|
|
// Dump the cabinet File into a TemporaryFile
|
|
// Param:
|
|
// OUT WCHAR pszCabFile[] : store the temporary cabinet file
|
|
// PMSIHANDLE hRecord: the record which contain the stream of a cabinet
|
|
//
|
|
HRESULT DumpCABFromMsm(char *pszFilename, DWORD cchFileName, PMSIHANDLE hRecord)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char buf[1024]; // !!!!fci and fdi are ansi apis
|
|
DWORD cbBuf;
|
|
DWORD cbBytesWritten;
|
|
CStringBuffer sbFilename;
|
|
|
|
HANDLE hd = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// generate a filename for temporary cabinet
|
|
// use the big buffer to generate a filename
|
|
//
|
|
|
|
DWORD num = ExpandEnvironmentStringsA(MSM_TEMP_CABIN_FILE, pszFilename, cchFileName);
|
|
if ((num == 0) || (num > cchFileName))
|
|
SETFAIL_AND_EXIT;
|
|
|
|
DWORD dwAttributes = GetFileAttributesA(pszFilename);
|
|
if ( dwAttributes != (DWORD)(-1))
|
|
{
|
|
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
SET_HRERR_AND_EXIT(ERROR_INTERNAL_ERROR);
|
|
|
|
//
|
|
// delete the file before create it, if can not delete, then it is an error,
|
|
// stop right here
|
|
//
|
|
IFFALSE_EXIT(DeleteFileA(pszFilename));
|
|
}
|
|
|
|
hd = CreateFileA(pszFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
|
if (hd == INVALID_HANDLE_VALUE)
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
|
|
//
|
|
// get the stream by reading out bytes from the record block by block
|
|
//
|
|
|
|
do {
|
|
cbBuf = sizeof(buf); // using bytes, not cch
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordReadStream(hRecord, 2, buf, &cbBuf));
|
|
if (cbBuf != 0)
|
|
{
|
|
cbBytesWritten = 0;
|
|
IFFALSE_EXIT(WriteFile(hd, buf, cbBuf, &cbBytesWritten, NULL));
|
|
}
|
|
}while(cbBuf > 0 );
|
|
|
|
IFFALSE_EXIT(CloseHandle(hd));
|
|
hd = INVALID_HANDLE_VALUE;
|
|
|
|
Exit:
|
|
if (hd != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hd);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// (0) ASSERT the database has opened and the cabient has created
|
|
// (1) check whether this is a mergemodule.cab in _Stream table.
|
|
// (2) if so, extract all files from this cab,
|
|
// (3) delete the entry from _StreamTable
|
|
// (4) add all files into new cabinet
|
|
//
|
|
HRESULT PrepareMsmCabinet()
|
|
{
|
|
if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_NEW)
|
|
return S_OK;
|
|
|
|
HRESULT hr = S_OK;
|
|
MSIHANDLE hRecord = NULL;
|
|
BOOL fExist = FALSE;
|
|
char szCabFile[MAX_PATH];
|
|
|
|
ASSERT_NTC(g_MsmInfo.m_hdb != NULL);
|
|
ASSERT_NTC(g_MsmInfo.m_hfci != NULL);
|
|
|
|
IFFAILED_EXIT(ExecuteQuerySQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME, fExist, &hRecord));
|
|
if (fExist)
|
|
{
|
|
if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_REGEN)
|
|
{
|
|
IFFAILED_EXIT(ExecuteDeleteFromSQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME));
|
|
}
|
|
else
|
|
{
|
|
ASSERT_NTC(g_MsmInfo.m_enumGenMode == MSMGEN_OPR_ADD);
|
|
|
|
IFFAILED_EXIT(DumpCABFromMsm(szCabFile, sizeof(szCabFile), hRecord));
|
|
IFFAILED_EXIT(MoveFilesInCabinetA(szCabFile));
|
|
IFFAILED_EXIT(ExecuteDeleteFromSQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME));
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (GetFileAttributes(szCabFile) != -1)
|
|
DeleteFileA(szCabFile);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT PrepareDatabase()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// open the msm, make it ready for READ_WRITE
|
|
//
|
|
IFFAILED_EXIT(OpenMsmFileForMsmGen(g_MsmInfo.m_sbMsmFileName));
|
|
|
|
//
|
|
// the database has opened
|
|
//
|
|
IFFAILED_EXIT(PrepareMsmCabinet());
|
|
|
|
|
|
//
|
|
// get moduleID or generate a new one
|
|
//
|
|
IFFAILED_EXIT(SetModuleID());
|
|
|
|
//
|
|
// for "-op regen",
|
|
// (0) for whatever case, we keep the directory table because it is manifest-independent
|
|
// (1) if component is specified on the command line, we delete most tables except Directory Table;
|
|
// (2) Otherwise, we use the old componentID table, so we delete all tables except Component-related Tables, which include
|
|
// Component Table, ModuleComponent Table, ModuleSignature Table;
|
|
// (3) THERE IS A BIG ASSUMPTION FOR (2): ASSEMBLYNAME IN THE MANIFEST IS NOT CHANGED!
|
|
//
|
|
// (4) all the tables used by msm would be get imported from msmgen Template file in HRESULT PrepareMsm() call;
|
|
//
|
|
if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_REGEN)
|
|
{
|
|
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"File"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"MsiAssembly"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"MsiAssemblyName"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"Class"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"TypeLib"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"ProgId"));
|
|
if (curAsmInfo.m_sbComponentID.IsEmpty() == FALSE)
|
|
{
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"Component"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"ModuleComponent"));
|
|
IFFAILED_EXIT(ExecuteDropTableSQL(L"ModuleSignature"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// if it is a user msm, make sure it has all the tables needed for msmgen
|
|
//
|
|
IFFAILED_EXIT(PrepareMsm());
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// if not specified by the user, ue the same basename as the manifest.
|
|
// in any case, extand it to be a fully-qualified path name for this msm
|
|
//
|
|
HRESULT SetMsmOutputFileName(PCWSTR pszManifestFileName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR tmpbuf[MAX_PATH];
|
|
|
|
PARAMETER_CHECK_NTC(pszManifestFileName != NULL);
|
|
|
|
if (g_MsmInfo.m_sbMsmFileName.IsEmpty() == TRUE)
|
|
{
|
|
// set .msm filename
|
|
UINT iRet = GetFullPathNameW(pszManifestFileName, NUMBER_OF(tmpbuf), tmpbuf, NULL);
|
|
if ((iRet == 0) || (iRet > NUMBER_OF(tmpbuf)))
|
|
{
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
}
|
|
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(tmpbuf, wcslen(tmpbuf)));
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32ChangePathExtension(MSM_FILE_EXT, NUMBER_OF(MSM_FILE_EXT) -1, eAddIfNoExtension));
|
|
}else{
|
|
// get fullpath name
|
|
UINT iRet = GetFullPathNameW(g_MsmInfo.m_sbMsmFileName, NUMBER_OF(tmpbuf), tmpbuf, NULL);
|
|
if ((iRet == 0) || (iRet > NUMBER_OF(tmpbuf)))
|
|
{
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
}
|
|
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(tmpbuf, wcslen(tmpbuf)));
|
|
}
|
|
|
|
//
|
|
// Set Cabinet FilePath
|
|
//
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32Assign(g_MsmInfo.m_sbMsmFileName));
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32RemoveLastPathElement());
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32EnsureTrailingPathSeparator());
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32Append(MERGEMODULE_CABINET_FILENAME, NUMBER_OF(MERGEMODULE_CABINET_FILENAME) -1));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Functions:
|
|
// (1)get the template msm file
|
|
// (2)get the msm output file
|
|
// (3)set static contents for some tables
|
|
//
|
|
HRESULT PrepareMsmOutputFiles(PCWSTR pszManifestFilename)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CurrentAssemblyReset;
|
|
|
|
if (g_MsmInfo.m_sbMsmTemplateFile.IsEmpty() == TRUE)
|
|
{
|
|
//
|
|
// get template file from current directory
|
|
//
|
|
WCHAR path[MAX_PATH];
|
|
DWORD dwRet;
|
|
dwRet = GetModuleFileNameW(NULL, path, NUMBER_OF(path));
|
|
|
|
if ((dwRet == 0) || (dwRet >= NUMBER_OF(path)))
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(path, wcslen(path)));
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32ChangePathExtension(L"msm", 3, eErrorIfNoExtension));
|
|
}
|
|
|
|
if (::GetFileAttributesW(g_MsmInfo.m_sbMsmTemplateFile) == (DWORD) -1)
|
|
{
|
|
fprintf(stderr, "the specified Msm TemplateFile %S does not exist!\n", g_MsmInfo.m_sbMsmTemplateFile);
|
|
SET_HRERR_AND_EXIT(::GetLastError());
|
|
}
|
|
|
|
IFFAILED_EXIT(SetMsmOutputFileName(pszManifestFilename));
|
|
|
|
//
|
|
// initialize the cabinet before the database is initialized because it may needed in
|
|
// the mode of "MSMGEN_OPR_ADD"
|
|
//
|
|
IFFAILED_EXIT(InitializeCabinetForWrite());
|
|
|
|
//
|
|
// prepare the msm files for open
|
|
//
|
|
IFFAILED_EXIT(PrepareDatabase());
|
|
|
|
//
|
|
// set entries to Directory for downlevel support
|
|
//
|
|
IFFAILED_EXIT(SetDirectoryTable());
|
|
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT PropagateXMLDOMNode(IXMLDOMNode* node, ELEMENT_ALLOWED_ATTRIBUTE rgAllowedAttribute[], DWORD num)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMNamedNodeMap* pattrs = NULL;
|
|
IXMLDOMNode* pChild = NULL;
|
|
CStringBuffer tmp;
|
|
DWORD j;
|
|
|
|
CurrentAssemblyReset;
|
|
|
|
for ( j = 0 ; j < num; j++)
|
|
rgAllowedAttribute[j].m_fValued = FALSE;
|
|
|
|
//
|
|
// write MSIAssemblyName table
|
|
//
|
|
if (SUCCEEDED(node->get_attributes(&pattrs)) && pattrs != NULL)
|
|
{
|
|
pattrs->nextNode(&pChild);
|
|
while (pChild)
|
|
{
|
|
BSTR name;
|
|
pChild->get_nodeName(&name);
|
|
for ( j = 0; j < num; j++)
|
|
{
|
|
if((rgAllowedAttribute[j].m_fValued == FALSE) && (wcscmp(rgAllowedAttribute[j].m_name, name) == 0))
|
|
{
|
|
VARIANT value;
|
|
pChild->get_nodeValue(&value);
|
|
if (value.vt != VT_BSTR)
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if ( ! rgAllowedAttribute[j].m_value->Win32Assign(V_BSTR(&value), wcslen(V_BSTR(&value))))
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
VariantClear(&value);
|
|
if ( !SUCCEEDED(hr))
|
|
break;
|
|
|
|
hr = S_OK;
|
|
if (rgAllowedAttribute[j].m_callbackFunc != NULL)
|
|
hr = rgAllowedAttribute[j].m_callbackFunc(
|
|
rgAllowedAttribute[j].m_name,
|
|
*(rgAllowedAttribute[j].m_value));
|
|
|
|
if ( !SUCCEEDED(hr))
|
|
break;
|
|
|
|
rgAllowedAttribute[j].m_fValued = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// cleaning work
|
|
//
|
|
SysFreeString(name);
|
|
pChild->Release();
|
|
pChild = NULL;
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
pattrs->Release();
|
|
pattrs = NULL;
|
|
|
|
goto Exit;
|
|
}
|
|
pattrs->nextNode(&pChild);
|
|
}
|
|
|
|
pattrs->Release();
|
|
pattrs = NULL;
|
|
}
|
|
Exit:
|
|
SAFE_RELEASE_COMPOINTER(pattrs);
|
|
SAFE_RELEASE_COMPOINTER(pChild);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSM_PARSER_DOM_NODE_file(IXMLDOMNode* node)
|
|
{
|
|
IXMLDOMNamedNodeMap* pattrs = NULL;
|
|
IXMLDOMNode* pChild = NULL;
|
|
BOOL fFoundFileName = FALSE;
|
|
HRESULT hr = S_OK;
|
|
CStringBuffer tmpStr;
|
|
CStringBuffer ShortLongPair;
|
|
DWORD CchFullpathFilename;
|
|
|
|
CurrentAssemblyReset;
|
|
IFFALSE_EXIT(tmpStr.Win32Assign(curAsmInfo.m_sbAssemblyPath));
|
|
|
|
//
|
|
// get the filename from node
|
|
//
|
|
if (SUCCEEDED(node->get_attributes(&pattrs)) && pattrs != NULL)
|
|
{
|
|
pattrs->nextNode(&pChild);
|
|
while (pChild)
|
|
{
|
|
BSTR name = NULL;
|
|
pChild->get_nodeName(&name);
|
|
if (wcscmp(name, L"name") == 0)
|
|
{
|
|
VARIANT value;
|
|
pChild->get_nodeValue(&value);
|
|
if (value.vt != VT_BSTR)
|
|
{
|
|
VariantClear(&value);
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if ( !curAsmInfo.m_sbAssemblyPath.Win32Append(V_BSTR(&value), wcslen(V_BSTR(&value))))
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
VariantClear(&value);
|
|
fFoundFileName = TRUE;
|
|
}
|
|
|
|
::SysFreeString(name);
|
|
pChild->Release();
|
|
pChild = NULL;
|
|
|
|
if (!SUCCEEDED(hr)){
|
|
pattrs->Release();
|
|
pattrs = NULL;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( fFoundFileName )
|
|
break;
|
|
|
|
pattrs->nextNode(&pChild);
|
|
}
|
|
if (pattrs)
|
|
{
|
|
pattrs->Release();
|
|
pattrs = NULL;
|
|
}
|
|
}
|
|
|
|
if ( !fFoundFileName)
|
|
SETFAIL_AND_EXIT;
|
|
|
|
CchFullpathFilename = curAsmInfo.m_sbAssemblyPath.GetCchAsDWORD();
|
|
//
|
|
// get fully qualified filename
|
|
//
|
|
IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), ShortLongPair));
|
|
|
|
//
|
|
// check the existence of the file
|
|
//
|
|
if ( GetFileAttributesW(curAsmInfo.m_sbAssemblyPath) == DWORD(-1))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// get FileIdentifier for this file
|
|
//
|
|
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
//
|
|
// add the file to FileTable
|
|
//
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_FILE,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath), // a.dll.12223423423423412343
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(ShortLongPair))); // a.dll | a.dll
|
|
|
|
//
|
|
// add this file to the cabinet
|
|
//
|
|
IFFAILED_EXIT(AddFileToCabinetW(
|
|
curAsmInfo.m_sbAssemblyPath, CchFullpathFilename,
|
|
curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch() - curAsmInfo.m_CchAssemblyPath));
|
|
|
|
//
|
|
// set Component Table with ComponentID, componentIdentifier, keypath:
|
|
//
|
|
if (curAsmInfo.m_fComponentTableSet == FALSE)
|
|
{
|
|
IFFAILED_EXIT(SetComponentId(curAsmInfo.m_sbComponentIdentifier, curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath));
|
|
curAsmInfo.m_fComponentTableSet = TRUE;
|
|
}
|
|
|
|
Exit:
|
|
if (pattrs)
|
|
pattrs->Release();
|
|
|
|
if(pChild)
|
|
pChild->Release();
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsValidAttributes(const ELEMENT_ALLOWED_ATTRIBUTE attribs[], DWORD num)
|
|
{
|
|
for (DWORD i=0; i< num; i++)
|
|
{
|
|
if (attribs[i].m_fRequired && ! attribs[i].m_fValued)
|
|
{
|
|
::SetLastError(ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT GetPrimAssemblyName(PCWSTR pwszAssemblyName, PWSTR pwszPrimAssemblyName, DWORD & cch)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0, num = wcslen(pwszAssemblyName);
|
|
|
|
if (cch < num)
|
|
{
|
|
cch = num;
|
|
SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
wcscpy(pwszPrimAssemblyName, pwszAssemblyName);
|
|
|
|
while ( i < num)
|
|
{
|
|
if (pwszPrimAssemblyName[i] == L'-')
|
|
{
|
|
pwszPrimAssemblyName[i] = L'_';
|
|
}
|
|
i++;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSM_PARSER_DOM_NODE_assemblyIdentity(IXMLDOMNode* node)
|
|
{
|
|
//
|
|
// we only are interested in the assemblyIdentity of the component, that is,
|
|
// <assemblyIdentity .... /> at the head of manifest, ignore <assemblyIdentity ..../> of
|
|
// dependency
|
|
//
|
|
if (curAsmInfo.m_sbComponentIdentifier.IsEmpty() == FALSE)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY];
|
|
static ELEMENT_ALLOWED_ATTRIBUTE rg_assemblyIdentity_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY] =
|
|
{
|
|
{L"name", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
|
|
{L"language", FALSE, NULL, FALSE, &rg_StringBuffer[1]},
|
|
{L"version", TRUE, NULL, FALSE, &rg_StringBuffer[2]},
|
|
{L"processorArchitecture", TRUE, NULL, FALSE, &rg_StringBuffer[3]},
|
|
{L"publicKeyToken", FALSE, NULL, FALSE, &rg_StringBuffer[4]},
|
|
{L"type", TRUE, NULL, FALSE, &rg_StringBuffer[5]}
|
|
};
|
|
|
|
|
|
CStringBuffer tmp;
|
|
WCHAR tmpbuf[MAX_PATH];
|
|
DWORD num = NUMBER_OF(tmpbuf);
|
|
|
|
CurrentAssemblyReset;
|
|
IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_assemblyIdentity_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY));
|
|
IFFALSE_EXIT(IsValidAttributes(rg_assemblyIdentity_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY));
|
|
|
|
IFFAILED_EXIT(GetPrimAssemblyName(*rg_assemblyIdentity_AllowedAttributes[MSMGEN_ASSEMBLYIDENTTIY_ATTRIBUTE_NAME].m_value, tmpbuf, num));
|
|
|
|
//
|
|
// Set module identifier
|
|
//
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Assign(tmpbuf, wcslen(tmpbuf)));
|
|
IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
//
|
|
// set componentIdentifier and add entries to table which depends on componentIdentifier
|
|
//
|
|
IFFALSE_EXIT(curAsmInfo.m_sbComponentIdentifier.Win32Assign(tmpbuf, wcslen(tmpbuf)));
|
|
IFFALSE_EXIT(curAsmInfo.m_sbComponentIdentifier.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
//
|
|
// insert manifest & catalog into File Table, cabinet,
|
|
//
|
|
IFFAILED_EXIT(SetManifestAndCatalog());
|
|
|
|
//
|
|
// write MsiAssemblyName table
|
|
//
|
|
for (DWORD i = 0; i < NUMBER_OF(rg_assemblyIdentity_AllowedAttributes); i++)
|
|
{
|
|
if (rg_assemblyIdentity_AllowedAttributes[i].m_fValued)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MSIASSEMBLYNAME,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_MSIASSEMBLYNAME,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(rg_assemblyIdentity_AllowedAttributes[i].m_name),
|
|
MAKE_PCWSTR(*rg_assemblyIdentity_AllowedAttributes[i].m_value)));
|
|
}
|
|
}
|
|
|
|
//
|
|
// write MsiAssebly Table
|
|
//
|
|
curAsmInfo.m_sbManifestFileName.Left(curAsmInfo.m_CchManifestFileName);
|
|
IFFALSE_EXIT(curAsmInfo.m_sbManifestFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
|
|
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_MSIASSEMBLY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_MSIASSEMBLY,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(GUID_NULL_IN_STRING),
|
|
MAKE_PCWSTR(curAsmInfo.m_sbManifestFileName))); // sfp.manifest.12343454534534534
|
|
|
|
//
|
|
// write ModuleSiguature table using version
|
|
//
|
|
BOOL fExist;
|
|
IFFAILED_EXIT(ExecuteQuerySQL(L"ModuleSignature", L"ModuleID", g_MsmInfo.m_sbModuleIdentifier, fExist, NULL));
|
|
if ( fExist == FALSE)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MODULESIGNATURE,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_MODULESIGNATURE,
|
|
MAKE_PCWSTR(g_MsmInfo.m_sbModuleIdentifier),
|
|
MAKE_PCWSTR(*rg_assemblyIdentity_AllowedAttributes[MSMGEN_ASSEMBLYIDENTTIY_ATTRIBUTE_VERSION].m_value)));
|
|
}else
|
|
{
|
|
// updateRecord
|
|
|
|
}
|
|
|
|
//
|
|
// write ModuleComponent table using version
|
|
//
|
|
|
|
IFFAILED_EXIT(ExecuteQuerySQL(L"ModuleComponents", L"Component", curAsmInfo.m_sbComponentIdentifier, fExist, NULL));
|
|
if ( fExist == FALSE)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MODULECOMPONENTS,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_MODULECOMPONENTS,
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(g_MsmInfo.m_sbModuleIdentifier)));
|
|
}else
|
|
{
|
|
// updateRecord
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSM_PARSER_DOM_NODE_comClass(IXMLDOMNode* node)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// About this array :
|
|
// 0, 2 would be stored in class table
|
|
// 1 would be stored in progid table
|
|
// 3 would be ignored and Typelib Table would be created when "<typelib />" is encounter
|
|
// 4 would be ignored
|
|
//
|
|
static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS];
|
|
static ELEMENT_ALLOWED_ATTRIBUTE rg_comClass_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS] = {
|
|
{L"clsid", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
|
|
{L"description", FALSE, NULL, FALSE, &rg_StringBuffer[1]},
|
|
{L"progid", FALSE, NULL, FALSE, &rg_StringBuffer[2]},
|
|
{L"tlbid", FALSE, NULL, FALSE, &rg_StringBuffer[3]},
|
|
{L"threadingModel", FALSE, NULL, FALSE, &rg_StringBuffer[4]}
|
|
};
|
|
|
|
CurrentAssemblyReset;
|
|
IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_comClass_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS));
|
|
IFFALSE_EXIT(IsValidAttributes(rg_comClass_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS));
|
|
|
|
//
|
|
// if the progId is not NULL, Insert an entry to ProgID Table
|
|
//
|
|
if (rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_fValued)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_PROGID,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_PROGID,
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_value),
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_CLSID].m_value),
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_DESCRIPTION].m_value)));
|
|
}
|
|
|
|
//
|
|
// insert one entry to ClassTable
|
|
//
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_CLASS,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_CLASS,
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_CLSID].m_value),
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_value),
|
|
MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_DESCRIPTION].m_value),
|
|
MAKE_PCWSTR(GUID_NULL_IN_STRING)));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MSM_PARSER_DOM_NODE_typelib(IXMLDOMNode* node)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// all of three attributes are required for "<typelib .... />" element
|
|
//
|
|
static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB];
|
|
static ELEMENT_ALLOWED_ATTRIBUTE rg_typelib_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB] = {
|
|
{L"tlbid", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
|
|
{L"version", TRUE, NULL, FALSE, &rg_StringBuffer[1]},
|
|
{L"helpdir", TRUE, NULL, FALSE, &rg_StringBuffer[2]}
|
|
};
|
|
|
|
CurrentAssemblyReset;
|
|
IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_typelib_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB));
|
|
IFFALSE_EXIT(IsValidAttributes(rg_typelib_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB));
|
|
|
|
//
|
|
// insert one entry to class table
|
|
//
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(
|
|
OPT_TYPELIB,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_TYPELIB,
|
|
MAKE_PCWSTR(*rg_typelib_AllowedAttributes[MSMGEN_TYPELIB_ATTRIBUTE_TLBID].m_value),
|
|
MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
|
|
MAKE_PCWSTR(*rg_typelib_AllowedAttributes[MSMGEN_TYPELIB_ATTRIBUTE_VERSION].m_value),
|
|
MAKE_PCWSTR(GUID_NULL_IN_STRING)));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT InsertCabinetIntoMsm()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRec = NULL;
|
|
|
|
CurrentAssemblyReset;
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewA(g_MsmInfo.m_hdb, "INSERT INTO `_Streams` (`Name`, `Data`) VALUES (?, ?)", &hView));
|
|
|
|
hRec = ::MsiCreateRecord(2);
|
|
if (NULL == hRec)
|
|
SETFAIL_AND_EXIT;
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStringW(hRec, 1, MERGEMODULE_CABINET_FILENAME));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStreamW(hRec, 2, g_MsmInfo.m_sbCabinet));
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRec));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewClose(hView));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// each entry in Component Table always need a KeyPath, which is a datafile
|
|
// for some assembly, which has no datafile or policy assembly, we have to add an entry to ComponentTable at the end
|
|
// of the generation
|
|
//
|
|
HRESULT CheckComponentTable()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (curAsmInfo.m_fComponentTableSet == FALSE)
|
|
{
|
|
IFFAILED_EXIT(SetComponentId(curAsmInfo.m_sbComponentIdentifier, NULL));
|
|
curAsmInfo.m_fComponentTableSet = TRUE;
|
|
}
|
|
Exit:
|
|
return hr;
|
|
|
|
}
|
|
|