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.
2047 lines
60 KiB
2047 lines
60 KiB
#include "stdinc.h"
|
|
#include "stdio.h"
|
|
#include "objbase.h"
|
|
#include "prettyformat.h"
|
|
#include "user32detours.h"
|
|
|
|
#define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
|
|
//
|
|
// Options:
|
|
//
|
|
// -manifest <filename> - Uses filename as the output/input manifest
|
|
// -useexisting - Assumes filename is already there, and that
|
|
// it potentially contains some data already
|
|
// that should be updated/appended to
|
|
// -rebuildexisting - Manifest exists, but remove everything except
|
|
// the file name and hash information (if present)
|
|
// -checkregistry - Indicates that the registry should be searched
|
|
// for other file entries in 'manifest'
|
|
// -dlls [dll [[dll] ...]] - List of DLLs (patterns) that should go into the manifest
|
|
// if not already present
|
|
// -tlb <typelibname> - Type library to pull extra data out of
|
|
//
|
|
|
|
#define STR_NOLOGO L"-nologo"
|
|
#define MS_LOGO L"Microsoft (R) Manifest Builder version 1.0.0.0\r\nCopyright (c) Microsoft Corporation 2001. All rights reserved.\r\n\r\n"
|
|
#define STR_FILE_TAG_NAME L"file"
|
|
#define STR_ASSEMBLY_MANIFEST_NAMESPACE L"urn:schemas-microsoft-com:asm.v1"
|
|
#define STR_FILESEARCH_PATTERN L"/asmns:assembly/asmns:file"
|
|
#define STR_COMCLASS_TAG L"comClass"
|
|
#define STR_COMCLASS_CLSID L"clsid"
|
|
#define STR_COMCLASS_TLBID L"tlbid"
|
|
#define STR_COMCLASS_PROGID L"progid"
|
|
#define STR_COMCLASS_THREADING L"threadingModel"
|
|
#define STR_COMCLASS_DESC L"description"
|
|
#define STR_ASM_NS L"asmns"
|
|
#define SELECTION_NAMESPACES (L"xmlns:" STR_ASM_NS L"='" STR_ASSEMBLY_MANIFEST_NAMESPACE L"'")
|
|
#define STR_MS_COMMENT_COPYRIGHT L"Copyright (C) Microsoft Corp. All Rights Reserved"
|
|
|
|
class __declspec(uuid("00020424-0000-0000-C000-000000000046")) CPSOAInterface;
|
|
|
|
class IMetaDataFileElement
|
|
{
|
|
public:
|
|
virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptElement) = 0;
|
|
};
|
|
|
|
|
|
class CComClassInformation : public IMetaDataFileElement
|
|
{
|
|
public:
|
|
CLSID m_ObjectIdent;
|
|
CLSID m_TlbIdent;
|
|
CString m_Description;
|
|
CString m_Name;
|
|
CString m_DllName;
|
|
CString m_ThreadingModel;
|
|
|
|
CString m_VersionIndependentProgId;
|
|
CSimpleList<CString> m_ProgIdListing;
|
|
|
|
CComClassInformation() {
|
|
ZeroMemory(&m_ObjectIdent, sizeof(m_ObjectIdent));
|
|
ZeroMemory(&m_TlbIdent, sizeof(m_TlbIdent));
|
|
}
|
|
|
|
virtual bool AddProgId(const CString& ProgId)
|
|
{
|
|
for (SIZE_T i = 0; i < m_ProgIdListing.Size(); i++) {
|
|
if (m_ProgIdListing[i] == ProgId)
|
|
return true;
|
|
}
|
|
|
|
m_ProgIdListing.Append(ProgId);
|
|
return true;
|
|
}
|
|
|
|
virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptClsidElement)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = ptClsidElement->setAttribute(
|
|
CString(L"clsid"),
|
|
_variant_t(StringFromCLSID(m_ObjectIdent)));
|
|
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
if (m_TlbIdent != GUID_NULL)
|
|
{
|
|
hr = ptClsidElement->setAttribute(
|
|
CString(L"tlbid"),
|
|
_variant_t(StringFromCLSID(m_TlbIdent)));
|
|
|
|
if (FAILED(hr))
|
|
return false;
|
|
}
|
|
|
|
hr = ptClsidElement->setAttribute(CString(L"description"), _variant_t(m_Description));
|
|
|
|
if (m_ThreadingModel.length() != 0)
|
|
{
|
|
hr = ptClsidElement->setAttribute(CString(L"threadingModel"), _variant_t(m_ThreadingModel));
|
|
if (FAILED(hr))
|
|
return false;
|
|
}
|
|
|
|
if (m_VersionIndependentProgId.length() != 0)
|
|
{
|
|
hr = ptClsidElement->setAttribute(CString(L"progid"), _variant_t(m_VersionIndependentProgId));
|
|
if (FAILED(hr))
|
|
return false;
|
|
}
|
|
|
|
for (SIZE_T pi = 0; pi < m_ProgIdListing.Size(); pi++)
|
|
{
|
|
CSmartPointer<IXMLDOMNode> ptCreatedNode;
|
|
CSmartPointer<IXMLDOMDocument> ptDocument;
|
|
VARIANT vt;
|
|
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
if (FAILED(hr = ptClsidElement->get_ownerDocument(&ptDocument)))
|
|
return false;
|
|
|
|
if (FAILED(ptDocument->createNode(
|
|
vt,
|
|
_bstr_t(L"progid"),
|
|
_bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
|
|
&ptCreatedNode)))
|
|
return false;
|
|
|
|
if (FAILED(ptCreatedNode->put_text(m_ProgIdListing[pi])))
|
|
return false;
|
|
|
|
if (FAILED(ptClsidElement->appendChild(ptCreatedNode, NULL)))
|
|
return false;
|
|
}
|
|
|
|
return hr == S_OK;
|
|
}
|
|
};
|
|
|
|
class CTlbInformation : public IMetaDataFileElement
|
|
{
|
|
public:
|
|
GUID m_Ident;
|
|
DWORD m_Version[2];
|
|
DWORD m_dwFlags;
|
|
CString m_HelpDirectory;
|
|
CString m_ResourceIdent;
|
|
CString m_SourceFile;
|
|
|
|
CTlbInformation() {
|
|
m_dwFlags = m_Version[0] = m_Version[1] = 0;
|
|
ZeroMemory(&m_Ident, sizeof(m_Ident));
|
|
}
|
|
|
|
virtual bool
|
|
CompleteElement(CSmartPointer<IXMLDOMElement> ptTlbElement)
|
|
{
|
|
if (FAILED(ptTlbElement->setAttribute(
|
|
_bstr_t(L"tlbid"),
|
|
_variant_t(StringFromCLSID(this->m_Ident)))))
|
|
return false;
|
|
|
|
if (m_ResourceIdent.length() != 0)
|
|
{
|
|
if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"resourceid"), _variant_t(m_ResourceIdent))))
|
|
return false;
|
|
}
|
|
|
|
if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"version"), _variant_t(FormatVersion(m_Version[0], m_Version[1])))))
|
|
return false;
|
|
|
|
if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"helpdir"), _variant_t(m_HelpDirectory))))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
//
|
|
// This is the assembly!comInterfaceProxyStub element member.
|
|
//
|
|
class CComInterfaceProxyStub : public IMetaDataFileElement
|
|
{
|
|
public:
|
|
IID m_InterfaceId;
|
|
GUID m_TlbId;
|
|
CLSID m_StubClsid;
|
|
CString m_Name;
|
|
int m_iMethods;
|
|
|
|
CComInterfaceProxyStub() {
|
|
ZeroMemory(&m_InterfaceId, sizeof(m_InterfaceId));
|
|
ZeroMemory(&m_TlbId, sizeof(m_TlbId));
|
|
ZeroMemory(&m_StubClsid, sizeof(m_StubClsid));
|
|
m_iMethods = 0;
|
|
}
|
|
|
|
virtual bool
|
|
CompleteElement(CSmartPointer<IXMLDOMElement> ptProxyStub)
|
|
{
|
|
if (m_InterfaceId != GUID_NULL)
|
|
if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"iid"), _variant_t(StringFromCLSID(m_InterfaceId)))))
|
|
return false;
|
|
|
|
if (m_TlbId != GUID_NULL)
|
|
if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"tlbid"), _variant_t(StringFromCLSID(m_TlbId)))))
|
|
return false;
|
|
|
|
if (m_Name.length() != 0)
|
|
if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"name"), _variant_t(m_Name))))
|
|
return false;
|
|
|
|
if (m_iMethods)
|
|
if (FAILED((ptProxyStub->setAttribute(_bstr_t(L"numMethods"), _variant_t((LONGLONG)m_iMethods)))))
|
|
return false;
|
|
|
|
if (m_StubClsid != GUID_NULL)
|
|
if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"proxyStubClsid32"), _variant_t(StringFromCLSID(m_StubClsid)))))
|
|
return false;
|
|
|
|
return true;
|
|
|
|
// Punting on base interface
|
|
}
|
|
};
|
|
|
|
class CInterfaceInformation
|
|
{
|
|
public:
|
|
bool m_fUsed;
|
|
IID m_InterfaceIID;
|
|
CString m_Name;
|
|
|
|
CInterfaceInformation() : m_fUsed(false) { }
|
|
};
|
|
|
|
class CWindowClass : IMetaDataFileElement
|
|
{
|
|
public:
|
|
CString m_WindowClass;
|
|
CString m_SourceDll;
|
|
|
|
virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptWindowClassElement)
|
|
{
|
|
return SUCCEEDED(ptWindowClassElement->put_text(this->m_WindowClass));
|
|
}
|
|
|
|
};
|
|
|
|
class CDllInformation
|
|
{
|
|
public:
|
|
CString m_DllName;
|
|
CSimpleList<CComInterfaceProxyStub*> m_IfaceProxies;
|
|
CSimpleList<CInterfaceInformation*> m_pInterfaces;
|
|
|
|
HRESULT PopulateFileElement(CSmartPointer<IXMLDOMElement> ptElement);
|
|
};
|
|
|
|
|
|
class CManBuilder
|
|
{
|
|
public:
|
|
CManBuilder();
|
|
~CManBuilder() { }
|
|
|
|
bool Initialize(SIZE_T argc, WCHAR** argv);
|
|
bool Run();
|
|
|
|
protected:
|
|
|
|
CComClassInformation* FindClassInfoForClsid(CLSID id);
|
|
|
|
enum {
|
|
HK_REDIR_HKLM,
|
|
HK_REDIR_HKCU,
|
|
HK_REDIR_HKCR,
|
|
HK_REDIR_HKCC,
|
|
HK_REDIR_HKU,
|
|
HK_REDIR_HKPD,
|
|
HK_REDIR_BASE_KEY,
|
|
HK_REDIR_COUNT
|
|
};
|
|
|
|
enum ErrorLevel {
|
|
ePlProgress = 0x01,
|
|
ePlWarning = 0x02,
|
|
ePlError = 0x04,
|
|
ePlSpew = 0x08
|
|
};
|
|
|
|
ErrorLevel m_plPrintLevel;
|
|
bool m_fAddCopyrightData;
|
|
|
|
bool DispUsage();
|
|
bool Display(ErrorLevel pl, PCWSTR Format, ...);
|
|
|
|
bool ProcessDllEntry(CSmartPointer<IXMLDOMElement> ptFileTargetElement);
|
|
|
|
bool FindFileDataFor(
|
|
const CString& FileName,
|
|
CSmartPointer<IXMLDOMElement> ptDocumentRoot,
|
|
CSmartPointer<IXMLDOMElement> &ptFileNode,
|
|
bool fAddIfNotPresent = false);
|
|
|
|
CString m_ManifestFilename;
|
|
CString m_TlbBaseName;
|
|
CString m_strRegistryRootKey;
|
|
CSimpleList<CString> m_Parameters;
|
|
CSimpleList<CString> m_IdentityBlob;
|
|
CSimpleList<CString> m_InputDllListing;
|
|
|
|
|
|
CSimpleList<CComClassInformation*> m_ComClassData;
|
|
CSimpleList<CTlbInformation*> m_TlbInfo;
|
|
CSimpleList<CInterfaceInformation> m_FoundInterfaces;
|
|
CSimpleList<CComInterfaceProxyStub*> m_ExternalProxies;
|
|
CSimpleList<CWindowClass*> m_WindowClasses;
|
|
|
|
bool m_fUseRegistryData, m_fTestCreation;
|
|
|
|
CSimpleMap<CString, CDllInformation> m_DllInformation;
|
|
|
|
bool ConstructEmptyAssemblyManifest(CSmartPointer<IXMLDOMDocument2> ptDocument);
|
|
void PrintXML(CSmartPointer<IDispatch> ptUnk);
|
|
void DisplayErrorInfo(CSmartPointer<ISupportErrorInfo> iErrorInfo);
|
|
bool UpdateManifestWithData(CSmartPointer<IXMLDOMDocument> ptDocument);
|
|
bool RegServerDll(CString ptFileElement);
|
|
bool GatherRegistryData();
|
|
bool EasyGetRegValue(HKEY hkRoot, PCWSTR pcwszSubKeyName, PCWSTR pcwszValueName, CString &OutValue, bool &fFound);
|
|
void DisplayParams();
|
|
bool FindWindowClasses();
|
|
|
|
//
|
|
// Look up what DLL owns this clsid
|
|
//
|
|
CString FindOwningClsid(CString& clsid);
|
|
bool AddInterface(CDllInformation &dll, CSmartPointer<ITypeInfo> ptTypeInfo);
|
|
};
|
|
|
|
CComClassInformation*
|
|
CManBuilder::FindClassInfoForClsid(CLSID id)
|
|
{
|
|
for (SIZE_T c = 0; c < this->m_ComClassData.Size(); c++)
|
|
{
|
|
if (m_ComClassData[c]->m_ObjectIdent == id)
|
|
return m_ComClassData[c];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::FindWindowClasses()
|
|
{
|
|
HMODULE hmUser32 = NULL;
|
|
UINT uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
if (GetModuleHandleW(L"user32.dll") == 0)
|
|
{
|
|
hmUser32 = LoadLibraryW(L"user32.dll");
|
|
}
|
|
|
|
//
|
|
// For this DLL, run through all its objects and see
|
|
// if they can be activated..
|
|
//
|
|
for (SIZE_T c = 0; c < m_InputDllListing.Size(); c++)
|
|
{
|
|
/*
|
|
// no need to do this again, all entries in the list has already been registered.
|
|
//
|
|
|
|
CString &dll = m_InputDllListing[c];
|
|
HMODULE hmThisDll = NULL;
|
|
|
|
hmThisDll = LoadLibraryW(dll);
|
|
|
|
if (hmThisDll == NULL)
|
|
{
|
|
Display(ePlProgress, L"Unable to loadlibrary %ls - can't sniff window classes.\r\n",
|
|
static_cast<PCWSTR>(dll));
|
|
}
|
|
else
|
|
{
|
|
FreeLibrary(hmThisDll);
|
|
}
|
|
*/
|
|
CSimpleList<CString> Classes;
|
|
User32Trampolines::GetRedirectedStrings(Classes);
|
|
User32Trampolines::ClearRedirections();
|
|
|
|
for (SIZE_T i = 0; i < Classes.Size(); i++)
|
|
{
|
|
CWindowClass *pClass = new CWindowClass;
|
|
PCWSTR pcwsz = wcsrchr(m_InputDllListing[c], L'\\');
|
|
if (pcwsz)
|
|
pClass->m_SourceDll = pcwsz + wcsspn(pcwsz, L"\\//");
|
|
else
|
|
pClass->m_SourceDll = m_InputDllListing[c];
|
|
|
|
pClass->m_WindowClass = Classes[i];
|
|
|
|
this->m_WindowClasses.Append(pClass);
|
|
}
|
|
|
|
}
|
|
|
|
if (hmUser32) FreeLibrary(hmUser32);
|
|
|
|
SetErrorMode(uiErrorMode);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
CManBuilder::EasyGetRegValue(
|
|
HKEY hkRoot,
|
|
PCWSTR pcwszSubKeyName,
|
|
PCWSTR pcwszValueName,
|
|
CString &OutValue,
|
|
bool &fFound
|
|
)
|
|
{
|
|
OutValue = L"";
|
|
HKEY hkSubKey = NULL;
|
|
bool fProblems = false;
|
|
ULONG ulError;
|
|
|
|
fFound = false;
|
|
|
|
if (0 == (ulError = RegOpenKeyW(hkRoot, pcwszSubKeyName, &hkSubKey)))
|
|
{
|
|
PBYTE pbData = NULL;
|
|
DWORD cbdwData = 0;
|
|
DWORD dwType;
|
|
|
|
while (true)
|
|
{
|
|
DWORD dwErr = RegQueryValueExW(hkSubKey, pcwszValueName, NULL, &dwType, pbData, &cbdwData);
|
|
|
|
if ((dwErr == ERROR_SUCCESS) && (pbData != NULL))
|
|
{
|
|
OutValue = (PWSTR)pbData;
|
|
fFound = true;
|
|
break;
|
|
}
|
|
else if ((dwErr == ERROR_MORE_DATA) || ((dwErr == ERROR_SUCCESS) && (pbData == NULL)))
|
|
{
|
|
if (pbData)
|
|
{
|
|
delete[] pbData;
|
|
}
|
|
|
|
pbData = new BYTE[cbdwData+1];
|
|
continue;
|
|
}
|
|
else if ((dwErr == ERROR_FILE_NOT_FOUND) || (dwErr == ERROR_PATH_NOT_FOUND))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
fProblems = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pbData)
|
|
{
|
|
delete[] pbData;
|
|
pbData = NULL;
|
|
}
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
|
|
return !fProblems;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::GatherRegistryData()
|
|
{
|
|
CSimpleList<CString> FoundFiles;
|
|
|
|
//
|
|
// Look at HKEY_CLASSES_ROOT\CLSID - it contains the list of clsids that we should
|
|
// be adding to the manifest.
|
|
//
|
|
CString PathBuilder;
|
|
WCHAR wchKeyName[MAX_PATH];
|
|
DWORD dwIndex = 0;
|
|
ULONG ulError;
|
|
DWORD cbDataLength;
|
|
HKEY hkIterationKey;
|
|
|
|
ulError = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_ENUMERATE_SUB_KEYS, &hkIterationKey);
|
|
|
|
while (ulError == ERROR_SUCCESS)
|
|
{
|
|
HKEY hkThisClass = NULL;
|
|
CString WorkerValue;
|
|
bool fPresent, fOk, fCreatedInfo = false;
|
|
CComClassInformation *pThisClass;
|
|
CLSID FoundClsid;
|
|
|
|
ulError = RegEnumKeyExW(hkIterationKey, dwIndex++, wchKeyName, &(cbDataLength = sizeof(wchKeyName)), NULL, NULL, NULL, NULL);
|
|
if (ulError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Conversion to a clsid failed? Hmm, but continue.
|
|
//
|
|
if (FAILED(CLSIDFromString(wchKeyName, &FoundClsid)))
|
|
continue;
|
|
|
|
//
|
|
// Find the existing class data to match up with. Otherwise, create a new
|
|
// entity and add it to the list.
|
|
//
|
|
pThisClass = FindClassInfoForClsid(FoundClsid);
|
|
if (pThisClass == NULL) {
|
|
pThisClass = new CComClassInformation();
|
|
pThisClass->m_ObjectIdent = FoundClsid;
|
|
fCreatedInfo = true;
|
|
}
|
|
|
|
//
|
|
// Description of the class
|
|
//
|
|
fOk = EasyGetRegValue(hkIterationKey, wchKeyName, NULL, WorkerValue, fPresent);
|
|
if (fOk && fPresent)
|
|
{
|
|
pThisClass->m_Description = WorkerValue;
|
|
}
|
|
|
|
//
|
|
// Now that we've got this subkey, let's go open it and do a little inspection on it.
|
|
//
|
|
ulError = RegOpenKeyExW(hkIterationKey, wchKeyName, 0, KEY_READ, &hkThisClass);
|
|
if (ulError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Get the version-independent prog id for this class
|
|
//
|
|
fOk = EasyGetRegValue(hkThisClass, L"VersionIndependentProgID", NULL, WorkerValue, fPresent);
|
|
if (fOk && fPresent)
|
|
{
|
|
pThisClass->m_VersionIndependentProgId = WorkerValue;
|
|
}
|
|
|
|
//
|
|
// Get the non-independent one
|
|
//
|
|
fOk = EasyGetRegValue(hkThisClass, L"ProgID", NULL, WorkerValue, fPresent);
|
|
if (fOk && fPresent)
|
|
{
|
|
pThisClass->AddProgId(WorkerValue);
|
|
}
|
|
|
|
//
|
|
// Get ourselves a threading model
|
|
//
|
|
fOk = EasyGetRegValue(hkThisClass, L"InprocServer32", L"ThreadingModel", WorkerValue, fPresent);
|
|
if (fOk && fPresent)
|
|
{
|
|
pThisClass->m_ThreadingModel = WorkerValue;
|
|
}
|
|
|
|
//
|
|
// And find the class's registered inproc server
|
|
//
|
|
fOk = EasyGetRegValue(hkThisClass, L"InprocServer32", NULL, WorkerValue, fPresent);
|
|
if (fOk && fPresent)
|
|
{
|
|
//
|
|
// Fix up this path - we need just the file name bit, we don't care about the
|
|
// remainder of the path.
|
|
//
|
|
PWSTR pwszLastSlash = wcsrchr(WorkerValue, L'\\');
|
|
if (pwszLastSlash == NULL)
|
|
pwszLastSlash = wcsrchr(WorkerValue, L'/');
|
|
|
|
pThisClass->m_DllName = (pwszLastSlash ? pwszLastSlash + 1 : WorkerValue);
|
|
}
|
|
|
|
RegCloseKey(hkThisClass);
|
|
hkThisClass = NULL;
|
|
}
|
|
|
|
//
|
|
// Found something in the registry that wasn't a creatable class, really..
|
|
//
|
|
if (fCreatedInfo) {
|
|
if (pThisClass->m_DllName.length() != 0)
|
|
m_ComClassData.Append(pThisClass);
|
|
else
|
|
delete pThisClass;
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey(hkIterationKey);
|
|
|
|
|
|
#if 0
|
|
while (true)
|
|
{
|
|
DWORD cbKeyNameLength = sizeof(wchKeyName);
|
|
ULONG ulError;
|
|
CString Found_Clsid, ProgId;
|
|
|
|
ulError = RegEnumKeyExW(User32Trampolines::RemapRegKey(HKEY_CLASSES_ROOT), dwIndex++, wchKeyName, &cbKeyNameLength, 0, 0, 0, 0);
|
|
|
|
if (ulError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Examine this key. Form up the path to it as {keyname}\Clsid. We know that this
|
|
// is a version-independent key if {keyname}\curver is present. (The version-dependent
|
|
// value should go in the comclsid's <comClass> tag, while the independent goes under
|
|
// the <comClass> as a child node.
|
|
//
|
|
// Not if it's one of the well-known values, though.
|
|
//
|
|
if ((lstrcmpiW(wchKeyName, L"CLSID") == 0) ||
|
|
(lstrcmpiW(wchKeyName, L"Interface") == 0) ||
|
|
(lstrcmpiW(wchKeyName, L"TypeLib") == 0))
|
|
continue;
|
|
|
|
CString ProgIdPath = wchKeyName + CString(L"\\Clsid");
|
|
CString ClsidFound;
|
|
bool fFound = false;
|
|
CComClassInformation *pCInfo = NULL;
|
|
|
|
EasyGetRegValue(User32Trampolines::RemapRegKey(HKEY_CLASSES_ROOT), ProgIdPath, NULL, ClsidFound, fFound);
|
|
|
|
if (fFound)
|
|
{
|
|
CLSID id;
|
|
CLSIDFromString(ClsidFound, &id);
|
|
|
|
if ((pCInfo = FindClassInfoForClsid(id)) != NULL)
|
|
{
|
|
pCInfo->m_ProgIdListing.Append(CString(wchKeyName));
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ulError != ERROR_NO_MORE_ITEMS)
|
|
Display(ePlError, L"Error 0x%08lx (%l) enumerating redirected HKEY_CLASSES_ROOT.\r\n",
|
|
ulError, ulError);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// And let's go look at all the interfaces that were in the tlb
|
|
//
|
|
this->m_DllInformation.GetKeys(FoundFiles);
|
|
for (SIZE_T c = 0; c < FoundFiles.Size(); c++)
|
|
{
|
|
CDllInformation &minfo = this->m_DllInformation[FoundFiles[c]];
|
|
|
|
for (SIZE_T f = 0; f < minfo.m_pInterfaces.Size(); f++)
|
|
{
|
|
CInterfaceInformation* pInfo = minfo.m_pInterfaces[f];
|
|
CComClassInformation* pComClass = NULL;
|
|
|
|
//
|
|
// Already found this one a home?
|
|
//
|
|
if (pInfo->m_fUsed) continue;
|
|
|
|
Display(ePlSpew, L"Looking for pstub %ls (%ls)\r\n",
|
|
static_cast<PCWSTR>(StringFromCLSID(pInfo->m_InterfaceIID)),
|
|
static_cast<PCWSTR>(pInfo->m_Name));
|
|
|
|
//
|
|
// First check. Is there a COM class with this IID?
|
|
//
|
|
if ((pComClass = this->FindClassInfoForClsid(pInfo->m_InterfaceIID)) != NULL)
|
|
{
|
|
//
|
|
// Great. Add an entry for the proxy stub interface to the file tag containing
|
|
// the clsid.
|
|
//
|
|
pInfo->m_fUsed = true;
|
|
CComInterfaceProxyStub *pstub = new CComInterfaceProxyStub;
|
|
|
|
pstub->m_InterfaceId = pInfo->m_InterfaceIID;
|
|
pstub->m_StubClsid = pComClass->m_ObjectIdent;
|
|
pstub->m_Name = pComClass->m_Name;
|
|
pstub->m_TlbId = pComClass->m_TlbIdent;
|
|
|
|
Display(ePlSpew, L"- Matched to COM class %ls (IID matches guid)\r\n",
|
|
static_cast<PCWSTR>(pstub->m_Name));
|
|
|
|
minfo.m_IfaceProxies.Append(pstub);
|
|
}
|
|
//
|
|
// Otherwise, look in the registry and try to map back to a proxy stub
|
|
// clsid.
|
|
//
|
|
else
|
|
{
|
|
CString RegPath = L"Interface\\" + StringFromCLSID(pInfo->m_InterfaceIID);
|
|
CString FoundClsid;
|
|
CString FoundTlbIdent;
|
|
bool fFoundClsid, fFoundTlbIdent;
|
|
|
|
this->EasyGetRegValue(HKEY_CLASSES_ROOT, RegPath + L"\\ProxyStubClsid32", NULL, FoundClsid, fFoundClsid);
|
|
this->EasyGetRegValue(HKEY_CLASSES_ROOT, RegPath + L"\\TypeLib", NULL, FoundTlbIdent, fFoundTlbIdent);
|
|
|
|
if (fFoundClsid)
|
|
{
|
|
CLSID clsid;
|
|
CLSIDFromString(FoundClsid, &clsid);
|
|
|
|
//
|
|
// Now go look and see if we own this clsid.
|
|
//
|
|
if ((pComClass = FindClassInfoForClsid(clsid)) != NULL)
|
|
{
|
|
pInfo->m_fUsed = true;
|
|
CComInterfaceProxyStub *pStub = new CComInterfaceProxyStub;
|
|
pStub->m_InterfaceId = pInfo->m_InterfaceIID;
|
|
pStub->m_StubClsid = pComClass->m_ObjectIdent;
|
|
pStub->m_Name = pComClass->m_Name;
|
|
pStub->m_TlbId = pComClass->m_TlbIdent;
|
|
|
|
m_DllInformation[pComClass->m_DllName].m_IfaceProxies.Append(pStub);
|
|
}
|
|
else if (clsid == __uuidof(CPSOAInterface))
|
|
{
|
|
CComInterfaceProxyStub *pStub = new CComInterfaceProxyStub;
|
|
SIZE_T c = 0;
|
|
|
|
pStub->m_InterfaceId = pInfo->m_InterfaceIID;
|
|
pStub->m_StubClsid = __uuidof(CPSOAInterface);
|
|
pStub->m_Name = L"Oleaut32 PSOAInterface";
|
|
pStub->m_iMethods = 0;
|
|
if (fFoundTlbIdent)
|
|
CLSIDFromString(FoundTlbIdent, &pStub->m_TlbId);
|
|
|
|
// This sucks, but it's necessary.
|
|
for (c = 0; c < this->m_ExternalProxies.Size(); c++)
|
|
{
|
|
if (this->m_ExternalProxies[c]->m_InterfaceId == pInfo->m_InterfaceIID)
|
|
break;
|
|
}
|
|
|
|
if (c == this->m_ExternalProxies.Size())
|
|
{
|
|
this->m_ExternalProxies.Append(pStub);
|
|
pStub = NULL;
|
|
}
|
|
|
|
if (pStub != NULL)
|
|
{
|
|
delete pStub;
|
|
pStub = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
CManBuilder::DisplayErrorInfo(
|
|
CSmartPointer<ISupportErrorInfo> iErrorInfo
|
|
)
|
|
{
|
|
if (iErrorInfo == NULL)
|
|
{
|
|
Display(ePlError, L"No more error information available.\n");
|
|
}
|
|
else
|
|
{
|
|
CSmartPointer<IErrorInfo> iInfo;
|
|
BSTR bst;
|
|
|
|
GetErrorInfo(0, &iInfo);
|
|
if ((iInfo != NULL) && SUCCEEDED(iInfo->GetDescription(&bst)))
|
|
{
|
|
Display(ePlError, L"Error: %ls\r\n", static_cast<PCWSTR>(bst));
|
|
if (bst)
|
|
{
|
|
SysFreeString(bst);
|
|
bst = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CManBuilder::PrintXML(
|
|
CSmartPointer<IDispatch> ptDispatch
|
|
)
|
|
{
|
|
if (0)
|
|
{
|
|
CSmartPointer<IXMLDOMDocument2> ptDoc;
|
|
if ((ptDoc = ptDispatch) != NULL)
|
|
PrettyFormatXmlDocument(ptDoc);
|
|
}
|
|
|
|
OLECHAR *wchGetXML = L"xml";
|
|
DISPID dispid;
|
|
|
|
if (ptDispatch != NULL)
|
|
{
|
|
_variant_t vresult;
|
|
HRESULT hr;
|
|
DISPPARAMS dp = { NULL, NULL, 0, 0 };
|
|
EXCEPINFO ei = { 0 };
|
|
|
|
if (FAILED(ptDispatch->GetIDsOfNames(
|
|
IID_NULL,
|
|
&wchGetXML,
|
|
1,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
&dispid))) return;
|
|
|
|
hr = ptDispatch->Invoke(
|
|
dispid,
|
|
IID_NULL,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
DISPATCH_PROPERTYGET,
|
|
&dp,
|
|
&vresult,
|
|
&ei,
|
|
NULL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Display(
|
|
ePlSpew,
|
|
L"XML:\r\n%ls\r\n",
|
|
static_cast<PCWSTR>((_bstr_t)vresult));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
SplitIdentityItem(
|
|
const PCWSTR pcwszIdentityString,
|
|
CString& ValueName,
|
|
CString& ValueValue
|
|
)
|
|
{
|
|
ValueName = ValueValue = L"";
|
|
PWSTR pwszClone = new WCHAR[lstrlenW(pcwszIdentityString) + 1];
|
|
PWSTR pwszEquals, pwszValue;
|
|
|
|
wcscpy(pwszClone, pcwszIdentityString);
|
|
pwszEquals = wcschr(pwszClone, L'=');
|
|
pwszValue = CharNextW(pwszEquals);
|
|
|
|
if (pwszEquals == NULL) return false;
|
|
|
|
*pwszEquals = UNICODE_NULL;
|
|
|
|
ValueName = pwszClone;
|
|
ValueValue = pwszValue;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CManBuilder::ConstructEmptyAssemblyManifest(
|
|
CSmartPointer<IXMLDOMDocument2> ptDocument
|
|
)
|
|
{
|
|
//
|
|
// Remove /everything/ from the document.
|
|
//
|
|
CSmartPointer<IXMLDOMProcessingInstruction> Processing;
|
|
CSmartPointer<IXMLDOMNode> AssemblyRootNode;
|
|
CSmartPointer<IXMLDOMElement> AssemblyRootElement;
|
|
VARIANT vt;
|
|
HRESULT hr;
|
|
|
|
// Create a processing instruction - <?xml version="1.0"?>
|
|
hr = ptDocument->createProcessingInstruction(
|
|
_bstr_t(L"xml"),
|
|
_bstr_t(L"version='1.0' encoding='UTF-8' standalone='yes'"),
|
|
&Processing);
|
|
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
// And add it
|
|
if (FAILED(ptDocument->appendChild(Processing, NULL)))
|
|
return false;
|
|
|
|
//
|
|
// If we're supposed to be injecting the MS copyright, do so
|
|
//
|
|
if (m_fAddCopyrightData)
|
|
{
|
|
CSmartPointer<IXMLDOMComment> CopyrightComment;
|
|
|
|
hr = ptDocument->createComment(STR_MS_COMMENT_COPYRIGHT, &CopyrightComment);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
if (FAILED(hr = ptDocument->appendChild(CopyrightComment, NULL)))
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Create the <assembly> root element.
|
|
//
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
if (FAILED(ptDocument->createNode(
|
|
vt,
|
|
_bstr_t(L"assembly"),
|
|
_bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
|
|
&AssemblyRootNode)))
|
|
return false;
|
|
|
|
if ((AssemblyRootElement = AssemblyRootNode) == NULL)
|
|
return false;
|
|
|
|
if (FAILED(AssemblyRootElement->setAttribute(CString(L"manifestVersion"), _variant_t(L"1.0"))))
|
|
return false;
|
|
|
|
if (FAILED(ptDocument->putref_documentElement(AssemblyRootElement)))
|
|
return false;
|
|
|
|
//
|
|
// Construct the identity tag if possible
|
|
//
|
|
if (this->m_IdentityBlob.Size())
|
|
{
|
|
CSmartPointer<IXMLDOMNode> ptIdentityNode;
|
|
CSmartPointer<IXMLDOMElement> ptIdentity;
|
|
CSmartPointer<IXMLDOMElement> ptDocRoot;
|
|
|
|
hr = ptDocument->createNode(
|
|
vt,
|
|
_bstr_t(L"assemblyIdentity"),
|
|
_bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
|
|
&ptIdentityNode);
|
|
|
|
if (FAILED(hr) || ((ptIdentity = ptIdentityNode) == NULL))
|
|
{
|
|
Display(ePlError, L"Can't create assemblyIdentity node!\r\n");
|
|
DisplayErrorInfo(ptDocument);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For each identity pair that was passed in, decide on
|
|
// the name and the value components.
|
|
//
|
|
CString strName, strValue;
|
|
|
|
for (SIZE_T sz = 0; sz < m_IdentityBlob.Size(); sz++)
|
|
{
|
|
if (!SplitIdentityItem(m_IdentityBlob[sz], strName, strValue))
|
|
{
|
|
Display(ePlError, L"Unable to interpret identity pair '%ls'\r\n",
|
|
static_cast<PCWSTR>(m_IdentityBlob[sz]));
|
|
}
|
|
else if (FAILED(hr = ptIdentity->setAttribute(strName, _variant_t(strValue))))
|
|
{
|
|
Display(ePlError, L"Unable to set attribute pair %ls = '%ls'\r\n",
|
|
static_cast<PCWSTR>(strName),
|
|
static_cast<PCWSTR>(strValue));
|
|
DisplayErrorInfo(ptIdentity);
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = ptDocument->get_documentElement(&ptDocRoot);
|
|
hr = ptDocRoot->appendChild(ptIdentityNode, NULL);
|
|
}
|
|
|
|
PrintXML(ptDocument);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
CString
|
|
FormatVersion(DWORD dwMaj, DWORD dwMin)
|
|
{
|
|
WCHAR wchBuffer[200];
|
|
_snwprintf(wchBuffer, 200, L"%d.%d", dwMaj, dwMin);
|
|
return CString(wchBuffer);
|
|
}
|
|
|
|
|
|
CString
|
|
StringFromCLSID(REFCLSID rclsid)
|
|
{
|
|
PWSTR pwsz = NULL;
|
|
HRESULT hr;
|
|
CString rvalue = L"(unknown)";
|
|
|
|
hr = StringFromCLSID(rclsid, &pwsz);
|
|
if (pwsz)
|
|
{
|
|
rvalue = pwsz;
|
|
CoTaskMemFree(pwsz);
|
|
pwsz = NULL;
|
|
}
|
|
return rvalue;
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
EnumTypeLibsFunc(
|
|
HMODULE hModule,
|
|
LPCWSTR lpType,
|
|
LPWSTR lpName,
|
|
LONG_PTR lp
|
|
)
|
|
{
|
|
static WCHAR wchBuiltFilePath[MAX_PATH*2];
|
|
CString tgt;
|
|
|
|
if ((UINT)lpName < 0xFFFF)
|
|
{
|
|
wsprintfW(wchBuiltFilePath, L"%d", (UINT)lpName);
|
|
tgt = wchBuiltFilePath;
|
|
}
|
|
else
|
|
{
|
|
tgt = lpName;
|
|
}
|
|
|
|
((CSimpleList<CString>*)lp)->Append(tgt);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::ProcessDllEntry(
|
|
CSmartPointer<IXMLDOMElement> ptFileElement
|
|
)
|
|
{
|
|
_variant_t vtFileName;
|
|
|
|
CSimpleList<CString> ResourceIdentList;
|
|
HMODULE hmDll = NULL;
|
|
CString dll;
|
|
|
|
if (FAILED(ptFileElement->getAttribute(_bstr_t(L"name"), &vtFileName)))
|
|
return false;
|
|
|
|
// instead using the pure dll filename, find the real path of this file,
|
|
dll = static_cast<_bstr_t>(vtFileName);
|
|
SIZE_T len = (static_cast<_bstr_t>(vtFileName)).length();
|
|
for (SIZE_T c = 0; c < m_InputDllListing.Size(); c++)
|
|
{
|
|
if (m_InputDllListing[c].length()>= len)
|
|
{
|
|
PCWSTR pstr = wcsstr(m_InputDllListing[c], (PWSTR)(static_cast<_bstr_t>(vtFileName)));
|
|
if ((pstr != NULL) && (wcslen(pstr) == len))
|
|
{
|
|
dll = m_InputDllListing[c];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Gather all the resource idents of TYPELIB resources
|
|
//
|
|
hmDll = LoadLibraryExW(dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if (hmDll == NULL)
|
|
{
|
|
ResourceIdentList.Append(CString(L""));
|
|
Display(ePlWarning, L"Warning - %ls can not been loaded, ResourceIdentList is appended with an empty string.\n",
|
|
static_cast<PCWSTR>(dll));
|
|
}
|
|
else
|
|
{
|
|
EnumResourceNamesW(
|
|
hmDll,
|
|
L"TYPELIB",
|
|
EnumTypeLibsFunc,
|
|
(LONG_PTR)&ResourceIdentList);
|
|
}
|
|
|
|
//
|
|
// If there were no resource idents, then just do a single pass
|
|
//
|
|
|
|
for (SIZE_T sz = 0; sz < ResourceIdentList.Size(); sz++)
|
|
{
|
|
CSmartPointer<ITypeLib> ptTypeLibrary;
|
|
CString strGuidString;
|
|
CString strLoadTypeLibParam;
|
|
UINT uiTypeInfoCount;
|
|
TLIBATTR *pLibAttr;
|
|
CTlbInformation* tlbInfo;
|
|
bool fSetResourceIdent = false;
|
|
CDllInformation &dllInfo = this->m_DllInformation[CString(vtFileName)];
|
|
|
|
tlbInfo = new CTlbInformation();
|
|
|
|
//
|
|
// The "blank" string is a placeholder so that we know that the file in question
|
|
// may not be a loadable dll.
|
|
//
|
|
if (ResourceIdentList[sz].length() == 0)
|
|
{
|
|
strLoadTypeLibParam = static_cast<_bstr_t>(vtFileName);
|
|
}
|
|
//
|
|
// Otherwise, the ResourceIdentList contains the resourceID of the typelibrary
|
|
// in question.
|
|
//
|
|
else
|
|
{
|
|
strLoadTypeLibParam = dll + CString(L"\\") + ResourceIdentList[sz];
|
|
tlbInfo->m_ResourceIdent = ResourceIdentList[sz];
|
|
}
|
|
|
|
tlbInfo->m_SourceFile = dll;
|
|
|
|
if (FAILED(LoadTypeLibEx(strLoadTypeLibParam, REGKIND_NONE, &ptTypeLibrary)))
|
|
continue;
|
|
|
|
//
|
|
// Now look through the tlb and see what there is to see.. Assume all CoClasses found
|
|
// in the typelib are implemented for this dll.
|
|
//
|
|
uiTypeInfoCount = ptTypeLibrary->GetTypeInfoCount();
|
|
|
|
if (FAILED(ptTypeLibrary->GetLibAttr(&pLibAttr)))
|
|
continue;
|
|
|
|
Display(ePlProgress, L"Found type library in file %ls, guid %ls (contains %d types)\n",
|
|
static_cast<PCWSTR>(_bstr_t(vtFileName)),
|
|
static_cast<PCWSTR>(StringFromCLSID(pLibAttr->guid)),
|
|
uiTypeInfoCount);
|
|
|
|
tlbInfo->m_Ident = pLibAttr->guid;
|
|
tlbInfo->m_Version[0] = pLibAttr->wMajorVerNum;
|
|
tlbInfo->m_Version[1] = pLibAttr->wMinorVerNum;
|
|
m_TlbInfo.Append(tlbInfo);
|
|
|
|
for (UINT ui = 0; ui < uiTypeInfoCount; ui++)
|
|
{
|
|
CSmartPointer<ITypeInfo> ptTypeInfo;
|
|
BSTR rawbstTypeName;
|
|
BSTR rawbstDocumentation;
|
|
CString strTypeName;
|
|
CString strDocumentation;
|
|
TYPEKIND tk;
|
|
TYPEATTR *pTypeAttr = NULL;
|
|
|
|
|
|
if (FAILED(ptTypeLibrary->GetTypeInfoType(ui, &tk)))
|
|
continue;
|
|
|
|
if (FAILED(ptTypeLibrary->GetTypeInfo(ui, &ptTypeInfo)))
|
|
continue;
|
|
|
|
if (FAILED(ptTypeInfo->GetTypeAttr(&pTypeAttr)))
|
|
continue;
|
|
|
|
//
|
|
// Get a little documentation
|
|
//
|
|
if (SUCCEEDED(ptTypeLibrary->GetDocumentation(
|
|
ui,
|
|
&rawbstTypeName,
|
|
&rawbstDocumentation,
|
|
NULL,
|
|
NULL)))
|
|
{
|
|
if (rawbstTypeName != NULL)
|
|
{
|
|
strTypeName = _bstr_t(rawbstTypeName, FALSE);
|
|
rawbstTypeName = NULL;
|
|
}
|
|
|
|
if (rawbstDocumentation != NULL)
|
|
{
|
|
strDocumentation = _bstr_t(rawbstDocumentation, FALSE);
|
|
rawbstDocumentation = NULL;
|
|
}
|
|
}
|
|
|
|
if (pTypeAttr->wTypeFlags & TYPEFLAG_FDUAL)
|
|
{
|
|
if (tk == TKIND_DISPATCH)
|
|
{
|
|
CSmartPointer<ITypeInfo> ptDispInfo;
|
|
HREFTYPE hrTypeInfo;
|
|
|
|
if (SUCCEEDED(ptTypeInfo->GetRefTypeOfImplType((UINT)-1, &hrTypeInfo)))
|
|
if (SUCCEEDED(ptTypeInfo->GetRefTypeInfo(hrTypeInfo, &ptDispInfo)))
|
|
this->AddInterface(dllInfo, ptDispInfo);
|
|
}
|
|
else if (tk == TKIND_INTERFACE)
|
|
{
|
|
this->AddInterface(dllInfo, ptTypeInfo);
|
|
}
|
|
}
|
|
|
|
if (tk == TKIND_COCLASS)
|
|
{
|
|
CComClassInformation *pClassInfo = NULL;
|
|
bool fCreated = false;
|
|
|
|
pClassInfo = FindClassInfoForClsid(pTypeAttr->guid);
|
|
|
|
if (pClassInfo == NULL)
|
|
{
|
|
pClassInfo = new CComClassInformation;
|
|
m_ComClassData.Append(pClassInfo);
|
|
}
|
|
|
|
pClassInfo->m_Description = strDocumentation;
|
|
pClassInfo->m_ObjectIdent = pTypeAttr->guid;
|
|
pClassInfo->m_Name = strTypeName;
|
|
pClassInfo->m_TlbIdent = pLibAttr->guid;
|
|
}
|
|
else if (tk == TKIND_INTERFACE)
|
|
{
|
|
this->AddInterface(dllInfo, ptTypeInfo);
|
|
}
|
|
|
|
if (pTypeAttr != NULL)
|
|
{
|
|
ptTypeInfo->ReleaseTypeAttr(pTypeAttr);
|
|
pTypeAttr = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (hmDll)
|
|
{
|
|
FreeLibrary(hmDll);
|
|
hmDll = NULL;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool
|
|
CManBuilder::AddInterface(
|
|
CDllInformation &dll,
|
|
CSmartPointer<ITypeInfo> ptTypeInfo
|
|
)
|
|
{
|
|
CInterfaceInformation *pInterface = NULL;
|
|
TYPEATTR *pTypeAttr = NULL;
|
|
BSTR bstName = NULL, bstDocumentation = NULL;
|
|
bool fRVal = false;
|
|
|
|
if (SUCCEEDED(ptTypeInfo->GetTypeAttr(&pTypeAttr)))
|
|
{
|
|
if (SUCCEEDED(ptTypeInfo->GetDocumentation(MEMBERID_NIL, &bstName, &bstDocumentation, NULL, NULL)))
|
|
{
|
|
pInterface = new CInterfaceInformation;
|
|
pInterface->m_InterfaceIID = pTypeAttr->guid;
|
|
pInterface->m_Name = bstName;
|
|
|
|
dll.m_pInterfaces.Append(pInterface);
|
|
|
|
Display(ePlSpew, L"Found interface %ls '%ls'\r\n",
|
|
static_cast<PCWSTR>(StringFromCLSID(pTypeAttr->guid)),
|
|
bstName);
|
|
|
|
fRVal = true;
|
|
}
|
|
}
|
|
|
|
if (bstName) ::SysFreeString(bstName);
|
|
if (bstDocumentation) ::SysFreeString(bstDocumentation);
|
|
if (pTypeAttr) ptTypeInfo->ReleaseTypeAttr(pTypeAttr);
|
|
|
|
return fRVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::FindFileDataFor(
|
|
const CString & FileName,
|
|
CSmartPointer < IXMLDOMElement > ptDocumentRoot,
|
|
CSmartPointer < IXMLDOMElement > & ptFileElementFound,
|
|
bool fAddIfNotPresent
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
CSmartPointer<IXMLDOMNode> ptFoundNode;
|
|
/*
|
|
const _bstr_t bstSearchPattern =
|
|
_bstr_t(L"/" STR_ASM_NS L":assembly/" STR_ASM_NS L":file[@name = '")
|
|
+ _bstr_t(FileName)
|
|
+ _bstr_t(L"']");
|
|
*/
|
|
CString StrippedName;
|
|
PCWSTR pcwsz;
|
|
|
|
//
|
|
// If the file name contains a slash of some sort, we need to get
|
|
// just the file name and not the path.
|
|
//
|
|
pcwsz = wcsrchr(FileName, L'\\');
|
|
if (pcwsz)
|
|
{
|
|
StrippedName = pcwsz + wcsspn(pcwsz, L"\\");
|
|
}
|
|
else
|
|
{
|
|
StrippedName = FileName;
|
|
}
|
|
|
|
_bstr_t bstSearchPattern =
|
|
_bstr_t(L"/" STR_ASM_NS L":assembly/" STR_ASM_NS L":file[@name = '")
|
|
+ _bstr_t(StrippedName)
|
|
+ _bstr_t(L"']");
|
|
|
|
|
|
if (ptFileElementFound != NULL)
|
|
ptFileElementFound.Release();
|
|
|
|
//
|
|
// Use single-select, since there should only be one entry that matches the
|
|
// above pattern anyhow.
|
|
//
|
|
if (SUCCEEDED(hr = ptDocumentRoot->selectSingleNode(bstSearchPattern, &ptFoundNode)))
|
|
{
|
|
//
|
|
// Convert from an IXMLDOMNode to an IXMLDOMElement
|
|
//
|
|
if ((ptFileElementFound = ptFoundNode) != NULL)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisplayErrorInfo(ptDocumentRoot);
|
|
}
|
|
|
|
if (fAddIfNotPresent)
|
|
{
|
|
//
|
|
// Create a new file node and insert it as the child of the document
|
|
// root. Print the XML just so we can see what it current is...
|
|
//
|
|
CSmartPointer<IXMLDOMDocument> ptDocument;
|
|
CSmartPointer<IXMLDOMNode> ptCreatedNode;
|
|
CSmartPointer<IXMLDOMElement> ptCreatedFileTag;
|
|
CSmartPointer<IXMLDOMNode> ptNodeInDocument;
|
|
|
|
VARIANT vt;
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
if (FAILED(ptDocumentRoot->get_ownerDocument(&ptDocument)))
|
|
return false;
|
|
|
|
//
|
|
// Create the file element (element = 'tag')
|
|
//
|
|
if (FAILED(ptDocument->createNode(
|
|
vt,
|
|
_bstr_t(STR_FILE_TAG_NAME),
|
|
_bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
|
|
&ptCreatedNode)))
|
|
return false;
|
|
|
|
//
|
|
// Convert the 'node' (base xml type) to an 'element' (tag)
|
|
//
|
|
if ((ptCreatedFileTag = ptCreatedNode) == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (FAILED(ptCreatedFileTag->setAttribute(
|
|
_bstr_t(L"name"),
|
|
_variant_t(_bstr_t(StrippedName)))))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (FAILED(ptDocumentRoot->appendChild(ptCreatedNode, &ptNodeInDocument)))
|
|
return false;
|
|
|
|
return ((ptFileElementFound = ptNodeInDocument) != NULL);
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
CManBuilder::CManBuilder() : m_fAddCopyrightData(false), m_fUseRegistryData(false), m_fTestCreation(false), m_plPrintLevel(ePlProgress)
|
|
{
|
|
}
|
|
|
|
|
|
bool
|
|
CManBuilder::Display(ErrorLevel pl, PCWSTR format, ...)
|
|
{
|
|
if ((pl & m_plPrintLevel) == 0)
|
|
return true;
|
|
|
|
va_list va;
|
|
va_start(va, format);
|
|
vwprintf(format, va);
|
|
va_end(va);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::RegServerDll(
|
|
CString strDllName
|
|
)
|
|
{
|
|
UINT uiMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
bool fReturnValue = true;
|
|
|
|
HMODULE hmModule = LoadLibraryW(strDllName);
|
|
if (hmModule != NULL)
|
|
{
|
|
typedef HRESULT (STDAPICALLTYPE *tpfnRegisterServer)();
|
|
tpfnRegisterServer pfnRegisterServer;
|
|
pfnRegisterServer = (tpfnRegisterServer)GetProcAddress(hmModule, "DllRegisterServer");
|
|
if (pfnRegisterServer != NULL)
|
|
{
|
|
pfnRegisterServer();
|
|
}
|
|
FreeLibrary(hmModule);
|
|
}else
|
|
{
|
|
Display(ePlError, L"%ls could not be loaded, can not call DllRegisterServer.\n", (PCWSTR)strDllName);
|
|
fReturnValue = false;
|
|
}
|
|
|
|
SetErrorMode(uiMode);
|
|
|
|
return fReturnValue;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::Run()
|
|
{
|
|
bool fOk = true;
|
|
CSmartPointer<IXMLDOMDocument2> ptDocument;
|
|
CSmartPointer<ITypeLib2> ptBaseTypeLibrary;
|
|
CSmartPointer<IXMLDOMElement> ptDocumentRoot;
|
|
CSmartPointer<IXMLDOMNodeList> ptFileElements;
|
|
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Create the XML document. Assume the user has MSXML 3 or better.
|
|
//
|
|
if (FAILED(hr = ptDocument.CreateInstance(CLSID_DOMDocument30)))
|
|
{
|
|
Display(ePlError, L"Unable to create instance of XML DOM, can't continue\n");
|
|
return false;
|
|
}
|
|
|
|
hr = ptDocument->setProperty(_bstr_t(L"SelectionLanguage"), _variant_t(_bstr_t(L"XPath")));
|
|
hr = ptDocument->setProperty(_bstr_t(L"SelectionNamespaces"), _variant_t(_bstr_t(SELECTION_NAMESPACES)));
|
|
|
|
ConstructEmptyAssemblyManifest(ptDocument);
|
|
|
|
//
|
|
// Get the document element - the <assembly> tag.
|
|
//
|
|
if (FAILED(ptDocument->get_documentElement(&ptDocumentRoot)))
|
|
{
|
|
Display(ePlError, L"Unable to get the document base element for this XML file. Bad XML?\n");
|
|
return false;
|
|
}
|
|
|
|
User32Trampolines::Initialize();
|
|
|
|
//
|
|
// Ensure there's file tags for the listed files on the -dlls parameter.
|
|
// If an entry is missing, add it.
|
|
//
|
|
for (SIZE_T sz = 0; sz < m_InputDllListing.Size(); sz++)
|
|
{
|
|
CSmartPointer<IXMLDOMElement> SingleFileNode;
|
|
this->FindFileDataFor(m_InputDllListing[sz], ptDocumentRoot, SingleFileNode, true);
|
|
if (m_fUseRegistryData)
|
|
{
|
|
if ( false == RegServerDll(m_InputDllListing[sz]))
|
|
{
|
|
Display(ePlError, L"%ls could not be Registered.\n", (PCWSTR)m_InputDllListing[sz]);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// First pass is to load all the files in the manifest, then go and
|
|
// think that they might contain type information.
|
|
//
|
|
if (SUCCEEDED(ptDocumentRoot->selectNodes(_bstr_t(STR_FILESEARCH_PATTERN), &ptFileElements)))
|
|
{
|
|
CSmartPointer<IXMLDOMNode> ptSingleFileNode;
|
|
while (SUCCEEDED(ptFileElements->nextNode(&ptSingleFileNode)))
|
|
{
|
|
if (ptSingleFileNode == NULL)
|
|
break;
|
|
|
|
//
|
|
// This will load the TLB from the DLL, and do all the Right Things
|
|
// in terms of getting the TLB information into the right file nodes
|
|
// (assuming they're not already in those file nodes..)
|
|
//
|
|
ProcessDllEntry(ptSingleFileNode);
|
|
|
|
//
|
|
// The one above will get released, but the one for the nextNode
|
|
// iteration is outside of the scope and should be nuked - do
|
|
// that here before the next loop.
|
|
//
|
|
ptSingleFileNode.Release();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Were we to look at the registry data? Fine, then let's go and look it all up.
|
|
//
|
|
if (this->m_fUseRegistryData)
|
|
{
|
|
GatherRegistryData();
|
|
}
|
|
|
|
//
|
|
// Now let's determine what DLLs actually expose the com classes we found. It is
|
|
// an error to expose a com class via a tlb that's not actually available from one
|
|
// of the DLLs listed.
|
|
//
|
|
{
|
|
SIZE_T iComClass = 0;
|
|
typedef HRESULT (__stdcall *pfnDllGetClassObject)(REFCLSID, REFIID, LPVOID*);
|
|
UINT uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
class CDllPairing
|
|
{
|
|
public:
|
|
CString DllName;
|
|
pfnDllGetClassObject pfnDGCO;
|
|
HMODULE hmModule;
|
|
|
|
CDllPairing() : hmModule(NULL), pfnDGCO(NULL) { }
|
|
~CDllPairing() { if (hmModule) { FreeLibrary(hmModule); hmModule = NULL; } }
|
|
};
|
|
|
|
SIZE_T cDllCount = this->m_DllInformation.Size();
|
|
CDllPairing *Dlls = new CDllPairing[cDllCount];
|
|
CDllPairing *pHere = Dlls;
|
|
|
|
for (m_DllInformation.Reset(); m_DllInformation.More(); m_DllInformation.Next())
|
|
{
|
|
pHere->DllName = m_DllInformation.CurrentKey();
|
|
pHere->hmModule = LoadLibraryW(pHere->DllName);
|
|
|
|
if (pHere->hmModule != NULL)
|
|
{
|
|
pHere->pfnDGCO = (pfnDllGetClassObject)GetProcAddress(pHere->hmModule, "DllGetClassObject");
|
|
}
|
|
|
|
pHere++;
|
|
}
|
|
|
|
for (iComClass = 0; iComClass < this->m_ComClassData.Size(); iComClass++)
|
|
{
|
|
CComClassInformation *pComClass = m_ComClassData[iComClass];
|
|
//
|
|
// Somehow we've already found this out?
|
|
//
|
|
if (pComClass->m_DllName.length() != 0)
|
|
continue;
|
|
|
|
//
|
|
// Ask all the DLLs for the class
|
|
//
|
|
for (SIZE_T idx = 0; idx < cDllCount; idx++)
|
|
{
|
|
CSmartPointer<IUnknown> punk;
|
|
HRESULT hres;
|
|
|
|
if (Dlls[idx].pfnDGCO == NULL)
|
|
continue;
|
|
|
|
hres = Dlls[idx].pfnDGCO(pComClass->m_ObjectIdent, IID_IUnknown, (LPVOID*)&punk);
|
|
|
|
if (hres != CLASS_E_CLASSNOTAVAILABLE)
|
|
pComClass->m_DllName = Dlls[idx].DllName;
|
|
|
|
if (punk != NULL)
|
|
punk->Release();
|
|
}
|
|
}
|
|
|
|
delete[] Dlls;
|
|
|
|
SetErrorMode(uiErrorMode);
|
|
}
|
|
|
|
|
|
//
|
|
// Do the "loadlibrary implies registering classes" thing
|
|
//
|
|
FindWindowClasses();
|
|
|
|
//
|
|
// Now take all the com class information and put it in files.
|
|
//
|
|
UpdateManifestWithData(ptDocument);
|
|
|
|
//
|
|
// And save it out to an xml file
|
|
//
|
|
if (FAILED(PrettyFormatXmlDocument(ptDocument)))
|
|
Display(ePlProgress, L"Could not pretty-format the document - the manifest will not be easily human-readable.\r\n");
|
|
|
|
//
|
|
// Dump current XML for fun
|
|
//
|
|
PrintXML(ptDocument);
|
|
|
|
if (FAILED(ptDocument->save(_variant_t(this->m_ManifestFilename))))
|
|
{
|
|
DisplayErrorInfo(ptDocument);
|
|
fOk = false;
|
|
}
|
|
|
|
//
|
|
// Are we on a sxs-aware platform?
|
|
//
|
|
if (m_fTestCreation)
|
|
{
|
|
HANDLE (WINAPI *pfnCreateActCtxW)(PCACTCTXW);
|
|
VOID (WINAPI *pfnReleaseActCtx)(HANDLE);
|
|
HANDLE hContext = INVALID_HANDLE_VALUE;
|
|
HMODULE hmKernel32 = NULL;
|
|
|
|
ACTCTXW actctxw = { sizeof(actctxw) };
|
|
actctxw.lpSource = this->m_ManifestFilename;
|
|
|
|
hmKernel32 = GetModuleHandleW(L"kernel32.dll");
|
|
|
|
if (hmKernel32 != NULL)
|
|
{
|
|
pfnCreateActCtxW = (HANDLE (WINAPI*)(PCACTCTXW))GetProcAddress(hmKernel32, "CreateActCtxW");
|
|
pfnReleaseActCtx = (VOID (WINAPI*)(HANDLE))GetProcAddress(hmKernel32, "ReleaseActCtx");
|
|
|
|
if ((pfnCreateActCtxW != NULL) && (pfnReleaseActCtx != NULL))
|
|
{
|
|
hContext = pfnCreateActCtxW(&actctxw);
|
|
|
|
if (hContext != INVALID_HANDLE_VALUE)
|
|
{
|
|
pfnReleaseActCtx(hContext);
|
|
Display(ePlProgress, L"Created valid assembly manifest.\r\n");
|
|
}
|
|
else
|
|
{
|
|
Display(ePlWarning, L"Warning - this manifest needs more work to be a valid component.\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Display(ePlWarning, L"Warning - can't test this manifest, this system does not support CreateActCtxW\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Display(ePlWarning, L"Warning - unable to test manifest, kernel32.dll module not found.\r\n");
|
|
}
|
|
}
|
|
|
|
User32Trampolines::Stop();
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CManBuilder::UpdateManifestWithData(
|
|
CSmartPointer<IXMLDOMDocument> ptDocument
|
|
)
|
|
{
|
|
CSimpleList<CString> FoundFiles;
|
|
this->m_DllInformation.GetKeys(FoundFiles);
|
|
const _bstr_t bstNamespace = STR_ASSEMBLY_MANIFEST_NAMESPACE;
|
|
HRESULT hr;
|
|
SIZE_T idx;
|
|
CSmartPointer<IXMLDOMElement> ptDocumentRoot;
|
|
VARIANT vt;
|
|
|
|
hr = ptDocument->get_documentElement(&ptDocumentRoot);
|
|
if (FAILED(hr))
|
|
{
|
|
Display(ePlError, L"Failed getting document root element!\r\n");
|
|
DisplayErrorInfo(ptDocument);
|
|
return false;
|
|
}
|
|
|
|
for (idx = 0; idx < this->m_WindowClasses.Size(); idx++)
|
|
{
|
|
CWindowClass *ptInfo = this->m_WindowClasses[idx];
|
|
CSmartPointer<IXMLDOMElement> ptFileElement;
|
|
CSmartPointer<IXMLDOMNode> ptWindowClassNode;
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
hr = ptDocument->createNode(vt, _bstr_t(L"windowClass"), bstNamespace, &ptWindowClassNode);
|
|
if (FAILED(hr))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ptInfo->CompleteElement(ptWindowClassNode) &&
|
|
this->FindFileDataFor(ptInfo->m_SourceDll, ptDocumentRoot, ptFileElement, true))
|
|
{
|
|
hr = ptFileElement->appendChild(ptWindowClassNode, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
for (idx = 0; idx < this->m_ComClassData.Size(); idx++)
|
|
{
|
|
CComClassInformation *ptInfo = this->m_ComClassData[idx];
|
|
CSmartPointer<IXMLDOMElement> ptFileElement;
|
|
CSmartPointer<IXMLDOMNode> ptComNodeNode;
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
if (ptInfo->m_DllName.length() == 0)
|
|
{
|
|
Display(ePlWarning, L"Com clsid %ls (%ls) not associated with a DLL, it will not be listed in the manifest\r\n",
|
|
static_cast<PCWSTR>(StringFromCLSID(ptInfo->m_ObjectIdent)),
|
|
static_cast<PCWSTR>(ptInfo->m_Name));
|
|
continue;
|
|
}
|
|
|
|
hr = ptDocument->createNode(vt, _bstr_t(L"comClass"), bstNamespace, &ptComNodeNode);
|
|
if (FAILED(hr))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ptInfo->CompleteElement(ptComNodeNode) &&
|
|
this->FindFileDataFor(ptInfo->m_DllName, ptDocumentRoot, ptFileElement, true))
|
|
{
|
|
hr = ptFileElement->appendChild(ptComNodeNode, NULL);
|
|
}
|
|
}
|
|
|
|
for (idx = 0; idx < this->m_TlbInfo.Size(); idx++)
|
|
{
|
|
CTlbInformation *ptInfo = this->m_TlbInfo[idx];
|
|
CSmartPointer<IXMLDOMElement> ptFileElement;
|
|
CSmartPointer<IXMLDOMNode> ptTlbNode;
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
hr = ptDocument->createNode(vt, _bstr_t(L"typelib"), bstNamespace, &ptTlbNode);
|
|
if (FAILED(hr))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ptInfo->CompleteElement(ptTlbNode) &&
|
|
this->FindFileDataFor(ptInfo->m_SourceFile, ptDocumentRoot, ptFileElement, true))
|
|
{
|
|
hr = ptFileElement->appendChild(ptTlbNode, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
for (SIZE_T sz = 0; sz < FoundFiles.Size(); sz++)
|
|
{
|
|
CSmartPointer<IXMLDOMElement> ptFileElement;
|
|
SIZE_T c;
|
|
|
|
CString &szFoundFilename = FoundFiles[sz];
|
|
CDllInformation &DllInfo = m_DllInformation[szFoundFilename];
|
|
|
|
// File node for this map entry not there? Insert it.
|
|
if (!this->FindFileDataFor(szFoundFilename, ptDocumentRoot, ptFileElement, true))
|
|
continue;
|
|
|
|
//
|
|
// Finally, proxy/stub interface implementors
|
|
//
|
|
for (c = 0; c < DllInfo.m_IfaceProxies.Size(); c++)
|
|
{
|
|
CSmartPointer<IXMLDOMNode> ptCreatedNode;
|
|
CComInterfaceProxyStub *pIfaceInfo = DllInfo.m_IfaceProxies[c];
|
|
VARIANT vt;
|
|
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
if (FAILED(ptDocument->createNode(vt, _bstr_t(L"comInterfaceProxyStub"), bstNamespace, &ptCreatedNode)))
|
|
continue;
|
|
|
|
if (pIfaceInfo->CompleteElement(ptCreatedNode))
|
|
{
|
|
if (FAILED(ptFileElement->appendChild(ptCreatedNode, NULL)))
|
|
{
|
|
DisplayErrorInfo(ptFileElement);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// For all the external proxies...
|
|
//
|
|
for (SIZE_T sz = 0; sz < m_ExternalProxies.Size(); sz++)
|
|
{
|
|
CSmartPointer<IXMLDOMNode> ptExtInterface;
|
|
VARIANT vt;
|
|
|
|
vt.vt = VT_INT;
|
|
vt.intVal = NODE_ELEMENT;
|
|
|
|
if (FAILED(ptDocument->createNode(vt, _bstr_t(L"comInterfaceExternalProxyStub"), bstNamespace, &ptExtInterface)))
|
|
{
|
|
DisplayErrorInfo(ptDocument);
|
|
continue;
|
|
}
|
|
|
|
m_ExternalProxies[sz]->CompleteElement(ptExtInterface);
|
|
if (FAILED(ptDocumentRoot->appendChild(ptExtInterface, NULL)))
|
|
{
|
|
DisplayErrorInfo(ptDocumentRoot);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
void
|
|
CManBuilder::DisplayParams()
|
|
{
|
|
static PCWSTR pcwszHelpText =
|
|
L"Side-by-Side component manifest building tool\r\n"
|
|
L"\r\n"
|
|
L"Parameters:\r\n"
|
|
L"\r\n"
|
|
L"-dlls [dll1] [[dll2] ...] List of DLLs to include in the component\r\n"
|
|
L" Include multiple files (-dlls foo.dll bar.dll) to create a manifest with\r\n"
|
|
L" multiple members\r\n"
|
|
L"-manifest <manifestname> File to output generated manifest to\r\n"
|
|
L"-verbose Print lots of extra debugging spew during run\r\n"
|
|
L"-silent Print minimal output, error only\r\n"
|
|
L"-nologo Don't display copyright banner\r\n"
|
|
L"-test Verify created manifest's structure\r\n"
|
|
L"-captureregistry Simulate regsvr32 of the DLL in question, and use\r\n"
|
|
L" information gathered from HKEY_CLASSES_ROOT\r\n"
|
|
L"-identity [identstring] Use the text in identstring to build the\r\n"
|
|
L" assembly's identity. See below for format\r\n"
|
|
L"\r\n"
|
|
L"Minimally, you should provide -manifest.\r\n"
|
|
L"\r\n"
|
|
L"[identstring] should be composed of name=value pairs, just like those\r\n"
|
|
L"present in a normal component. For example - the Microsoft Common Controls\r\n"
|
|
L"version 6.0.0.0 assembly for x86 could be built as follows:\r\n"
|
|
L"\r\n"
|
|
L"-identity type='win32' name='Microsoft.Windows.Common-Controls'\r\n"
|
|
L" version='6.0.0.0' processorArchitecture='x86'\r\n"
|
|
L" publicKeyToken='6595b64144ccf1df'\r\n"
|
|
L"\r\n";
|
|
|
|
Display(ePlSpew, pcwszHelpText);
|
|
}
|
|
|
|
|
|
bool
|
|
CManBuilder::Initialize(
|
|
SIZE_T argc,
|
|
WCHAR** argv
|
|
)
|
|
{
|
|
bool fNoLogo = false;
|
|
bool fParamsOk = true;
|
|
SIZE_T i;
|
|
|
|
m_Parameters.EnsureSize(argc);
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
if (lstrcmpiW(argv[i], STR_NOLOGO) == 0)
|
|
fNoLogo = true;
|
|
else
|
|
m_Parameters[m_Parameters.Size()] = argv[i];
|
|
}
|
|
|
|
if (!fNoLogo)
|
|
{
|
|
this->Display(ePlProgress, MS_LOGO);
|
|
}
|
|
|
|
for (i = 0; fParamsOk && (i < m_Parameters.Size()); i++)
|
|
{
|
|
if (CString(L"-manifest") == m_Parameters[i])
|
|
{
|
|
if ((i + 1) < m_Parameters.Size())
|
|
m_ManifestFilename = m_Parameters[++i];
|
|
else
|
|
fParamsOk = false;
|
|
}
|
|
else if (CString(L"-?") == m_Parameters[i])
|
|
{
|
|
this->m_plPrintLevel = (ErrorLevel)0xf;
|
|
DisplayParams();
|
|
return false;
|
|
}
|
|
else if (CString(L"-dlls") == m_Parameters[i])
|
|
{
|
|
while (++i < m_Parameters.Size())
|
|
{
|
|
CString param = m_Parameters[i];
|
|
|
|
if (((PCWSTR)param)[0] == L'-')
|
|
break;
|
|
|
|
m_InputDllListing.Append(param); // keep the path info
|
|
}
|
|
--i;
|
|
}
|
|
else if (CString(L"-identity") == m_Parameters[i])
|
|
{
|
|
while (++i < m_Parameters.Size())
|
|
{
|
|
CString param = m_Parameters[i];
|
|
if ((static_cast<PCWSTR>(param))[0] == L'-')
|
|
break;
|
|
m_IdentityBlob.Append(param);
|
|
}
|
|
--i;
|
|
}
|
|
else if (CString(L"-silent") == m_Parameters[i])
|
|
{
|
|
this->m_plPrintLevel = ePlError;
|
|
}
|
|
else if (CString(L"-mscopyright") == m_Parameters[i])
|
|
{
|
|
m_fAddCopyrightData = true;
|
|
}
|
|
else if (CString(L"-captureregistry") == m_Parameters[i])
|
|
{
|
|
m_fUseRegistryData = true;
|
|
}
|
|
else if (CString(L"-test") == m_Parameters[i])
|
|
{
|
|
this->m_fTestCreation = true;
|
|
}
|
|
else if (CString(L"-verbose") == m_Parameters[i])
|
|
{
|
|
this->m_plPrintLevel = (ErrorLevel)0xf;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bad parameters?
|
|
//
|
|
if (
|
|
(m_ManifestFilename.length() == 0))
|
|
{
|
|
this->m_plPrintLevel = (ErrorLevel)0xf;
|
|
DisplayParams();
|
|
return false;
|
|
}
|
|
|
|
return fParamsOk;
|
|
|
|
}
|
|
|
|
CString
|
|
CreateStringGuid()
|
|
{
|
|
GUID uuid;
|
|
CoCreateGuid(&uuid);
|
|
return StringFromCLSID(uuid);
|
|
}
|
|
|
|
int __cdecl wmain(int argc, WCHAR** argv)
|
|
{
|
|
CManBuilder builder;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
if (builder.Initialize(argc, argv))
|
|
{
|
|
builder.Run();
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|