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.
1770 lines
56 KiB
1770 lines
56 KiB
#include <windows.h>
|
|
#include <fusenetincludes.h>
|
|
#include <stdio.h>
|
|
#include "mg.h"
|
|
#include "manifestnode.h"
|
|
#include "xmlutil.h"
|
|
#include "assemblycache.h"
|
|
|
|
#include "version.h"
|
|
|
|
#define DIRECTORY_PATH 0
|
|
#define FILE_PATH 1
|
|
|
|
|
|
#define DEFAULT_POLLING_INTERVAL L"6"
|
|
|
|
#define MAX_DEPLOY_DIRS (5)
|
|
CString g_sDeployDirs[MAX_DEPLOY_DIRS];
|
|
DWORD g_dwDeployDirs=0;
|
|
|
|
typedef enum _COMMAND_MODE_ {
|
|
CmdUsage,
|
|
CmdTemplate,
|
|
CmdList,
|
|
CmdDependencyList,
|
|
CmdSubscription,
|
|
CmdManifest,
|
|
} COMMAND_MODE, *LPCOMMAND_MODE;
|
|
|
|
CString g_sTargetDir;
|
|
CString g_sTemplateFile;
|
|
CString g_sAppManifestURL;
|
|
CString g_sPollingInterval;
|
|
CString g_sSubscriptionManifestDir;
|
|
CString g_sAppManifestFile;
|
|
|
|
|
|
|
|
CString g_sAppBase;
|
|
|
|
BOOL g_bFailOnWarnings=TRUE;
|
|
BOOL g_bLookInGACForDependencies;
|
|
BOOL g_bCopyDependentSystemAssemblies;
|
|
|
|
class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30;
|
|
|
|
|
|
typedef HRESULT(*PFNGETCORSYSTEMDIRECTORY)(LPWSTR, DWORD, LPDWORD);
|
|
typedef HRESULT (__stdcall *PFNCREATEASSEMBLYCACHE) (IAssemblyCache **ppAsmCache, DWORD dwReserved);
|
|
|
|
#define WZ_MSCOREE_DLL_NAME L"mscoree.dll"
|
|
#define GETCORSYSTEMDIRECTORY_FN_NAME "GetCORSystemDirectory"
|
|
#define CREATEASSEMBLYCACHE_FN_NAME "CreateAssemblyCache"
|
|
#define WZ_FUSION_DLL_NAME L"Fusion.dll"
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CreateFusionAssemblyCache
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CreateFusionAssemblyCache(IAssemblyCache **ppFusionAsmCache)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HMODULE hEEShim = NULL;
|
|
HMODULE hFusion = NULL;
|
|
WCHAR szFusionPath[MAX_PATH];
|
|
DWORD ccPath = MAX_PATH;
|
|
|
|
PFNGETCORSYSTEMDIRECTORY pfnGetCorSystemDirectory = NULL;
|
|
PFNCREATEASSEMBLYCACHE pfnCreateAssemblyCache = NULL;
|
|
|
|
// Find out where the current version of URT is installed
|
|
hEEShim = LoadLibrary(WZ_MSCOREE_DLL_NAME);
|
|
if(!hEEShim)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
pfnGetCorSystemDirectory = (PFNGETCORSYSTEMDIRECTORY)
|
|
GetProcAddress(hEEShim, GETCORSYSTEMDIRECTORY_FN_NAME);
|
|
|
|
if((!pfnGetCorSystemDirectory))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get cor path.
|
|
if (FAILED(hr = (pfnGetCorSystemDirectory(szFusionPath, MAX_PATH, &ccPath))))
|
|
goto exit;
|
|
|
|
|
|
// Form path to fusion.
|
|
lstrcatW(szFusionPath, WZ_FUSION_DLL_NAME);
|
|
hFusion = LoadLibrary(szFusionPath);
|
|
if(!hFusion)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get method ptr.
|
|
pfnCreateAssemblyCache = (PFNCREATEASSEMBLYCACHE)
|
|
GetProcAddress(hFusion, CREATEASSEMBLYCACHE_FN_NAME);
|
|
|
|
if((!pfnCreateAssemblyCache))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Create the fusion cache interface.
|
|
if (FAILED(hr = (pfnCreateAssemblyCache(ppFusionAsmCache, 0))))
|
|
goto exit;
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// PathNormalize
|
|
// Creates absolute path from relative, using current directory of mg.exe or parent process.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT PathNormalize(LPWSTR pwzPath, LPWSTR *ppwzAbsolutePath, DWORD dwFlag, BOOL bExists)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR pwzTempDir[MAX_PATH], pwzAbsolutePath[MAX_PATH];
|
|
DWORD ccDir = MAX_PATH;
|
|
|
|
*ppwzAbsolutePath = NULL;
|
|
//If path is relative, prepend the current directory
|
|
if (PathIsRelative(pwzPath))
|
|
{
|
|
GetCurrentDirectory(ccDir, pwzTempDir);
|
|
StrCat(pwzTempDir, L"\\");
|
|
StrCat(pwzTempDir, pwzPath);
|
|
}
|
|
else
|
|
StrCpy(pwzTempDir, pwzPath);
|
|
|
|
|
|
if (!PathCanonicalize(pwzAbsolutePath, pwzTempDir))
|
|
{
|
|
printf("Dir \"%ws\" canonicalize error\n", pwzTempDir);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
//If path is supposed to be a diesctory, append a trailing slash if not already there
|
|
ccDir = lstrlen(pwzAbsolutePath);
|
|
if (dwFlag == DIRECTORY_PATH && pwzAbsolutePath[ccDir -1] != L'\\')
|
|
{
|
|
pwzAbsolutePath[ccDir] = L'\\';
|
|
pwzAbsolutePath[ccDir +1] = L'\0';
|
|
}
|
|
|
|
//Make sure the direcotry exists
|
|
if (dwFlag == DIRECTORY_PATH && !bExists)
|
|
{
|
|
if(!PathIsDirectory(pwzAbsolutePath))
|
|
{
|
|
printf("Dir \"%ws\" is not a valid directory\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
//Make sure the file exists
|
|
else if (dwFlag == FILE_PATH)
|
|
{
|
|
if(!bExists)
|
|
{
|
|
if(!PathFileExists(pwzAbsolutePath))
|
|
{
|
|
printf("File \"%ws\" does not exist\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
if(PathIsDirectory(pwzAbsolutePath))
|
|
{
|
|
printf("File \"%ws\" is a directory\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
(*ppwzAbsolutePath) = WSTRDupDynamic(pwzAbsolutePath);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// IsUniqueManifest
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT IsUniqueManifest(List<ManifestNode *> *pSeenAssemblyList,
|
|
ManifestNode *pManifestNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ManifestNode *pCurrentNode=NULL;
|
|
LISTNODE pos;
|
|
|
|
//cycle through list of unique manifests seen so far
|
|
//if new manifest is not found, add it to the list
|
|
pos = pSeenAssemblyList->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
if (pCurrentNode = pSeenAssemblyList->GetNext(pos))
|
|
{
|
|
//Not Unique, go return
|
|
if ((hr =pCurrentNode->IsEqual(pManifestNode)) == S_OK)
|
|
{
|
|
hr= S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//No match, AsmId is unique, add it to the list
|
|
//Dont release pAsmId since list doesnt ref count
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// DequeueItem
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT DequeueItem(List<ManifestNode*> *pList, ManifestNode** ppManifestNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LISTNODE pos = NULL;
|
|
|
|
(*ppManifestNode) = NULL;
|
|
|
|
pos = pList->GetHeadPosition();
|
|
if (!pos)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
(*ppManifestNode) = pList->GetAt(pos);
|
|
pList->RemoveAt(pos);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ProbeForAssemblyInPath
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT ProbeForAssemblyInPath(CString &sDeployDir, IAssemblyIdentity *pName, ManifestNode **ppManifestNode) //LPWSTR *ppwzFilePath, DWORD *pdwType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD cbBuf = 0, ccBuf =0 ;
|
|
LPWSTR pwzBuf = NULL;
|
|
|
|
CString sName, sLocale, sPublicKeyToken, sCLRDisplayName, sRelativeAssemblyPath;
|
|
CString sProbingPaths[6];
|
|
IAssemblyIdentity *pAssemblyId= NULL;
|
|
IAssemblyManifestImport *pManImport=NULL;
|
|
|
|
|
|
// first try to find assembly by probing
|
|
if(FAILED(hr = pName->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwzBuf, &cbBuf)))
|
|
goto exit;
|
|
sName.TakeOwnership(pwzBuf);
|
|
|
|
if(FAILED(hr = pName->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE, &pwzBuf, &cbBuf)))
|
|
goto exit;
|
|
sLocale.TakeOwnership(pwzBuf);
|
|
|
|
if(FAILED(hr = pName->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN, &pwzBuf, &ccBuf)
|
|
&& hr != HRESULT_FROM_WIN32(ERROR_NOT_FOUND)))
|
|
goto exit;
|
|
else if(hr == S_OK)
|
|
sPublicKeyToken.TakeOwnership(pwzBuf);
|
|
|
|
//bugbug - Hack to supress warning messages for not being able to find mscorlib
|
|
if(sPublicKeyToken._pwz && !StrCmpI(sPublicKeyToken._pwz, L"b77a5c561934e089") && !StrCmpI(sName._pwz, L"mscorlib"))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
//Set up the six different probing locations
|
|
// 1: appBase\AssemblyName.dll
|
|
// 2: appBase\AssemblyName.exe
|
|
// 3: appBase\AssemblyName\AssemblyName.dll
|
|
// 4: appBase\AssemblyName\AssemblyName.exe
|
|
// 5: appBase\local\AssemblyName\AssemblyName.dll
|
|
// 6: appBase\local\AssemblyName\AssemblyName.exe
|
|
|
|
sProbingPaths[0].Assign(sDeployDir);
|
|
sProbingPaths[0].Append(sName);
|
|
sProbingPaths[1].Assign(sProbingPaths[0]);
|
|
|
|
sProbingPaths[0].Append(L".dll");
|
|
sProbingPaths[1].Append(L".exe");
|
|
|
|
sProbingPaths[2].Assign(sDeployDir);
|
|
sProbingPaths[2].Append(sName);
|
|
sProbingPaths[2].Append(L"\\");
|
|
sProbingPaths[2].Append(sName);
|
|
sProbingPaths[3].Assign(sProbingPaths[2]);
|
|
|
|
sProbingPaths[2].Append(L".dll");
|
|
sProbingPaths[3].Append(L".exe");
|
|
|
|
sProbingPaths[4].Assign(sDeployDir);
|
|
sProbingPaths[4].Append(sLocale);
|
|
sProbingPaths[4].Append(L"\\");
|
|
sProbingPaths[4].Append(sName);
|
|
sProbingPaths[4].Append(L"\\");
|
|
sProbingPaths[4].Append(sName);
|
|
sProbingPaths[5].Assign(sProbingPaths[4]);
|
|
|
|
sProbingPaths[4].Append(L".dll");
|
|
sProbingPaths[5].Append(L".exe");
|
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
//Check first to see if the file exists
|
|
if (GetFileAttributes(sProbingPaths[i]._pwz) != -1)
|
|
{
|
|
hr = CreateAssemblyManifestImport(&pManImport, sProbingPaths[i]._pwz, NULL, 0);
|
|
if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_BAD_FORMAT))
|
|
goto exit;
|
|
|
|
if(hr == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT) || (hr = pManImport->GetAssemblyIdentity(&pAssemblyId)) != S_OK)
|
|
{
|
|
SAFERELEASE(pManImport);
|
|
continue;
|
|
}
|
|
|
|
//bugbug - need to make IsEqual function more robust
|
|
//sanity check to make sure the assemblies are the same
|
|
if (pName->IsEqual(pAssemblyId) != S_OK)
|
|
{
|
|
SAFERELEASE(pAssemblyId);
|
|
SAFERELEASE(pManImport);
|
|
continue;
|
|
}
|
|
|
|
// Match found
|
|
(*ppManifestNode) = new ManifestNode(pManImport,
|
|
sDeployDir._pwz,
|
|
sProbingPaths[i]._pwz + sDeployDir._cc - 1,
|
|
PRIVATE_ASSEMBLY);
|
|
|
|
SAFERELEASE(pAssemblyId);
|
|
SAFERELEASE(pManImport);
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// assembly not found in this dir.
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
|
|
exit:
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ProbeForAssemblyInGAC
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT ProbeForAssemblyInGAC(IAssemblyIdentity *pName, ManifestNode **ppManifestNode) //LPWSTR *ppwzFilePath, DWORD *pdwType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD cbBuf = 0, ccBuf =0 ;
|
|
LPWSTR pwzBuf = NULL;
|
|
IAssemblyManifestImport *pManImport=NULL;
|
|
|
|
CString sCLRDisplayName;
|
|
|
|
WCHAR pwzPath[MAX_PATH];
|
|
ASSEMBLY_INFO asmInfo;
|
|
IAssemblyCache *pAsmCache = NULL;
|
|
|
|
memset(&asmInfo, 0, sizeof(asmInfo));
|
|
asmInfo.pszCurrentAssemblyPathBuf = pwzPath;
|
|
asmInfo.cchBuf = MAX_PATH;
|
|
|
|
if (FAILED(hr = CreateFusionAssemblyCache(&pAsmCache)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = pName->GetCLRDisplayName(NULL, &pwzBuf, &ccBuf)))
|
|
goto exit;
|
|
sCLRDisplayName.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
if ((hr = pAsmCache->QueryAssemblyInfo(0, sCLRDisplayName._pwz, &asmInfo)) == S_OK)
|
|
{
|
|
// Assembly found in GAC
|
|
if ((hr = CreateAssemblyManifestImport(&pManImport, asmInfo.pszCurrentAssemblyPathBuf, NULL, 0)) != S_OK)
|
|
goto exit;
|
|
|
|
(*ppManifestNode) = new ManifestNode(pManImport,
|
|
NULL,
|
|
asmInfo.pszCurrentAssemblyPathBuf,
|
|
GAC_ASSEMBLY);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
SAFERELEASE(pAsmCache);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ProbeForAssembly
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT ProbeForAssembly(IAssemblyIdentity *pName, ManifestNode **ppManifestNode) //LPWSTR *ppwzFilePath, DWORD *pdwType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwDirCount=0;
|
|
|
|
*ppManifestNode = NULL;
|
|
|
|
while(dwDirCount < g_dwDeployDirs)
|
|
{
|
|
if(SUCCEEDED(hr = ProbeForAssemblyInPath( g_sDeployDirs[dwDirCount],
|
|
pName, ppManifestNode)))
|
|
goto exit;
|
|
|
|
dwDirCount++;
|
|
}
|
|
|
|
if( (IsKnownAssembly(pName, KNOWN_SYSTEM_ASSEMBLY) == S_OK)
|
|
&& (!g_bCopyDependentSystemAssemblies) )
|
|
{
|
|
hr = S_FALSE; // ignore system dependencies
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if( g_bLookInGACForDependencies )
|
|
{
|
|
//Can't find assembly by probing
|
|
//Try to find the assembly in the GAC.
|
|
if(SUCCEEDED(hr = ProbeForAssemblyInGAC(pName, ppManifestNode)))
|
|
goto exit;
|
|
}
|
|
|
|
// assembly not found
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
|
|
exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// FindAssemblies
|
|
// note: Assumes that pwzDir has a trailing slash.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT FindAllAssemblies (LPWSTR pwzDir, List<ManifestNode *> *pManifestList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fdFile;
|
|
IAssemblyIdentity *pTempAsmId=NULL;
|
|
IAssemblyManifestImport *pManifestImport = NULL;
|
|
ManifestNode *pManifestNode = NULL;
|
|
CString sSearchString;
|
|
DWORD dwLastError = 0;
|
|
|
|
// set up search string to find all files in the passed in directory
|
|
sSearchString.Assign(pwzDir);
|
|
sSearchString.Append(L"*");
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: Search path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
hFind = FindFirstFile(sSearchString._pwz, &fdFile);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
// BUGBUG - getlasterror() ?
|
|
hr = E_FAIL;
|
|
printf("Find file error\n");
|
|
goto exit;
|
|
}
|
|
|
|
//enumerate through all the files in the directory,
|
|
// and recursivly call FindAllAssemblies on any directories encountered
|
|
while(TRUE)
|
|
{
|
|
if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
|
|
{
|
|
CString sFilePath;
|
|
|
|
//create absolute file name by appending the filename to the dir name
|
|
sFilePath.Assign(pwzDir);
|
|
sFilePath.Append(fdFile.cFileName);
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: File path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
//If the file is a directory, recursivly call FindAllAssemblies
|
|
if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
|
{
|
|
sFilePath.Append(L"\\");
|
|
if (FAILED(hr = FindAllAssemblies(sFilePath._pwz, pManifestList)))
|
|
goto exit;
|
|
}
|
|
// If a file, check to see if it is a Assembly, if it is, add it to our master list
|
|
else
|
|
{
|
|
if((hr = CreateAssemblyManifestImport(&pManifestImport, sFilePath._pwz, NULL, 0)) == S_OK)
|
|
{
|
|
// check to make sure file we just opened wasnt just an XML file
|
|
if ((hr =pManifestImport->GetAssemblyIdentity(&pTempAsmId)) == S_OK)
|
|
{
|
|
// List does not AddRef, so dont release pManifestImport and refcount will stay at one
|
|
// Clean up after list is no longer needed.
|
|
pManifestNode = new ManifestNode(pManifestImport,
|
|
g_sAppBase._pwz,
|
|
sFilePath._pwz+g_sAppBase._cc-1,
|
|
PRIVATE_ASSEMBLY);
|
|
pManifestList->AddTail(pManifestNode);
|
|
SAFERELEASE(pTempAsmId);
|
|
}
|
|
else if (FAILED(hr))
|
|
goto exit;
|
|
|
|
SAFERELEASE(pManifestImport);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FindNextFile(hFind, &fdFile))
|
|
{
|
|
dwLastError = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(dwLastError == ERROR_NO_MORE_FILES)
|
|
hr = S_OK;
|
|
else
|
|
hr = HRESULT_FROM_WIN32(dwLastError);
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// TraverseManifestDependencyTree
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT TraverseManifestDependencyTrees(List<ManifestNode *> *pManifestList,
|
|
List<LPWSTR> *pAssemblyFileList, List<ManifestNode *> *pUniqueAssemblyList, BOOL bListMode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAssemblyManifestImport *pDepManifestImport=NULL;
|
|
IManifestInfo *pDepAsmInfo=NULL, *pFileInfo=NULL;
|
|
IAssemblyIdentity *pAsmId=NULL;
|
|
ManifestNode *pManifestNode=NULL, *pDepManifestNode = NULL;
|
|
LPWSTR pwz = NULL;
|
|
DWORD index = 0, cb = 0, cc = 0, dwFlag = 0, dwHash=0, dwType=0;
|
|
CString sFileName, sRelativeFilePath, sAbsoluteFilePath, sBuffer, sManifestName;
|
|
|
|
|
|
while((hr = DequeueItem(pManifestList, &pManifestNode)) == S_OK)
|
|
{
|
|
// If Assembly has already been parsed, no need doing it again, skip to the next assembly
|
|
if ((hr = IsUniqueManifest(pUniqueAssemblyList, pManifestNode)) != S_OK)
|
|
{
|
|
SAFEDELETE(pManifestNode);
|
|
continue;
|
|
}
|
|
pUniqueAssemblyList->AddTail(pManifestNode);
|
|
|
|
pManifestNode->GetManifestFilePath(&pwz);
|
|
sManifestName.TakeOwnership(pwz);
|
|
|
|
//If the manifest was found by probing, add its name to the list of files
|
|
hr =pManifestNode->GetManifestType(&dwType);
|
|
if (dwType == PRIVATE_ASSEMBLY)
|
|
{
|
|
|
|
dwHash = HashString(sManifestName._pwz, HASHTABLE_SIZE, false);
|
|
pAssemblyFileList[dwHash].AddTail(WSTRDupDynamic(sManifestName._pwz));
|
|
|
|
//need the relative dir path of the manifest rwt the app base for future use
|
|
sRelativeFilePath.Assign(sManifestName);
|
|
|
|
sRelativeFilePath.RemoveLastElement();
|
|
if(sRelativeFilePath.CharCount() > 1) // add a backslash only if string has any non-null chars. i.e. stringLength is non-zero; note here _cc holds 1(null-char).
|
|
sRelativeFilePath.Append(L"\\");
|
|
}
|
|
|
|
if(bListMode)
|
|
fprintf(stderr, "\nAssembly %ws:\n", sManifestName._pwz);
|
|
|
|
//Add all dependant assemblies to the queue to be later traversed
|
|
while ((hr = pManifestNode->GetNextAssembly(index++, &pDepAsmInfo)) == S_OK)
|
|
{
|
|
if(FAILED(hr = pDepAsmInfo->Get(MAN_INFO_DEPENDENT_ASM_ID, (LPVOID *)&pAsmId, &cb, &dwFlag)))
|
|
goto exit;
|
|
|
|
pAsmId->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwz, &cc);
|
|
|
|
//Try to find the assembly by first probing, then by checking in the GAC.
|
|
if(FAILED(hr = ProbeForAssembly(pAsmId, &pDepManifestNode)))
|
|
{
|
|
//Assembly not found, display warning message
|
|
//Bugbug, should mg still spit out a manifest knowing that things are missing?
|
|
fprintf(stderr, "WRN: Unable to find dependency %ws. in manifest %ws\n", pwz, sManifestName._pwz);
|
|
if(g_bFailOnWarnings)
|
|
{
|
|
fprintf(stderr, "Warning treated as error. mg exiting....\n");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
SAFERELEASE(pAsmId);
|
|
continue;
|
|
}
|
|
else if (hr == S_OK)
|
|
{
|
|
//Dont release since no add refing in the list is taking place
|
|
if ((hr = IsUniqueManifest(pUniqueAssemblyList, pDepManifestNode)) == S_OK)
|
|
pManifestList->AddTail(pDepManifestNode);
|
|
|
|
SAFERELEASE(pAsmId);
|
|
|
|
if(bListMode)
|
|
fprintf(stderr, "\tDependant Assembly: %ws\n", pwz);
|
|
}
|
|
SAFERELEASE(pDepAsmInfo);
|
|
}
|
|
|
|
// Add all files to hash table
|
|
index = 0;
|
|
pManifestNode->GetManifestType(&dwType);
|
|
while (dwType == PRIVATE_ASSEMBLY && pManifestNode->GetNextFile(index++, &pFileInfo) == S_OK)
|
|
{
|
|
LPWSTR pwzFileName = NULL;
|
|
if(FAILED(pFileInfo->Get(MAN_INFO_ASM_FILE_NAME, (LPVOID *)&pwz, &cb, &dwFlag)))
|
|
goto exit;
|
|
|
|
sBuffer.TakeOwnership(pwz);
|
|
sFileName.Assign(sRelativeFilePath);
|
|
sFileName.Append(sBuffer);
|
|
sAbsoluteFilePath.Assign(g_sAppBase);
|
|
sAbsoluteFilePath.Append(sFileName);
|
|
sFileName.ReleaseOwnership(&pwzFileName);
|
|
|
|
dwHash = HashString(pwzFileName, HASHTABLE_SIZE, false);
|
|
pAssemblyFileList[dwHash].AddTail(pwzFileName);
|
|
|
|
//If file is listed as part of an assembly, but cannot be found, display a warning.
|
|
//Bugbug, should mg still spit out a manifest knowing that things are missing?
|
|
if(!PathFileExists(sAbsoluteFilePath._pwz))
|
|
printf("Warning: File \"%ws\" does not exist and is called out in \"%ws\"\n",sAbsoluteFilePath._pwz, sManifestName._pwz);
|
|
|
|
if(bListMode)
|
|
fprintf(stderr, "\tDependant File: %ws\n", pwzFileName);
|
|
|
|
//Release ownership since string is now part of hash table and hash table does not ref count
|
|
// sFileName.ReleaseOwnership();
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CrossReferenceFiles
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CrossReferenceFiles(LPWSTR pwzDir, List<LPWSTR> *pAssemblyFileList, List<LPWSTR> *pRawFiles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fdFile;
|
|
DWORD dwHash = 0;
|
|
LISTNODE pos;
|
|
LPWSTR pwzBuf=NULL;
|
|
bool bRawFile = FALSE;
|
|
DWORD dwLastError = 0;
|
|
|
|
CString sSearchString;
|
|
|
|
// set up search string to find all files in the passed in directory
|
|
sSearchString.Assign(pwzDir);
|
|
sSearchString.Append(L"*");
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: Search path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
hFind = FindFirstFile(sSearchString._pwz, &fdFile);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = E_FAIL;
|
|
printf("Find file error\n");
|
|
goto exit;
|
|
}
|
|
|
|
//enumerate through all the files in the directory,
|
|
// and recursivly call FindAllAssemblies on any directories encountered
|
|
while(TRUE)
|
|
{
|
|
if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
|
|
{
|
|
CString sFilePath;
|
|
|
|
//create absolute file name by appending the filename to the dir name
|
|
sFilePath.Assign(pwzDir);
|
|
sFilePath.Append(fdFile.cFileName);
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: Search path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
//if file is actually a direcoty, recrusivly call crossRefernceFiles on the Directory
|
|
if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
|
{
|
|
sFilePath.Append(L"\\");
|
|
if (FAILED(hr = CrossReferenceFiles(sFilePath._pwz, pAssemblyFileList, pRawFiles)))
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
//Check to see if the file is in the hash table.
|
|
//If it isnt, then we know it is not called out from any assembly
|
|
//add it to the Raw file list
|
|
bRawFile = TRUE;
|
|
dwHash = HashString(sFilePath._pwz+g_sAppBase._cc - 1, HASHTABLE_SIZE, false);
|
|
|
|
pos = pAssemblyFileList[dwHash].GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf = pAssemblyFileList[dwHash].GetNext(pos);
|
|
if (!StrCmpI(pwzBuf, sFilePath._pwz+g_sAppBase._cc - 1))
|
|
{
|
|
bRawFile = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bRawFile)
|
|
{
|
|
pwzBuf = WSTRDupDynamic(sFilePath._pwz+g_sAppBase._cc - 1);
|
|
pRawFiles->AddTail(pwzBuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// BUGBUG - do fnf, check error.
|
|
if (!FindNextFile(hFind, &fdFile))
|
|
{
|
|
dwLastError = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(dwLastError == ERROR_NO_MORE_FILES)
|
|
hr = S_OK;
|
|
else
|
|
hr = HRESULT_FROM_WIN32(dwLastError);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CopyRawFile
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CopyRawFile(LPWSTR pwzFilePath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CString sDest;
|
|
CString sSrc;
|
|
|
|
|
|
sDest.Assign(g_sTargetDir);
|
|
sDest.Append(pwzFilePath); // this should be relative path ...
|
|
|
|
if(FAILED(hr = CreateDirectoryHierarchy(sDest._pwz, NULL)))
|
|
goto exit;
|
|
|
|
sSrc.Assign(g_sAppBase);
|
|
sSrc.Append(pwzFilePath);
|
|
|
|
printf(" Copying RawFile from <%ws> TO <%ws> \n", sSrc._pwz, sDest._pwz);
|
|
|
|
if(!::CopyFile(sSrc._pwz, sDest._pwz, FALSE))
|
|
{
|
|
hr = FusionpHresultFromLastError();
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CopyAssemblyBits
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CopyAssemblyBits(CString &sSrcDir, CString &sDestDir, ManifestNode *pManifestNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD nIndex=0;
|
|
DWORD dwFlag;
|
|
DWORD cbBuf;
|
|
LPWSTR pwzBuf=NULL;
|
|
IManifestInfo *pFileInfo = NULL;
|
|
|
|
|
|
if(FAILED(hr = CreateDirectoryHierarchy(sDestDir._pwz, NULL)))
|
|
goto exit;
|
|
|
|
if(!::CopyFile(sSrcDir._pwz, sDestDir._pwz, FALSE))
|
|
{
|
|
hr = FusionpHresultFromLastError();
|
|
goto exit;
|
|
}
|
|
|
|
//copy all file dependecies of the assembly as well
|
|
nIndex = 0;
|
|
|
|
while (pManifestNode->GetNextFile(nIndex++, &pFileInfo) == S_OK)
|
|
{
|
|
if(FAILED(pFileInfo->Get(MAN_INFO_ASM_FILE_NAME, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag)))
|
|
goto exit;
|
|
// sRelativeFilePath.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
|
|
sSrcDir.RemoveLastElement();
|
|
sSrcDir.Append(L"\\");
|
|
sSrcDir.Append(pwzBuf);
|
|
|
|
sDestDir.RemoveLastElement();
|
|
sDestDir.Append(L"\\");
|
|
sDestDir.Append(pwzBuf);
|
|
|
|
// CreateDirectoryHierarchy(sPrivateAssemblyDir._pwz, sRelativeFilePath._pwz);
|
|
if(!::CopyFile(sSrcDir._pwz, sDestDir._pwz, FALSE))
|
|
{
|
|
hr = FusionpHresultFromLastError();
|
|
goto exit;
|
|
}
|
|
|
|
SAFEDELETEARRAY(pwzBuf);
|
|
SAFERELEASE(pFileInfo);
|
|
}
|
|
|
|
exit :
|
|
|
|
SAFEDELETEARRAY(pwzBuf);
|
|
SAFERELEASE(pFileInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CopyAssembly
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CopyAssembly(ManifestNode *pManifestNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CString sDest;
|
|
CString sSrc;
|
|
LPWSTR pwzManifestFilePath = NULL;
|
|
LPWSTR pwzSrcDir=NULL;
|
|
LPWSTR pwzTemp = NULL;
|
|
DWORD dwType;
|
|
IAssemblyIdentity *pAssemblyId = NULL;
|
|
CString sAssemblyName;
|
|
|
|
hr = pManifestNode->GetManifestFilePath(&pwzManifestFilePath);
|
|
|
|
hr = pManifestNode->GetManifestType(&dwType);
|
|
|
|
sDest.Assign(g_sTargetDir);
|
|
|
|
if (dwType == PRIVATE_ASSEMBLY)
|
|
{
|
|
sDest.Append(pwzManifestFilePath); // this should be relative path ...
|
|
|
|
if(FAILED(hr = pManifestNode->GetSrcRootDir(&pwzSrcDir)))
|
|
goto exit;
|
|
sSrc.Assign(pwzSrcDir);
|
|
sSrc.Append(pwzManifestFilePath);
|
|
}
|
|
else if (dwType == GAC_ASSEMBLY)
|
|
{
|
|
LPWSTR pwzBuf = NULL;
|
|
DWORD ccBuf = 0;
|
|
|
|
pManifestNode->GetAssemblyIdentity(&pAssemblyId);
|
|
|
|
if(FAILED(hr = pAssemblyId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
|
|
&pwzBuf,
|
|
&ccBuf)))
|
|
goto exit;
|
|
|
|
if(!(pwzTemp = PathFindFileName(pwzManifestFilePath)))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
sAssemblyName.TakeOwnership(pwzBuf);
|
|
|
|
sAssemblyName.Append(L"\\");
|
|
sAssemblyName.Append(pwzTemp); // manifest file name of the GAC assembly.
|
|
|
|
sDest.Append(sAssemblyName);
|
|
sSrc.Assign(pwzManifestFilePath);
|
|
}
|
|
|
|
printf(" Copying Assembly Man from <%ws> TO <%ws> \n", sSrc._pwz, sDest._pwz);
|
|
hr = CopyAssemblyBits(sSrc, sDest, pManifestNode);
|
|
|
|
if (dwType == GAC_ASSEMBLY)
|
|
{
|
|
// set the install codebase of the assembly copied from GAC
|
|
// to that of its relative path in target dir. This will be written to manifest ??
|
|
hr = pManifestNode->SetManifestFilePath(sAssemblyName._pwz);
|
|
}
|
|
|
|
exit:
|
|
|
|
SAFEDELETEARRAY(pwzSrcDir);
|
|
SAFEDELETEARRAY(pwzManifestFilePath);
|
|
SAFERELEASE(pAssemblyId);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CopyFilesToTargetDir
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CopyFilesToTargetDir(List<ManifestNode*> *pUniqueManifestList, List<LPWSTR> *pRawFiles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ManifestNode *pManifestNode = NULL;
|
|
LISTNODE pos;
|
|
LPWSTR pwzBuf;
|
|
|
|
|
|
//Cycle through all of the unique manifests
|
|
pos = pUniqueManifestList->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pManifestNode = pUniqueManifestList->GetNext(pos);
|
|
|
|
//if the manifest was found by probing initially, then it is already in the Appbase's directory
|
|
//continue to the next manifest
|
|
//if the manifest was found in the GAC and is not a system assembly, copy the
|
|
//assembly into the Appbase
|
|
if(FAILED(hr = CopyAssembly(pManifestNode)))
|
|
goto exit;
|
|
}
|
|
|
|
//Copy RawFiles to Target Dir
|
|
pos = pRawFiles->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf = pRawFiles->GetNext(pos);
|
|
if(FAILED(hr = CopyRawFile(pwzBuf)))
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// PrivatizeAssemblies
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT PrivatizeAssemblies(List<ManifestNode*> *pUniqueManifestList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ManifestNode *pManifestNode = NULL;
|
|
LISTNODE pos;
|
|
LPWSTR pwzBuf =NULL;
|
|
DWORD dwType = 0, ccBuf = 0, cbBuf = 0, dwFlag = 0, nIndex = 0;
|
|
IAssemblyIdentity *pAssemblyId = NULL;
|
|
IManifestInfo *pFileInfo = NULL;
|
|
WCHAR pwzPath[MAX_PATH];
|
|
ASSEMBLY_INFO asmInfo;
|
|
IAssemblyCache *pAsmCache = NULL;
|
|
|
|
CString sPublicKeyToken, sCLRDisplayName;
|
|
CString sAssemblyName, sAssemblyManifestFileName;
|
|
CString sPrivateAssemblyPath, sPrivateAssemblyDir;
|
|
CString sAssemblyGACPath, sAssemblyGACDir;
|
|
CString sRelativeFilePath, sFileGACPath, sFilePrivatePath;
|
|
CString sBuffer;
|
|
|
|
memset(&asmInfo, 0, sizeof(asmInfo));
|
|
asmInfo.pszCurrentAssemblyPathBuf = pwzPath;
|
|
asmInfo.cchBuf = MAX_PATH;
|
|
|
|
if (FAILED(hr = CreateFusionAssemblyCache(&pAsmCache)))
|
|
goto exit;
|
|
|
|
|
|
//Cycle through all of the unique manifests
|
|
pos = pUniqueManifestList->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pManifestNode = pUniqueManifestList->GetNext(pos);
|
|
hr = pManifestNode->GetManifestType(&dwType);
|
|
|
|
//if the manifest was found by probing initially, then it is already in the Appbase's directory
|
|
//continue to the next manifest
|
|
//if the manifest was found in the GAC and is not a system assembly, copy the
|
|
//assembly into the Appbase
|
|
|
|
if (dwType == PRIVATE_ASSEMBLY)
|
|
continue;
|
|
else if (dwType == GAC_ASSEMBLY)
|
|
{
|
|
pManifestNode->GetAssemblyIdentity(&pAssemblyId);
|
|
|
|
hr = pAssemblyId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN, &pwzBuf, &ccBuf);
|
|
sPublicKeyToken.TakeOwnership(pwzBuf);
|
|
|
|
//if the assembly is a system assembly, skip to next manifest
|
|
if (!StrCmpI(sPublicKeyToken._pwz, L"b77a5c561934e089") || !StrCmpI(sPublicKeyToken._pwz, L"b03f5f7f11d50a3a"))
|
|
{
|
|
SAFERELEASE(pAssemblyId);
|
|
continue;
|
|
}
|
|
|
|
//get the assemblies dir by making a call into CreateAssemblyCache
|
|
if(FAILED(hr = pAssemblyId->GetCLRDisplayName(NULL, &pwzBuf, &ccBuf)))
|
|
goto exit;
|
|
sCLRDisplayName.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
if ((hr = pAsmCache->QueryAssemblyInfo(0, sCLRDisplayName._pwz, &asmInfo)) != S_OK)
|
|
goto exit;
|
|
|
|
sAssemblyGACPath.Assign(asmInfo.pszCurrentAssemblyPathBuf);
|
|
sAssemblyGACPath.LastElement(sAssemblyManifestFileName);
|
|
|
|
sAssemblyGACDir.Assign(sAssemblyGACPath);
|
|
sAssemblyGACDir.RemoveLastElement();
|
|
|
|
|
|
hr = pAssemblyId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwzBuf, &ccBuf);
|
|
sAssemblyName.TakeOwnership(pwzBuf);
|
|
|
|
//set up the new directory to store the assembly in
|
|
// g_sAppBase\assemblyname\,
|
|
sPrivateAssemblyDir.Assign(g_sAppBase);
|
|
sPrivateAssemblyDir.Append(sAssemblyName);
|
|
sPrivateAssemblyDir.Append(L"\\");
|
|
CreateDirectoryHierarchy(sPrivateAssemblyDir._pwz, sAssemblyManifestFileName._pwz);
|
|
|
|
sPrivateAssemblyPath.Assign(sPrivateAssemblyDir);
|
|
sPrivateAssemblyPath.Append(sAssemblyManifestFileName);
|
|
|
|
::CopyFile(sAssemblyGACPath._pwz, sPrivateAssemblyPath._pwz, FALSE);
|
|
|
|
//copy all file dependecies of the assembly as well
|
|
nIndex = 0;
|
|
while (pManifestNode->GetNextFile(nIndex++, &pFileInfo) == S_OK)
|
|
{
|
|
if(FAILED(pFileInfo->Get(MAN_INFO_ASM_FILE_NAME, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag)))
|
|
goto exit;
|
|
sRelativeFilePath.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
sFileGACPath.Assign(sAssemblyGACDir);
|
|
sFileGACPath.Append(sRelativeFilePath);
|
|
|
|
sFilePrivatePath.Assign(sPrivateAssemblyDir);
|
|
sFilePrivatePath.Append(sRelativeFilePath);
|
|
|
|
CreateDirectoryHierarchy(sPrivateAssemblyDir._pwz, sRelativeFilePath._pwz);
|
|
::CopyFile(sFileGACPath._pwz, sFilePrivatePath._pwz, FALSE);
|
|
}
|
|
|
|
//update the manifestnode's FileName field with the new relative path wrt the Appbase
|
|
pManifestNode->SetManifestFilePath(sPrivateAssemblyPath._pwz + g_sAppBase._cc - 1);
|
|
pManifestNode->SetManifestType(PRIVATE_ASSEMBLY);
|
|
|
|
SAFERELEASE(pAssemblyId);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
SAFERELEASE(pAsmCache);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//GetInitialDependencies
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//Bugbug, Big Avalon Hack
|
|
HRESULT GetInitialDependencies(LPWSTR pwzTemplatePath, List<ManifestNode *> *pManifestList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMDocument2 *pXMLDoc = NULL;
|
|
IXMLDOMNode *pRootNode = NULL, *pSearchNode = NULL;
|
|
BSTR bstrSearchString=NULL;
|
|
ManifestNode *pManifestNode = NULL;
|
|
|
|
WCHAR pwzPath[MAX_PATH];
|
|
ASSEMBLY_INFO asmInfo;
|
|
IAssemblyCache *pAsmCache = NULL;
|
|
IAssemblyManifestImport *pManImport = NULL;
|
|
|
|
if(FAILED(hr = LoadXMLDocument(pwzTemplatePath, &pXMLDoc)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = pXMLDoc->get_firstChild(&pRootNode)))
|
|
goto exit;
|
|
|
|
bstrSearchString = ::SysAllocString(L"//shellState[@entryImageType=\"avalon\"]");
|
|
if (!bstrSearchString)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
if (FAILED(hr = pRootNode->selectSingleNode(bstrSearchString, &pSearchNode)))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
if (pSearchNode)
|
|
{
|
|
// Try to find the assembly in the GAC.
|
|
memset(&asmInfo, 0, sizeof(asmInfo));
|
|
asmInfo.pszCurrentAssemblyPathBuf = pwzPath;
|
|
asmInfo.cchBuf = MAX_PATH;
|
|
|
|
if (FAILED(hr = CreateFusionAssemblyCache(&pAsmCache)))
|
|
goto exit;
|
|
|
|
if ((hr = pAsmCache->QueryAssemblyInfo(0, L"Avalon.Application", &asmInfo)) == S_OK)
|
|
{
|
|
if ((hr = CreateAssemblyManifestImport(&pManImport, asmInfo.pszCurrentAssemblyPathBuf, NULL, 0)) != S_OK)
|
|
goto exit;
|
|
|
|
pManifestNode = new ManifestNode(pManImport,
|
|
NULL,
|
|
asmInfo.pszCurrentAssemblyPathBuf,
|
|
GAC_ASSEMBLY);
|
|
pManifestList->AddTail(pManifestNode);
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
fprintf(stderr, "Warning: Cannot find Avalon Runtime in GAC\n");
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if (bstrSearchString)
|
|
::SysFreeString(bstrSearchString);
|
|
SAFERELEASE(pSearchNode);
|
|
SAFERELEASE(pRootNode);
|
|
SAFERELEASE(pXMLDoc);
|
|
SAFERELEASE(pManImport);
|
|
SAFERELEASE(pAsmCache);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CreateSubscriptionManifest
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CreateSubscriptionManifest(LPWSTR pwzApplicationManifestPath,
|
|
LPWSTR pwzSubscriptionManifestPath, LPWSTR pwzURL, LPWSTR pwzPollingInterval)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAssemblyManifestImport *pManImport = NULL;
|
|
IAssemblyIdentity *pAppAssemblyId = NULL;
|
|
CString sSubAssemblyName, sSubcriptionFilePath;
|
|
LPWSTR pwzBuf = NULL;
|
|
DWORD ccBuf = NULL;
|
|
|
|
//createmanifest on the input file
|
|
if(FAILED(hr = CreateAssemblyManifestImport(&pManImport, pwzApplicationManifestPath, NULL, 0)))
|
|
goto exit;
|
|
|
|
if((hr = pManImport->GetAssemblyIdentity(&pAppAssemblyId)) != S_OK)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
//grab the name of the assembly
|
|
//appended with ".subscription", this will be the subscription manifest name
|
|
if(FAILED(hr = pAppAssemblyId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
|
|
&pwzBuf, &ccBuf)))
|
|
goto exit;
|
|
sSubAssemblyName.TakeOwnership(pwzBuf, ccBuf);
|
|
sSubAssemblyName.Append(L".subscription");
|
|
|
|
sSubcriptionFilePath.Assign(pwzSubscriptionManifestPath);
|
|
sSubcriptionFilePath.Append(sSubAssemblyName);
|
|
|
|
if(FAILED(hr = CreateDirectoryHierarchy(sSubcriptionFilePath._pwz, NULL)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = CreateXMLSubscriptionManifest(sSubcriptionFilePath._pwz, pAppAssemblyId, pwzURL, pwzPollingInterval)))
|
|
goto exit;
|
|
|
|
exit:
|
|
SAFERELEASE(pManImport);
|
|
SAFERELEASE(pAppAssemblyId);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// PrintDependencies
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT PrintDependencies(List <LPWSTR> *pRawFileList, List<ManifestNode *> *pUniqueManifestList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwzBuf = NULL, pwz= NULL;
|
|
DWORD dwType = 0;
|
|
ManifestNode *pManifestNode = NULL;
|
|
LISTNODE pos;
|
|
|
|
pos = pRawFileList->GetHeadPosition();
|
|
while(pos)
|
|
{
|
|
pwzBuf = pRawFileList->GetNext(pos);
|
|
fprintf(stderr, "Raw File : %ws\n", pwzBuf);
|
|
}
|
|
|
|
pos = pUniqueManifestList->GetHeadPosition();
|
|
while(pos)
|
|
{
|
|
pManifestNode = pUniqueManifestList->GetNext(pos);
|
|
pManifestNode->GetManifestFilePath(&pwzBuf);
|
|
pManifestNode->GetManifestType(&dwType);
|
|
if (dwType == PRIVATE_ASSEMBLY)
|
|
fprintf(stderr, "Manifest : %ws\n", pwzBuf);
|
|
else
|
|
{
|
|
pwz = StrRChr(pwzBuf, NULL, L'\\') + 1;
|
|
fprintf(stderr, "GAC Manifest : %ws\n", pwz);
|
|
}
|
|
SAFEDELETEARRAY(pwzBuf);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageTopLevel
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageTopLevel()
|
|
{
|
|
printf("Manifest Generator Usage: \n"
|
|
"mg -<mode> [<param_name>:<param_value> ... ]\n"
|
|
"Modes supported in mg\n"
|
|
"t: Generate Template File Mode\n"
|
|
"l: List Mode\n"
|
|
"d: List Dependency Mode\n"
|
|
"s: Subscription Manifest Gereration Mode \n"
|
|
"m: Manifest Generation Mode\n\n"
|
|
"For help on a Mode, Use \"mg -<mode> help\" \n"
|
|
"Valid <param_name>:<param_value> pairs \n"
|
|
"sd:<source_directory_path> \n"
|
|
"td:<target_dir> \n"
|
|
"dd:<dependency_dir> \n"
|
|
"tf:<template_file_path> \n"
|
|
"smd:<subscription_dir> \n"
|
|
"amf:<app_man_file> \n"
|
|
"amu:<app_man_URL> \n"
|
|
"si:<sync_interval> \n"
|
|
"WRN:allow -- meaning allow warnings. Deafault is exit on warnings.\n"
|
|
"GAC:follow -- meaning follow dependencies on GAC. Default is don't probe for dependencies in GAC\n"
|
|
"SYS:copy -- copy dependent system assemblies from GAC to target dir\n"
|
|
);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageCmdTemplate
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageCmdTemplate()
|
|
{
|
|
printf("Usage: \n"
|
|
"Template Mode:\n"
|
|
"mg -t tf:<file_path>\n\n"
|
|
"\t<file_path> = path where template manifest will be created.\n\n"
|
|
);
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageCmdList
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageCmdList()
|
|
{
|
|
printf("Usage: \n"
|
|
"List Mode:\n"
|
|
"mg -l sd:<source_directory_path> [tf:<template_file_path>] [dd:<dependency_dir> \n\n"
|
|
"\t[source_directory_path] = path of Application to chase dependencies\n"
|
|
"\toptional: <template_file_path> = path of Template file\n"
|
|
"\toptional : <dependency_dir> = user defined dependency dir where some dependencies could be found\n\n"
|
|
);
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageCmdDependencyList
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageCmdDependencyList()
|
|
{
|
|
printf("Usage: \n"
|
|
"List Dependency Mode:\n"
|
|
"mg -d sd:<source_directory_path> [dd:<dependency_dir> \n\n"
|
|
"\t<source_directory path> = path of Application to chase dependencies\n\n"
|
|
"\toptional : <dependency_dir> = user defined dependency dir where some dependencies could be found\n\n"
|
|
);
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageCmdSubscription
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageCmdSubscription()
|
|
{
|
|
printf("Usage: \n"
|
|
"Subscription Manifest Gereration Mode:\n"
|
|
"mg -s smd:<subscription_dir> amf:<app_man_file> amu:<app_man_URL> [si:<sync_interval>] \n\n"
|
|
"\t<subscription_dir> = path where subscription manifest will be created\n"
|
|
"\t<app_man_file> = path to the Application manifest you wish to generate a subscription for\n"
|
|
"\t<app_man_URL] = URL of application manifest\n"
|
|
"\toptional: <sync_interval] = syncronize interval in hours\n\n"
|
|
);
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageCmdManifest
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageCmdManifest()
|
|
{
|
|
printf("Usage: \n"
|
|
"Manifest Generation Mode:\n"
|
|
"mg -m sd:<source_dir> td:<target_dir> tf:<template_file> [dd:<dependency_dir>]\n\n"
|
|
"\t<source_dir> = path of the Application of which you want to generate a manifest for\n"
|
|
"\t<target_dir> = path to which all app files and dependencies will be copied\n"
|
|
"\t<template_file> = path of requried input Template file\n"
|
|
"\toptional : <dependency_dir> = user defined dependency dir where some dependencies could be found\n\n"
|
|
);
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// UsageAll
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT UsageAll()
|
|
{
|
|
// call all above functions
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT UsageCommand(COMMAND_MODE CmdMode)
|
|
{
|
|
switch(CmdMode)
|
|
{
|
|
case CmdTemplate:
|
|
UsageCmdTemplate();
|
|
break;
|
|
|
|
case CmdList:
|
|
UsageCmdList();
|
|
break;
|
|
|
|
case CmdDependencyList:
|
|
UsageCmdDependencyList();
|
|
break;
|
|
|
|
case CmdSubscription:
|
|
UsageCmdSubscription();
|
|
break;
|
|
|
|
case CmdManifest:
|
|
UsageCmdManifest();
|
|
break;
|
|
|
|
default :
|
|
UsageTopLevel();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT GetDir( LPWSTR pszSrc, LPWSTR *ppwzDir, BOOL bExists)
|
|
{
|
|
return PathNormalize(pszSrc, ppwzDir, DIRECTORY_PATH, bExists);
|
|
}
|
|
|
|
HRESULT GetFile( LPWSTR pszSrc, LPWSTR *ppwzFile, BOOL bExists)
|
|
{
|
|
return PathNormalize(pszSrc, ppwzFile, FILE_PATH, bExists);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ParseCommandLineArgs
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT ParseCommandLineArgs(int argc,
|
|
WCHAR **argv,
|
|
COMMAND_MODE & CmdMode
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszBuf=NULL;
|
|
|
|
if(argc < 2)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if ( !StrCmpI(argv[1], L"-t"))
|
|
{
|
|
CmdMode = CmdTemplate;
|
|
}
|
|
else if ( !StrCmpI(argv[1], L"-l"))
|
|
{
|
|
CmdMode = CmdList;
|
|
}
|
|
else if ( !StrCmpI(argv[1], L"-d"))
|
|
{
|
|
CmdMode = CmdDependencyList;
|
|
}
|
|
else if ( !StrCmpI(argv[1], L"-s"))
|
|
{
|
|
CmdMode = CmdSubscription;
|
|
}
|
|
else if ( !StrCmpI(argv[1], L"-m"))
|
|
{
|
|
CmdMode = CmdManifest;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
int currArg = 2;
|
|
LPWSTR pwzParamName;
|
|
LPWSTR pwzParamValue;
|
|
|
|
while ( currArg < argc)
|
|
{
|
|
pwzParamName = argv[currArg];
|
|
|
|
if(pwzParamValue = StrChr(pwzParamName, L':'))
|
|
{
|
|
*pwzParamValue = L'\0';
|
|
pwzParamValue++;
|
|
}
|
|
|
|
if( (!pwzParamValue) || !lstrlen(pwzParamValue) )
|
|
{
|
|
if ( StrCmpI(pwzParamName, L"help"))
|
|
printf(" Param Value not specified for \"%s\" \n", pwzParamName);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if ( !StrCmpI(pwzParamName, L"sd"))
|
|
{
|
|
if(FAILED(hr = GetDir(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sAppBase.Assign(pszBuf);
|
|
|
|
g_sDeployDirs[g_dwDeployDirs++].Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"td"))
|
|
{
|
|
if(FAILED(hr = GetDir(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sTargetDir.Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"dd"))
|
|
{
|
|
if(FAILED(hr = GetDir(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sDeployDirs[g_dwDeployDirs++].Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"tf"))
|
|
{
|
|
if(FAILED(hr = GetFile(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sTemplateFile.Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"amu"))
|
|
{
|
|
g_sAppManifestURL.Assign(pwzParamValue);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"si"))
|
|
{
|
|
g_sPollingInterval.Assign(pwzParamValue);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"smd"))
|
|
{
|
|
if(FAILED(hr = GetDir(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sSubscriptionManifestDir.Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"amf"))
|
|
{
|
|
if(FAILED(hr = GetFile(pwzParamValue, &pszBuf, TRUE)))
|
|
goto exit;
|
|
|
|
g_sAppManifestFile.Assign(pszBuf);
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"WRN"))
|
|
{
|
|
g_bFailOnWarnings = 0;
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"GAC"))
|
|
{
|
|
g_bLookInGACForDependencies = 1;
|
|
}
|
|
else if ( !StrCmpI(pwzParamName, L"SYS"))
|
|
{
|
|
g_bCopyDependentSystemAssemblies = 1;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
currArg++;
|
|
|
|
SAFEDELETEARRAY(pszBuf);
|
|
}
|
|
|
|
|
|
exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// wmain
|
|
/////////////////////////////////////////////////////////////////////////
|
|
int __cdecl wmain(int argc, WCHAR **argv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bCoInitialized = TRUE;
|
|
List<ManifestNode *> ManifestList;
|
|
List<ManifestNode *> UniqueManifestList;
|
|
List<LPWSTR> AssemblyFileList[HASHTABLE_SIZE];
|
|
List<LPWSTR> RawFiles;
|
|
DWORD dwType=0;
|
|
ManifestNode *pManifestNode = NULL;
|
|
LISTNODE pos;
|
|
BOOL bListMode = FALSE;
|
|
|
|
LPWSTR pwzBuf=NULL;
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
bCoInitialized = FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
COMMAND_MODE CmdMode = CmdUsage;
|
|
|
|
// Parse
|
|
if(FAILED(hr = ParseCommandLineArgs(argc, argv, CmdMode)))
|
|
{
|
|
UsageCommand(CmdMode);
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// execute
|
|
switch(CmdMode)
|
|
{
|
|
case CmdTemplate:
|
|
if(g_sTemplateFile._cc <= 1)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
hr = CreateAppManifestTemplate(g_sTemplateFile._pwz);
|
|
break;
|
|
|
|
case CmdDependencyList:
|
|
|
|
bListMode = TRUE;
|
|
// continue with CmdList.....
|
|
case CmdList:
|
|
{
|
|
if(g_sAppBase._cc <= 1)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
if(g_sTemplateFile._cc >= 1)
|
|
{
|
|
if(FAILED(hr = GetInitialDependencies(g_sTemplateFile._pwz, &ManifestList)))
|
|
goto exit;
|
|
}
|
|
|
|
if(FAILED(hr = FindAllAssemblies(g_sAppBase._pwz, &ManifestList)))
|
|
goto exit;
|
|
if(FAILED(hr = TraverseManifestDependencyTrees(&ManifestList, AssemblyFileList, &UniqueManifestList, bListMode)))
|
|
goto exit;
|
|
if(FAILED(hr = CrossReferenceFiles(g_sAppBase._pwz, AssemblyFileList, &RawFiles)))
|
|
goto exit;
|
|
|
|
if(!bListMode)
|
|
{
|
|
if(FAILED(hr = PrintDependencies(&RawFiles, &UniqueManifestList)))
|
|
goto exit;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CmdManifest:
|
|
{
|
|
if((g_sAppBase._cc <= 1)
|
|
|| (g_sTemplateFile._cc <= 1)
|
|
|| (g_sTargetDir._cc <= 1)\
|
|
|| !StrCmpI(g_sAppBase._pwz, g_sTargetDir._pwz))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
if(FAILED(hr = GetInitialDependencies(g_sTemplateFile._pwz, &ManifestList)))
|
|
goto exit;
|
|
if(FAILED(hr = FindAllAssemblies(g_sAppBase._pwz, &ManifestList)))
|
|
goto exit;
|
|
if(FAILED(hr = TraverseManifestDependencyTrees(&ManifestList, AssemblyFileList, &UniqueManifestList, FALSE)))
|
|
goto exit;
|
|
if(FAILED(hr = CrossReferenceFiles(g_sAppBase._pwz, AssemblyFileList, &RawFiles)))
|
|
goto exit;
|
|
if(FAILED(hr = CopyFilesToTargetDir(&UniqueManifestList, &RawFiles)))
|
|
goto exit;
|
|
if(FAILED(hr = CreateXMLAppManifest(g_sTargetDir._pwz, g_sTemplateFile._pwz, &UniqueManifestList, &RawFiles)))
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case CmdSubscription:
|
|
|
|
if((g_sAppManifestFile._cc <= 1)
|
|
|| (g_sSubscriptionManifestDir._cc <= 1)
|
|
|| (g_sAppManifestURL._cc <= 1))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
if(g_sPollingInterval._cc <= 1)
|
|
{
|
|
g_sPollingInterval.Assign(DEFAULT_POLLING_INTERVAL);
|
|
}
|
|
|
|
hr = CreateSubscriptionManifest(g_sAppManifestFile._pwz,
|
|
g_sSubscriptionManifestDir._pwz,
|
|
g_sAppManifestURL._pwz,
|
|
g_sPollingInterval._pwz);
|
|
break;
|
|
|
|
default :
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
// Clean up hash table
|
|
for (int i = 0; i < HASHTABLE_SIZE; i++)
|
|
{
|
|
pos = AssemblyFileList[i].GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf = AssemblyFileList[i].GetNext(pos);
|
|
SAFEDELETEARRAY(pwzBuf);
|
|
}
|
|
|
|
AssemblyFileList[i].RemoveAll();
|
|
}
|
|
|
|
//clean up Rawfilelist
|
|
pos = RawFiles.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf = RawFiles.GetNext(pos);
|
|
SAFEDELETEARRAY(pwzBuf);
|
|
}
|
|
RawFiles.RemoveAll();
|
|
|
|
// clean up ManifestList
|
|
pos = ManifestList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pManifestNode = ManifestList.GetNext(pos);
|
|
SAFEDELETE(pManifestNode);
|
|
}
|
|
ManifestList.RemoveAll();
|
|
|
|
// clean up UniqueManifestList
|
|
pos = UniqueManifestList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pManifestNode = UniqueManifestList.GetNext(pos);
|
|
SAFEDELETE(pManifestNode);
|
|
}
|
|
UniqueManifestList.RemoveAll();
|
|
|
|
|
|
if (bCoInitialized)
|
|
CoUninitialize();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
fprintf(stderr, "\nFailed with code 0x%x \n", hr);
|
|
UsageCommand(CmdMode);
|
|
|
|
}
|
|
return hr;
|
|
}
|