#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 - 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 - 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 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 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 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 ptCreatedNode; CSmartPointer 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 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 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 ptWindowClassElement) { return SUCCEEDED(ptWindowClassElement->put_text(this->m_WindowClass)); } }; class CDllInformation { public: CString m_DllName; CSimpleList m_IfaceProxies; CSimpleList m_pInterfaces; HRESULT PopulateFileElement(CSmartPointer 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 ptFileTargetElement); bool FindFileDataFor( const CString& FileName, CSmartPointer ptDocumentRoot, CSmartPointer &ptFileNode, bool fAddIfNotPresent = false); CString m_ManifestFilename; CString m_TlbBaseName; CString m_strRegistryRootKey; CSimpleList m_Parameters; CSimpleList m_IdentityBlob; CSimpleList m_InputDllListing; CSimpleList m_ComClassData; CSimpleList m_TlbInfo; CSimpleList m_FoundInterfaces; CSimpleList m_ExternalProxies; CSimpleList m_WindowClasses; bool m_fUseRegistryData, m_fTestCreation; CSimpleMap m_DllInformation; bool ConstructEmptyAssemblyManifest(CSmartPointer ptDocument); void PrintXML(CSmartPointer ptUnk); void DisplayErrorInfo(CSmartPointer iErrorInfo); bool UpdateManifestWithData(CSmartPointer 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 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(dll)); } else { FreeLibrary(hmThisDll); } */ CSimpleList 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 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 tag, while the independent goes under // the 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(StringFromCLSID(pInfo->m_InterfaceIID)), static_cast(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(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 iErrorInfo ) { if (iErrorInfo == NULL) { Display(ePlError, L"No more error information available.\n"); } else { CSmartPointer iInfo; BSTR bst; GetErrorInfo(0, &iInfo); if ((iInfo != NULL) && SUCCEEDED(iInfo->GetDescription(&bst))) { Display(ePlError, L"Error: %ls\r\n", static_cast(bst)); if (bst) { SysFreeString(bst); bst = NULL; } } } } void CManBuilder::PrintXML( CSmartPointer ptDispatch ) { if (0) { CSmartPointer 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((_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 ptDocument ) { // // Remove /everything/ from the document. // CSmartPointer Processing; CSmartPointer AssemblyRootNode; CSmartPointer AssemblyRootElement; VARIANT vt; HRESULT hr; // Create a processing instruction - 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 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 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 ptIdentityNode; CSmartPointer ptIdentity; CSmartPointer 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(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(strName), static_cast(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*)lp)->Append(tgt); return TRUE; } bool CManBuilder::ProcessDllEntry( CSmartPointer ptFileElement ) { _variant_t vtFileName; CSimpleList 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(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 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(_bstr_t(vtFileName)), static_cast(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 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 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 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(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 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 ptDocument; CSmartPointer ptCreatedNode; CSmartPointer ptCreatedFileTag; CSmartPointer 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 ptDocument; CSmartPointer ptBaseTypeLibrary; CSmartPointer ptDocumentRoot; CSmartPointer 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 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 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 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 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 ptDocument ) { CSimpleList FoundFiles; this->m_DllInformation.GetKeys(FoundFiles); const _bstr_t bstNamespace = STR_ASSEMBLY_MANIFEST_NAMESPACE; HRESULT hr; SIZE_T idx; CSmartPointer 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 ptFileElement; CSmartPointer 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 ptFileElement; CSmartPointer 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(StringFromCLSID(ptInfo->m_ObjectIdent)), static_cast(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 ptFileElement; CSmartPointer 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 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 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 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 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(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(); }