Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1259 lines
38 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
msmgen.cpp
Abstract:
Main Function calls for msm generation
Author:
Xiaoyu Wu(xiaoyuw) 01-Aug-2001
--*/
#include "msmgen.h"
#include "util.h"
#include "objbase.h"
#include "initguid.h"
#include "coguid.h"
#include "msidefs.h"
#include <string.h>
#define DEFAULT_MODULE_IDENTIFIER_PREFIX L"Module0"
#define MSMGEN_FROM_MANFILE 0
#define MSMGEN_FROM_MANLIST 1
#define MSMGEN_FROM_MANGROUP 2
extern void MsmToUpper(CBaseStringBuffer &);
//
// global variables
//
CStringBuffer g_sbTemplateFile;
ASSEMBLY_INFO curAsmInfo;
MSM_INFO g_MsmInfo;
//
// function declaration
//
DECLARE_FUNCTION(_file);
DECLARE_FUNCTION(_assemblyIdentity);
DECLARE_FUNCTION(_comClass);
DECLARE_FUNCTION(_typelib);
static MSM_DOMNODE_WORKER s_msm_worker[]={
DEFINE_ATTRIBUTE_MSM_INTERESTED(file),
DEFINE_ATTRIBUTE_MSM_INTERESTED(assemblyIdentity),
DEFINE_ATTRIBUTE_MSM_INTERESTED(comClass),
DEFINE_ATTRIBUTE_MSM_INTERESTED(typelib)
};
void PrintUsage()
{
WCHAR filename[MAX_PATH];
PWSTR exe = NULL;
if (GetModuleFileNameW(NULL, filename, NUMBER_OF(filename)) > 0)
{
exe = wcsrchr(filename, L'\\');
if (exe == NULL)
{
wcscpy(filename, L"msmgen exe ");
exe = filename;
}else
exe ++;
}
else
{
wcscpy(filename, L"msmgen exe ");
exe = filename;
}
fprintf(stderr, "Generate .msm for an assembly\n\n");
fprintf(stderr, "%S manfile manifest_file.manifest [-compid {guid}] [-msmid {guid}] [-msm file.msm] [-template templatefile.msm]\n", exe);
fprintf(stderr, "%S manlist manifest_list.txt [-msmid {guid}] [-msm file.msm] [-template templatefile.msm]\n", exe);
fprintf(stderr, "%S mangroup manifest_group.txt [-template templatefile.msm]\n", exe);
exit(0);
}
VOID ZeroOutCurrentAssemblyInfo()
{
curAsmInfo.m_sbAssemblyPath.Left(0);
curAsmInfo.m_sbManifestFileName.Left(0);
curAsmInfo.m_sbCatalogFileName.Left(0);
curAsmInfo.m_CchAssemblyPath = 0;
curAsmInfo.m_CchManifestFileName = 0;
curAsmInfo.m_CchCatalogFileName = 0;
curAsmInfo.m_sbComponentID.Left(0);
curAsmInfo.m_sbLangID.Left(0);
curAsmInfo.m_sbComponentIdentifier.Left(0);
curAsmInfo.m_fComponentTableSet = FALSE;
}
VOID ZeroOutMsmInfo()
{
g_MsmInfo.m_guidModuleID = GUID_NULL;
g_MsmInfo.m_sbModuleGuidStr.Left(0);
g_MsmInfo.m_hfci = NULL;
g_MsmInfo.m_sbMsmFileName.Left(0);
g_MsmInfo.m_hdb = NULL;
g_MsmInfo.m_sbModuleIdentifier.Left(0);
g_MsmInfo.m_sLanguageID = 0;
g_MsmInfo.m_sbCabinet.Left(0);
//g_MsmInfo.m_sbMsmTemplateFile.Left(0);
}
HRESULT ValidateCurrentMsmInfo()
{
HRESULT hr = S_OK;
INTERNAL_ERROR_CHECK_NTC(g_MsmInfo.m_sbMsmFileName.Cch() != 0);
INTERNAL_ERROR_CHECK_NTC(g_MsmInfo.m_sbMsmTemplateFile.Cch() != 0);
INTERNAL_ERROR_CHECK_NTC(g_MsmInfo.m_guidModuleID != GUID_NULL);
INTERNAL_ERROR_CHECK_NTC(g_MsmInfo.m_sbModuleGuidStr.Cch() != 0);
hr = S_OK;
Exit:
return hr;
}
HRESULT LoadManifestToDOMDocument(IXMLDOMDocument *pDoc)
{
VARIANT vURL;
VARIANT_BOOL vb;
HRESULT hr = S_OK;
BSTR bstr = NULL;
CurrentAssemblyRealign;
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(curAsmInfo.m_sbManifestFileName));
bstr = SysAllocString(curAsmInfo.m_sbAssemblyPath);
IFFAILED_EXIT(pDoc->put_async(VARIANT_FALSE));
// Load xml document from the given URL or file path
VariantInit(&vURL);
vURL.vt = VT_BSTR;
V_BSTR(&vURL) = bstr;
IFFAILED_EXIT(pDoc->load(vURL, &vb));
Exit:
SysFreeString(bstr);
return hr;
}
HRESULT PopulateDOMNode(IXMLDOMNode * node)
{
HRESULT hr = S_OK;
BSTR nodeName = NULL;
DOMNodeType nodetype;
IFFAILED_EXIT(node->get_nodeType(&nodetype));
if(nodetype == NODE_ELEMENT)
{
IFFAILED_EXIT(node->get_nodeName(&nodeName));
for ( DWORD i = 0 ; i < NUMBER_OF(s_msm_worker); i++)
{
if (wcscmp(s_msm_worker[i].pwszNodeName, nodeName) == 0)
{
IFFAILED_EXIT(s_msm_worker[i].pfn(node));
break;
}
}
}
Exit:
SysFreeString(nodeName);
return hr;
}
HRESULT WalkDomTree(IXMLDOMNode * node)
{
HRESULT hr = S_OK;
IXMLDOMNode* pChild = NULL, *pNext = NULL;
IFFAILED_EXIT(PopulateDOMNode(node));
node->get_firstChild(&pChild);
while (pChild)
{
IFFAILED_EXIT(WalkDomTree(pChild));
pChild->get_nextSibling(&pNext);
pChild->Release();
pChild = NULL;
pChild = pNext;
pNext = NULL;
}
Exit:
if (pChild)
pChild->Release();
if(pNext)
pNext->Release();
return hr;
}
HRESULT PopulateAssemblyManifest()
{
HRESULT hr = S_OK;
IXMLDOMDocument *pDoc = NULL;
IXMLDOMNode *pNode = NULL;
IFFAILED_EXIT(CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pDoc));
IFFAILED_EXIT(LoadManifestToDOMDocument(pDoc));
IFFAILED_EXIT(pDoc->QueryInterface(IID_IXMLDOMNode,(void**)&pNode));
IFFAILED_EXIT(WalkDomTree(pNode));
Exit:
SAFE_RELEASE_COMPOINTER(pDoc);
SAFE_RELEASE_COMPOINTER(pNode);
return hr;
}
HRESULT PrepareMergeModuleOutputFileFromScratch()
{
HRESULT hr = S_OK;
LPOLESTR tmpstr = NULL;
PMSIHANDLE hSummaryInfo = NULL;
CurrentAssemblyRealign;
// make sure that msm, template and msm-guid has been set
IFFAILED_EXIT(ValidateCurrentMsmInfo());
//
// set cabinet output filename
//
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));
IFFAILED_EXIT(InitializeCabinetForWrite());
// open msm as a database
ASSERT_NTC(g_MsmInfo.m_hdb == NULL);
ASSERT_NTC(g_MsmInfo.m_sbMsmTemplateFile.IsEmpty() == FALSE);
IFFALSE_EXIT(CopyFileW(g_MsmInfo.m_sbMsmTemplateFile, g_MsmInfo.m_sbMsmFileName, FALSE));
IFFALSE_EXIT(SetFileAttributesW(g_MsmInfo.m_sbMsmFileName, FILE_ATTRIBUTE_NORMAL));
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiOpenDatabaseW(g_MsmInfo.m_sbMsmFileName, (LPCWSTR)(MSIDBOPEN_DIRECT), &g_MsmInfo.m_hdb));
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiGetSummaryInformation(g_MsmInfo.m_hdb, NULL, 3, &hSummaryInfo));
INTERNAL_ERROR_CHECK_NTC(g_MsmInfo.m_guidModuleID != GUID_NULL);
IFFAILED_EXIT(StringFromCLSID(g_MsmInfo.m_guidModuleID, &tmpstr));
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiSummaryInfoSetProperty(hSummaryInfo, PID_REVNUMBER, VT_LPSTR, 0,0, tmpstr));
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiSummaryInfoSetProperty(hSummaryInfo, PID_PAGECOUNT, VT_I4, 150, 0, 0));
//
// write ModuleSiguature table using version
//
ASSERT_NTC(g_MsmInfo.m_sbModuleIdentifier.Cch() != 0);
IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MODULESIGNATURE,
NUMBER_OF_PARAM_TO_INSERT_TABLE_MODULESIGNATURE,
MAKE_PCWSTR(g_MsmInfo.m_sbModuleIdentifier),
MAKE_PCWSTR(L"1.0.0.0")));
Exit:
MsiSummaryInfoPersist(hSummaryInfo);
CoTaskMemFree(tmpstr);
return hr;
}
#define MSMGEN_CREATE_MSM_ALWAYS 0x01
#define MSMGEN_ADD_ASSEMBLY_INTO_EXIST_MSM 0x02
HRESULT PutAssemblyIntoMergeModule(DWORD dwFlags)
{
HRESULT hr = S_OK;
PARAMETER_CHECK_NTC((dwFlags == MSMGEN_CREATE_MSM_ALWAYS) || (dwFlags == MSMGEN_ADD_ASSEMBLY_INTO_EXIST_MSM));
ASSERT_NTC(curAsmInfo.m_sbAssemblyPath.Cch() != 0);
ASSERT_NTC(curAsmInfo.m_sbManifestFileName.Cch() != 0);
ASSERT_NTC(curAsmInfo.m_sbCatalogFileName.Cch() != 0);
ASSERT_NTC(curAsmInfo.m_sbComponentID.Cch() != 0);
ASSERT_NTC(g_MsmInfo.m_sbMsmFileName.Cch() != NULL);
// validate global structure of msmInfo and asmInfo
if (dwFlags == MSMGEN_CREATE_MSM_ALWAYS)
{
// delete mam if exist
SetFileAttributesW(g_MsmInfo.m_sbMsmFileName, FILE_ATTRIBUTE_NORMAL);
DeleteFileW(g_MsmInfo.m_sbMsmFileName);
if (GetFileAttributesW(g_MsmInfo.m_sbMsmFileName) != (DWORD) (-1))
{
ReportError("failed to create a new msm. The msm file, %S, could not be removed!", (PCWSTR)g_MsmInfo.m_sbMsmFileName);
SETFAIL_AND_EXIT;
}
else if (::GetLastError() != ERROR_FILE_NOT_FOUND)
{
if (::GetLastError() == ERROR_PATH_NOT_FOUND)
{
CStringBuffer sb;
IFFALSE_EXIT(sb.Win32Assign(g_MsmInfo.m_sbMsmFileName));
IFFALSE_EXIT(sb.Win32RemoveLastPathElement());
IFFALSE_EXIT(FusionpCreateDirectories(sb, sb.Cch()));
goto MsmContinue;
}
ReportError("failed to create a new msm. GetFileAttribute for %S return error other than NOT_FOUND, win32 err code = %d\n", (PCWSTR)g_MsmInfo.m_sbMsmFileName, ::GetLastError());
SETFAIL_AND_EXIT;
}
MsmContinue:
IFFAILED_EXIT(PrepareMergeModuleOutputFileFromScratch());
IFFAILED_EXIT(PopulateAssemblyManifest());
}
else if (dwFlags == MSMGEN_ADD_ASSEMBLY_INTO_EXIST_MSM)
{
if (GetFileAttributesW(g_MsmInfo.m_sbMsmFileName) == (DWORD) (-1))
{
ReportError("failed to add assembly into a msm. The msm file, %S, does not exist!", (PCWSTR)g_MsmInfo.m_sbMsmFileName);
SETFAIL_AND_EXIT;
}
IFFAILED_EXIT(PopulateAssemblyManifest());
}
Exit:
return hr;
}
void Msmgen_TracingFunctionFailure(PWSTR x, PSTR func, DWORD line)
{
PWSTR p = x;
PWSTR q;
WCHAR Callee[256];
while ((p != NULL) && ((*p == L' ') || (*p == L'(')))
p ++;
q = p;
if (p != NULL)
q = wcschr(p , L'(');
if (q != NULL)
{
wcsncpy(Callee, p, q - p);
ReportError("%S called in %s at line %2d failed!", Callee, func, line);
}else
{
ReportError("Function called in %s at line %2d failed!", func, line);
}
return;
}
//
// make msi-specified guid string ready : uppercase and replace "-" with "_"
//
HRESULT GetMsiGUIDStrFromGUID(DWORD dwFlags, GUID & guid, CSmallStringBuffer & str)
{
HRESULT hr = S_OK;
WCHAR tmpbuf[MAX_PATH];
LPOLESTR tmpstr = NULL;
IFFAILED_EXIT(StringFromCLSID(guid, &tmpstr));
wcscpy(tmpbuf, tmpstr);
for (DWORD i=0; i < wcslen(tmpbuf); i++)
{
if (tmpbuf[i] == L'-')
tmpbuf[i] = L'_';
else
tmpbuf[i]= towupper(tmpbuf[i]);
}
if (dwFlags & MSIGUIDSTR_WITH_PREPEND_DOT)
{
tmpbuf[0] = L'.';
IFFALSE_EXIT(str.Win32Assign(tmpbuf, wcslen(tmpbuf) - 1 )); // has prepend "."
}else
IFFALSE_EXIT(str.Win32Assign(tmpbuf + 1 , wcslen(tmpbuf) - 2 )); // get rid of "{" and "}"
Exit:
CoTaskMemFree(tmpstr);
return hr;
}
HRESULT FillMsmForInitialize()
{
HRESULT hr = S_OK;
WCHAR buf[MAX_PATH];
if (GetFileAttributesW(g_MsmInfo.m_sbMsmFileName) != DWORD(-1))
{
SetFileAttributesW(g_MsmInfo.m_sbMsmFileName, FILE_ATTRIBUTE_NORMAL);
DeleteFileW(g_MsmInfo.m_sbMsmFileName);
if (GetFileAttributesW(g_MsmInfo.m_sbMsmFileName) != DWORD(-1))
{
ReportError("the output %s already exist, please rename or delete it.\n");
hr = E_INVALIDARG;
goto Exit;
}
}
//
// set template filename
//
if (g_MsmInfo.m_sbMsmTemplateFile.Cch() == 0)
{
if (FALSE == g_sbTemplateFile.IsEmpty())
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(g_sbTemplateFile));
} else
{
//
// get template file from current directory
//
DWORD dwRet;
dwRet = GetModuleFileNameW(NULL, buf, NUMBER_OF(buf));
if ((dwRet == 0) || (dwRet >= NUMBER_OF(buf)))
SET_HRERR_AND_EXIT(::GetLastError());
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(buf, wcslen(buf)));
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32ChangePathExtension(L"msm", 3, eErrorIfNoExtension));
}
}
// make sure that the template file must exist!
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());
}
// set msm ID
if (g_MsmInfo.m_guidModuleID == GUID_NULL)
{
IFFAILED_EXIT(::CoCreateGuid(&g_MsmInfo.m_guidModuleID));
}
IFFAILED_EXIT(GetMsiGUIDStrFromGUID(MSIGUIDSTR_WITH_PREPEND_DOT, g_MsmInfo.m_guidModuleID, g_MsmInfo.m_sbModuleGuidStr));
// unset until we get textual assembly identity
IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Assign(L"_", 1)); //make sure that ModuleID does not start with a "_"
IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Append(g_MsmInfo.m_sbModuleGuidStr + 1, g_MsmInfo.m_sbModuleGuidStr.Cch() -1));
hr= S_OK;
Exit:
return hr;
}
#define FILE_EXTENSION_MSM L"msm"
#define FILE_EXTENSION_MSM_CCH 3
using namespace std;
#include <string>
HRESULT InitializeMsmA(string & strManFile, string & strMsmFile, string & strMsmID, string & strTemplateFile)
{
HRESULT hr = S_OK;
LPOLESTR tmpstr = NULL;
PARAMETER_CHECK_NTC(!strManFile.empty());
ZeroOutMsmInfo(); // void function
//
// set output msm filename
//
if (strMsmFile.empty())
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(strManFile.c_str(), strManFile.length()));
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32ChangePathExtension(FILE_EXTENSION_MSM, FILE_EXTENSION_MSM_CCH, eErrorIfNoExtension));
}
else
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(strMsmFile.c_str(), strMsmFile.length()));
}
//
// set template filename
//
if (!strTemplateFile.empty())
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(strTemplateFile.c_str(), strTemplateFile.length()));
}
// set msm ID
g_MsmInfo.m_guidModuleID = GUID_NULL;
if (!strMsmID.empty())
{
//
// get ModuleID from msm and save it into the global structure
//
CStringBuffer sb;
IFFALSE_EXIT(sb.Win32Assign(strMsmID.c_str(), strMsmID.length()));
IFFAILED_EXIT(CLSIDFromString(LPOLESTR(PCWSTR(sb)), &g_MsmInfo.m_guidModuleID));
}
IFFAILED_EXIT(FillMsmForInitialize());
hr = S_OK;
Exit:
CoTaskMemFree(tmpstr);
return hr;
}
HRESULT InitializeMsmW(PCWSTR pszManFile, PCWSTR pszMsmFile, PCWSTR pszMsmID, PCWSTR pszTemplateFile)
{
HRESULT hr = S_OK;
PMSIHANDLE hSummaryInfo = NULL;\
PARAMETER_CHECK_NTC(pszManFile != NULL);
ZeroOutMsmInfo(); // void function
//
// set output msm filename
//
if (pszMsmFile == NULL)
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(pszManFile, wcslen(pszManFile)));
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32ChangePathExtension(FILE_EXTENSION_MSM, FILE_EXTENSION_MSM_CCH, eErrorIfNoExtension));
}
else
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(pszMsmFile, wcslen(pszMsmFile)));
}
//
// set template filename
//
if (pszTemplateFile != NULL)
{
IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(pszTemplateFile, wcslen(pszTemplateFile)));
}
// set msm ID
g_MsmInfo.m_guidModuleID = GUID_NULL;
if (pszMsmID != NULL)
{
//
// get ModuleID from msm and save it into the global structure
//
IFFAILED_EXIT(CLSIDFromString(LPOLESTR(pszMsmID), &g_MsmInfo.m_guidModuleID));
}
IFFAILED_EXIT(FillMsmForInitialize());
hr = S_OK;
Exit:
return hr;
}
HRESULT GetInfoMsmgenCommandLineParameters(const DWORD dwGenFlag, wchar_t ** Options, DWORD NumOptions, PWSTR * pszComponentID, PWSTR * pszMsmFile, PWSTR * pszMsmID, PWSTR * pszTemplateFile)
{
HRESULT hr = S_OK;
DWORD i = 0;
PARAMETER_CHECK_NTC((dwGenFlag == MSMGEN_FROM_MANFILE) || (dwGenFlag == MSMGEN_FROM_MANLIST));
PARAMETER_CHECK_NTC(NumOptions % 2 == 0);
*pszComponentID = NULL;
*pszMsmFile = NULL;
*pszMsmID = NULL;
*pszTemplateFile = NULL;
while ( i < NumOptions)
{
if (Options[i][0] != L'-') // must begin with "-"
goto InvalidOption;
if (_wcsicmp(Options[i], L"-msm") == 0 )
{
if (*pszMsmFile != NULL)
{
ReportError("output msm is specified more than once\n");
goto InvalidOption;
} else
{
*pszMsmFile = Options[i + 1];
}
}
else if (_wcsicmp(Options[i], L"-template") == 0 )
{
if (*pszTemplateFile != NULL)
{
ReportError("TemplateFile is specified more than once\n");
goto InvalidOption;
} else
{
*pszTemplateFile = Options[i + 1];
}
}
else if (_wcsicmp(Options[i], L"-compid") == 0 )
{
if (dwGenFlag == MSMGEN_FROM_MANLIST)
{
ReportError("ComponentID should not be specified for manlist\n");
goto InvalidOption;
}
if (*pszComponentID != NULL)
{
ReportError("ComponentID is specified more than once\n");
goto InvalidOption;
}
else
{
*pszComponentID = Options[i + 1];
}
}
else if (_wcsicmp(Options[i], L"-msmid") == 0 )
{
if (*pszMsmID != NULL)
{
ReportError("msmid is specified more than once\n");
goto InvalidOption;
} else
{
*pszMsmID = Options[i + 1];
}
}
else
goto InvalidOption;
i++; // skip the option
i++; // skip the value of the option
}
hr = S_OK;
goto Exit;
InvalidOption:
PrintUsage();
hr = E_INVALIDARG;
Exit:
return hr;
}
HRESULT InitializeAsmInfoW(PCWSTR pszManifestFile, PCWSTR pszComponent)
{
HRESULT hr = S_OK;
WCHAR tmp[MAX_PATH];
UINT iRet;
LPOLESTR tmpstr = NULL;
PWSTR p = NULL;
PARAMETER_CHECK_NTC(pszManifestFile != NULL);
// initialize the global structure of current assembly info
ZeroOutCurrentAssemblyInfo();
//
// set manifest, catalog and AssemblyPath,
//
// the manifest does not exist
if (::GetFileAttributesW(pszManifestFile) == DWORD (-1))
{
ReportError("the manifest file, %S, does not exist, try with manifest file's fullpath!\n", pszManifestFile);
SETFAIL_AND_EXIT;
}
iRet = ::GetFullPathNameW(pszManifestFile, NUMBER_OF(tmp), tmp, NULL);
if ((iRet == 0 ) || (iRet > NUMBER_OF(tmp)))
{
ReportError("Get the fullpath of manifest file, %S, failed with LastError=%d!\n", pszManifestFile, ::GetLastError());
SET_HRERR_AND_EXIT(::GetLastError());
}
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Assign(tmp, wcslen(tmp)));
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32GetLastPathElement(curAsmInfo.m_sbManifestFileName));
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32RemoveLastPathElement());
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32EnsureTrailingPathSeparator()); // Path with a trailing slash is always ready to use
curAsmInfo.m_CchAssemblyPath = curAsmInfo.m_sbAssemblyPath.GetCchAsDWORD();
curAsmInfo.m_CchManifestFileName = curAsmInfo.m_sbManifestFileName.GetCchAsDWORD();
IFFALSE_EXIT(curAsmInfo.m_sbCatalogFileName.Win32Assign(curAsmInfo.m_sbManifestFileName));
IFFALSE_EXIT(curAsmInfo.m_sbCatalogFileName.Win32ChangePathExtension(CATALOG_FILE_EXT, NUMBER_OF(CATALOG_FILE_EXT) -1, eAddIfNoExtension));
IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(curAsmInfo.m_sbCatalogFileName));
if (::GetFileAttributesW(curAsmInfo.m_sbAssemblyPath) == DWORD (-1))
{
ReportError("The catalog file, %S, does not exist!", (PCWSTR)curAsmInfo.m_sbAssemblyPath);
SETFAIL_AND_EXIT;
}
curAsmInfo.m_CchCatalogFileName = curAsmInfo.m_sbCatalogFileName.GetCchAsDWORD();
//
// reset
//
curAsmInfo.m_sbAssemblyPath.Left(curAsmInfo.m_CchAssemblyPath);
curAsmInfo.m_sbManifestFileName.Left(curAsmInfo.m_CchManifestFileName);
//
// set componentID
//
if (pszComponent == NULL)
{
GUID tmpguid;
IFFAILED_EXIT(::CoCreateGuid(&tmpguid));
IFFAILED_EXIT(StringFromCLSID(tmpguid, &tmpstr));
IFFALSE_EXIT(curAsmInfo.m_sbComponentID.Win32Assign(tmpstr, wcslen(tmpstr)));
}
else
{
IFFALSE_EXIT(curAsmInfo.m_sbComponentID.Win32Assign(pszComponent, wcslen(pszComponent)));
}
MsmToUpper(curAsmInfo.m_sbComponentID);
Exit:
CoTaskMemFree(tmpstr);
return hr;
}
HRESULT InitializeAsmInfoA(const string & strManifestFile, const string & strComponent)
{
WCHAR wstrManifestFile[MAX_PATH];
WCHAR wstrComponentID[64];
HRESULT hr = S_OK;
PARAMETER_CHECK_NTC(!strManifestFile.empty());
if (0 == MultiByteToWideChar(CP_ACP, 0, strManifestFile.c_str(), strManifestFile.length(), wstrManifestFile, NUMBER_OF(wstrManifestFile)))
{
ReportError("convert %s to wstr failed!", strManifestFile.c_str());
SETFAIL_AND_EXIT;
}
wstrManifestFile[strManifestFile.length()] = L'\0';
if (!strComponent.empty())
{
if (0 == MultiByteToWideChar(CP_ACP, 0, strComponent.c_str(), strComponent.length(), wstrComponentID, NUMBER_OF(wstrComponentID)))
{
ReportError("convert %s to wstr failed!", strComponent.c_str());
SETFAIL_AND_EXIT;
}
wstrComponentID[strComponent.length()] = L'\0';
}
IFFAILED_EXIT(InitializeAsmInfoW(wstrManifestFile, strComponent.empty() ? NULL : wstrComponentID));
Exit:
return hr;
}
void CleanupMsm()
{
if ( g_MsmInfo.m_hfci != NULL)
{
FCIDestroy(g_MsmInfo.m_hfci);
g_MsmInfo.m_hfci = NULL;
}
if ( g_MsmInfo.m_hdb!= NULL){
MsiDatabaseCommit(g_MsmInfo.m_hdb);
MsiCloseHandle(g_MsmInfo.m_hdb);
g_MsmInfo.m_hdb = NULL;
}
return;
}
HRESULT FinalizedMsm()
{
HRESULT hr = S_OK;
IFFAILED_EXIT(CloseCabinet());
IFFAILED_EXIT(InsertCabinetIntoMsm());
Exit:
DeleteFileW(g_MsmInfo.m_sbCabinet);
CleanupMsm();
return hr;
}
HRESULT CreateMsmForSingleManifest(PCWSTR pszManifestFile, PCWSTR pszComponent)
{
HRESULT hr = S_OK;
PARAMETER_CHECK_NTC(pszManifestFile != NULL);
IFFAILED_EXIT(InitializeAsmInfoW(pszManifestFile, pszComponent));
IFFAILED_EXIT(PutAssemblyIntoMergeModule(MSMGEN_CREATE_MSM_ALWAYS));
IFFAILED_EXIT(FinalizedMsm());
Exit:
return hr;
}
#include <fstream>
#if defined(_WIN64)
#pragma warning(disable: 4244)
#endif
#include <strstream>
#if defined(_WIN64)
#pragma warning(default: 4244)
#endif
void MsmTrimString(string & str)
{
if (!str.empty())
{
string::size_type x = str.find_first_not_of(' ');
if (x != 0)
str.erase(0, x);
if (!str.empty())
{
x = str.find_last_not_of(' ');
if (x != str.length() - 1)
str.erase(x + 1, str.length() - 1 - x);
}
}
return;
}
HRESULT CreateMsmForManifestList(PCWSTR pwszManListFile)
{
HRESULT hr = S_OK;
char pszManListFile[MAX_PATH];
int iBufSize;
string strline;
string strManifestFilename;
string strComponentID;
DWORD numLine = 0;
ifstream manlist;
PARAMETER_CHECK_NTC(pwszManListFile != NULL);
iBufSize = WideCharToMultiByte(CP_ACP, 0, pwszManListFile, wcslen(pwszManListFile), NULL, 0, NULL, NULL);
if (iBufSize > NUMBER_OF(pszManListFile))
{
ReportError("the manlist filename, %S, is longer than MAX_PATH\n", pwszManListFile);
SETFAIL_AND_EXIT;
}
if (0 == WideCharToMultiByte(CP_ACP, 0, pwszManListFile, wcslen(pwszManListFile), pszManListFile, NUMBER_OF(pszManListFile), NULL, NULL))
{
ReportError("the manlist filename, %S, failed to convert to ansi string\n", pwszManListFile);
SETFAIL_AND_EXIT;
}
pszManListFile[wcslen(pwszManListFile)] = '\0';
manlist.open(pszManListFile);
if (manlist.fail())
{
ReportError("the manlist, %S, now as %s, can not be opened\n", pwszManListFile, pszManListFile);
SETFAIL_AND_EXIT;
}
for(; !manlist.eof(); )
{
getline(manlist, strline);
if (strline.empty())
break;
numLine ++;
// extract manifest filename[required] and componentID[optional] and its default value could be empty or "default"
istrstream iline(strline.c_str());
getline(iline, strManifestFilename, ',');
getline(iline, strComponentID);
MsmTrimString(strManifestFilename);
MsmTrimString(strComponentID);
if (strManifestFilename.empty() == TRUE)
{
ReportError("no manifest is specified on line %d in manlist file %S \n", numLine, pwszManListFile);
SETFAIL_AND_EXIT;
}
IFFAILED_EXIT(InitializeAsmInfoA(strManifestFilename, strComponentID));
if (numLine == 1)
{
IFFAILED_EXIT(PutAssemblyIntoMergeModule(MSMGEN_CREATE_MSM_ALWAYS));
}
else
{
IFFAILED_EXIT(PutAssemblyIntoMergeModule(MSMGEN_ADD_ASSEMBLY_INTO_EXIST_MSM));
}
}
IFFAILED_EXIT(FinalizedMsm());
hr = S_OK;
Exit:
return hr;
}
class ManGroupKey{
public:
string strTag;
string strMsmID;
string strMsmFile;
string strTemplateFile;
string strManifest;
};
class ManGroupValue{
public:
string strComponentID;
};
#include <functional>
bool less<ManGroupKey>::operator()(const ManGroupKey& x, const ManGroupKey& y) const
{
if (x.strTag != y.strTag)
return (x.strTag < y.strTag);
if (x.strMsmID != y.strMsmID)
return (x.strMsmID < y.strMsmID);
if (x.strMsmFile != y.strMsmFile)
return (x.strMsmFile < y.strMsmFile);
if (x.strTemplateFile != y.strTemplateFile)
return (x.strTemplateFile < y.strTemplateFile);
return (x.strManifest < y.strManifest);
}
#include <map>
#include <utility>
HRESULT CreateMsmForManifestGroup(PCWSTR pwszMangroupFile)
{
HRESULT hr = S_OK;
ifstream mangroup;
char pszMangroupFile[MAX_PATH];
ManGroupKey mgKey;
ManGroupValue mgValue;
map<ManGroupKey, ManGroupValue> mapManGroup;
map<ManGroupKey, ManGroupValue>::iterator m1_pIter;
typedef pair <ManGroupKey, ManGroupValue> Mangroup_Entry;
int iBufSize;
DWORD numLine;
string strline;
bool fCurrentInAGroup;
bool fStartFromSratch;
string strCurrentMsmid;
string strCurrentMsmFile;
string strCurrentMsmTemplate;
PARAMETER_CHECK_NTC(pwszMangroupFile != NULL);
iBufSize = WideCharToMultiByte(CP_ACP, 0, pwszMangroupFile, wcslen(pwszMangroupFile), NULL, 0, NULL, NULL);
if (iBufSize > NUMBER_OF(pszMangroupFile))
{
ReportError("the manlist filename, %S, is longer than MAX_PATH\n", pwszMangroupFile);
SETFAIL_AND_EXIT;
}
if (0 == WideCharToMultiByte(CP_ACP, 0, pwszMangroupFile, wcslen(pwszMangroupFile), pszMangroupFile, NUMBER_OF(pszMangroupFile), NULL, NULL))
{
ReportError("the manlist filename, %S, failed to convert to ansi string\n", pwszMangroupFile);
SETFAIL_AND_EXIT;
}
pszMangroupFile[wcslen(pwszMangroupFile)] = '\0';
mangroup.open(pszMangroupFile);
if (mangroup.fail())
{
ReportError("the mangroupfile, %S, now as %s, can not be opened\n", pwszMangroupFile, pszMangroupFile);
SETFAIL_AND_EXIT;
}
numLine = 0;
//
// firstly read the file into a map which is sorted during insert
//
for(; !mangroup.eof(); )
{
getline(mangroup, strline);
if (strline.empty())
continue;
istrstream iline(strline.c_str());
if (iline.str() == NULL)
break;
numLine ++;
// clean the key strings
mgKey.strTag.erase();
mgKey.strMsmID.erase();
mgKey.strManifest.erase();
mgKey.strMsmFile.erase();
mgKey.strTemplateFile.erase();
mgValue.strComponentID.erase();
getline(iline, mgKey.strTag, ',');
getline(iline, mgKey.strMsmID, ',');
getline(iline, mgKey.strMsmFile, ',');
getline(iline, mgKey.strManifest, ',');
getline(iline, mgValue.strComponentID, ',');
getline(iline, mgKey.strTemplateFile, ',');
MsmTrimString(mgKey.strTag);
MsmTrimString(mgKey.strMsmID);
MsmTrimString(mgKey.strManifest);
MsmTrimString(mgKey.strMsmFile);
MsmTrimString(mgValue.strComponentID);
MsmTrimString(mgKey.strTemplateFile);
if (mgKey.strTag.empty())
{
ReportError("error on line %d in mangroup file %S, also is %s: Tag or MsmID is empty\n", numLine, pwszMangroupFile, pszMangroupFile);
SETFAIL_AND_EXIT;
}
if (mgKey.strManifest.empty())
{
ReportError("error on line %d in mangroup file %S, also is %s: manifest file is empty\n", numLine, pwszMangroupFile, pszMangroupFile);
SETFAIL_AND_EXIT;
}
if ((mgKey.strTag.compare("0") != 0) && (mgKey.strTag.compare("1") != 0))
{
ReportError("error on line %d in mangroup file %S, also is %s: tag must be 0 or 1\n", numLine, pwszMangroupFile, pszMangroupFile);
SETFAIL_AND_EXIT;
}
if (mgKey.strTag.compare("1") == 0)
{
//
// in this case, msmid and msmfile must be specified
//
if ((mgKey.strMsmFile.empty()) || (mgKey.strMsmID.empty()))
{
ReportError("if the first column is set to be \"1\", output msm file and msmid must be specified in the mangroup file!\n");
SETFAIL_AND_EXIT;
}
}
mapManGroup.insert(Mangroup_Entry(mgKey, mgValue));
}
fCurrentInAGroup = false;
fStartFromSratch = true;
for ( m1_pIter = mapManGroup.begin( ); m1_pIter != mapManGroup.end( ); m1_pIter++ )
{
mgKey = m1_pIter->first;
mgValue = m1_pIter->second;
if (mgKey.strTag.compare("1") == 0)
{
if (fCurrentInAGroup == false)
{
fStartFromSratch = true;
fCurrentInAGroup = true;
strCurrentMsmid = mgKey.strMsmID;
strCurrentMsmFile = mgKey.strMsmFile;
strCurrentMsmTemplate = mgKey.strTemplateFile;
}else
{
if (strCurrentMsmid != mgKey.strMsmID)
{
IFFAILED_EXIT(FinalizedMsm());
fStartFromSratch = true;
fCurrentInAGroup = true;
strCurrentMsmid = mgKey.strMsmID;
strCurrentMsmFile = mgKey.strMsmFile;
strCurrentMsmTemplate = mgKey.strTemplateFile;
} else
{
// they must share the same msmID and msmfile
if (!mgKey.strMsmFile.empty())
{
if (mgKey.strMsmFile != strCurrentMsmFile)
{
ReportError("must share the same msm output file\n");
SETFAIL_AND_EXIT;
}
}
if (!mgKey.strTemplateFile.empty())
{
if (mgKey.strTemplateFile != strCurrentMsmTemplate)
{
ReportError("must use the same msm templatefile\n");
SETFAIL_AND_EXIT;
}
}
}
}
} else if (mgKey.strTag == "0")
{
if (fCurrentInAGroup == true)
{
// close current manifest group
IFFAILED_EXIT(FinalizedMsm());
}
fStartFromSratch = true;
fCurrentInAGroup = false;
}
else
{
// impossible case
ReportError("tag is neither 0 nor 1\n");
SETFAIL_AND_EXIT;
}
if (fStartFromSratch)
{
IFFAILED_EXIT(InitializeMsmA(mgKey.strManifest, mgKey.strMsmFile, mgKey.strMsmID, mgKey.strTemplateFile));
IFFAILED_EXIT(InitializeAsmInfoA(mgKey.strManifest, mgValue.strComponentID));
IFFAILED_EXIT(PutAssemblyIntoMergeModule(MSMGEN_CREATE_MSM_ALWAYS));
}
else
{
ASSERT_NTC(fCurrentInAGroup == true);
if (fCurrentInAGroup)
{
IFFAILED_EXIT(InitializeAsmInfoA(mgKey.strManifest, mgValue.strComponentID));
IFFAILED_EXIT(PutAssemblyIntoMergeModule(MSMGEN_ADD_ASSEMBLY_INTO_EXIST_MSM));
}
}
// for single generation
if (fCurrentInAGroup == false)
{
ASSERT_NTC(fStartFromSratch == true);
IFFAILED_EXIT(FinalizedMsm());
}
fStartFromSratch = false;
}
if (fCurrentInAGroup == true)
IFFAILED_EXIT(FinalizedMsm());
Exit:
return hr;
}
extern "C" int __cdecl wmain(int argc, wchar_t** argv)
{
HRESULT hr = S_OK;
PWSTR pszComponentID = NULL, pszMsmFile = NULL, pszMsmID = NULL, pszTemplateFile = NULL;
DWORD dwGenFlag;
if ((argc < 3) || ((argc % 2) != 1))
{
PrintUsage();
hr = E_INVALIDARG;
goto Exit;
}
if (!FusionpInitializeHeap(NULL)){
hr = HRESULT_FROM_WIN32(::GetLastError());
goto Exit;
}
CoInitialize(NULL);
//
// the first parameter must be "manfile" or "manlist" or "mangroup"
//
if (_wcsicmp(argv[1], L"manfile") == 0)
{
dwGenFlag = MSMGEN_FROM_MANFILE;
}
else if (_wcsicmp(argv[1], L"manlist") == 0)
{
dwGenFlag = MSMGEN_FROM_MANLIST;
}
else if (_wcsicmp(argv[1], L"mangroup") == 0)
{
dwGenFlag = dwGenFlag = MSMGEN_FROM_MANGROUP;
if ((argc != 3) && (argc != 5))
{
goto InvalidParam;
}
if (argc == 5)
{
// it must try to specify a template
if (_wcsicmp(argv[3], L"-template") != 0)
{
goto InvalidParam;
}else
{
IFFALSE_EXIT(g_sbTemplateFile.Win32Assign(argv[4], wcslen(argv[4])));
}
}
}
else
{
goto InvalidParam;
}
//check the existence of the input file
if ( GetFileAttributesW(argv[2]) == DWORD (-1))
{
ReportError("man file does not exist!\n");
goto InvalidParam;
}
else
{
if (dwGenFlag == MSMGEN_FROM_MANFILE)
{
CStringBuffer manfile;
CSmallStringBuffer ext;
IFFALSE_EXIT(manfile.Win32Assign(argv[2], wcslen(argv[2])));
IFFALSE_EXIT(manfile.Win32GetPathExtension(ext));
if (ext.Cch() == 0)
{
ReportError("Manifest file must has ext as .man or .manifest\n");
goto InvalidParam;
}
}
}
if ((dwGenFlag == MSMGEN_FROM_MANFILE) || (dwGenFlag == MSMGEN_FROM_MANLIST))
{
//
// parse and validate parameters
//
IFFAILED_EXIT(GetInfoMsmgenCommandLineParameters(dwGenFlag, argv+3, argc-3, &pszComponentID, &pszMsmFile, &pszMsmID, &pszTemplateFile));
}
switch(dwGenFlag)
{
case MSMGEN_FROM_MANFILE:
IFFAILED_EXIT(InitializeMsmW(argv[2], pszMsmFile, pszMsmID, pszTemplateFile));
IFFAILED_EXIT(CreateMsmForSingleManifest(argv[2], pszComponentID));
break;
case MSMGEN_FROM_MANLIST:
if (pszComponentID != NULL)
{
ReportError("componentID should not be specified with manlist\n");
goto InvalidParam;
}
IFFAILED_EXIT(InitializeMsmW(argv[2], pszMsmFile, pszMsmID, pszTemplateFile));
IFFAILED_EXIT(CreateMsmForManifestList(argv[2]));
break;
case MSMGEN_FROM_MANGROUP:
IFFAILED_EXIT(CreateMsmForManifestGroup(argv[2]));
break;
}
hr = S_OK;
goto Exit;
InvalidParam:
PrintUsage();
hr = E_INVALIDARG;
Exit:
CoUninitialize();
CleanupMsm();
if (hr == S_OK)
printf("msm is generated successfully!");
else
printf("msm is failed to be generated!");
return (hr == S_OK) ? 0 : 1;
}