#using #using "assm.netmodule" #include #include #include #include #include #include #include #include "cor.h" using namespace System; using namespace Microsoft::Fusion::ADF; using System::Runtime::InteropServices::Marshal; #define ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE 32 #define MAX_PKT_LEN 33 typedef HRESULT (*pfnGetAssemblyMDImport)(LPCWSTR szFileName, REFIID riid, LPVOID *ppv); typedef BOOL (*pfnStrongNameTokenFromPublicKey)(LPBYTE, DWORD, LPBYTE*, LPDWORD); typedef HRESULT (*pfnStrongNameErrorInfo)(); typedef VOID (*pfnStrongNameFreeBuffer)(LPBYTE); //#pragma unmanaged pfnGetAssemblyMDImport g_pfnGetAssemblyMDImport = NULL; pfnStrongNameTokenFromPublicKey g_pfnStrongNameTokenFromPublicKey = NULL; pfnStrongNameErrorInfo g_pfnStrongNameErrorInfo = NULL; pfnStrongNameFreeBuffer g_pfnStrongNameFreeBuffer = NULL; //-------------------------------------------------------------------- // BinToUnicodeHex //-------------------------------------------------------------------- HRESULT BinToUnicodeHex(LPBYTE pSrc, UINT cSrc, LPWSTR pDst) { UINT x; UINT y; #define TOHEX(a) ((a)>=10 ? L'a'+(a)-10 : L'0'+(a)) for ( x = 0, y = 0 ; x < cSrc ; ++x ) { UINT v; v = pSrc[x]>>4; pDst[y++] = TOHEX( v ); v = pSrc[x] & 0x0f; pDst[y++] = TOHEX( v ); } pDst[y] = '\0'; return S_OK; } // --------------------------------------------------------------------------- // DeAllocateAssemblyMetaData //------------------------------------------------------------------- STDAPI DeAllocateAssemblyMetaData(ASSEMBLYMETADATA *pamd) { // NOTE - do not 0 out counts // since struct may be reused. pamd->cbLocale = 0; SAFEDELETEARRAY(pamd->szLocale); SAFEDELETEARRAY(pamd->rProcessor); SAFEDELETEARRAY(pamd->rOS); return S_OK; } // --------------------------------------------------------------------------- // InitializeEEShim //------------------------------------------------------------------- HRESULT InitializeEEShim() { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); HMODULE hMod; // BUGBUG - mscoree.dll never gets unloaded with increasing ref count. // what does URT do? hMod = LoadLibrary(TEXT("mscoree.dll")); IF_WIN32_FALSE_EXIT(hMod); g_pfnGetAssemblyMDImport = (pfnGetAssemblyMDImport)GetProcAddress(hMod, "GetAssemblyMDImport"); g_pfnStrongNameTokenFromPublicKey = (pfnStrongNameTokenFromPublicKey)GetProcAddress(hMod, "StrongNameTokenFromPublicKey"); g_pfnStrongNameErrorInfo = (pfnStrongNameErrorInfo)GetProcAddress(hMod, "StrongNameErrorInfo"); g_pfnStrongNameFreeBuffer = (pfnStrongNameFreeBuffer)GetProcAddress(hMod, "StrongNameFreeBuffer"); if (!g_pfnGetAssemblyMDImport || !g_pfnStrongNameTokenFromPublicKey || !g_pfnStrongNameErrorInfo || !g_pfnStrongNameFreeBuffer) { hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); goto exit; } exit: return hr; } // --------------------------------------------------------------------------- // CreateMetaDataImport //------------------------------------------------------------------- HRESULT CreateMetaDataImport(LPCOLESTR pszFilename, IMetaDataAssemblyImport **ppImport) { HRESULT hr= S_OK; MAKE_ERROR_MACROS_STATIC(hr); IF_FAILED_EXIT(InitializeEEShim()); hr = (*g_pfnGetAssemblyMDImport)(pszFilename, IID_IMetaDataAssemblyImport, (void **)ppImport); IF_TRUE_EXIT(hr == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT), hr); // do not assert IF_FAILED_EXIT(hr); exit: return hr; } // --------------------------------------------------------------------------- // AllocateAssemblyMetaData //------------------------------------------------------------------- STDAPI AllocateAssemblyMetaData(ASSEMBLYMETADATA *pamd) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); // Re/Allocate Locale array SAFEDELETEARRAY(pamd->szLocale); if (pamd->cbLocale) { IF_ALLOC_FAILED_EXIT(pamd->szLocale = new(WCHAR[pamd->cbLocale])); } // Re/Allocate Processor array SAFEDELETEARRAY(pamd->rProcessor); IF_ALLOC_FAILED_EXIT(pamd->rProcessor = new(DWORD[pamd->ulProcessor])); // Re/Allocate OS array SAFEDELETEARRAY(pamd->rOS); IF_ALLOC_FAILED_EXIT(pamd->rOS = new(OSINFO[pamd->ulOS])); exit: if (FAILED(hr) && pamd) DeAllocateAssemblyMetaData(pamd); return hr; } // --------------------------------------------------------------------------- // ByteArrayMaker // --------------------------------------------------------------------------- HRESULT ByteArrayMaker(LPVOID pvOriginator, DWORD dwOriginator, LPBYTE *ppbPublicKeyToken, DWORD *pcbPublicKeyToken) { //LPBYTE pbPublicKeyToken; //DWORD cbPublicKeyToken; if (!(g_pfnStrongNameTokenFromPublicKey((LPBYTE)pvOriginator, dwOriginator, ppbPublicKeyToken, pcbPublicKeyToken))) { return g_pfnStrongNameErrorInfo(); } //*ppbPublicKeyToken = pbPublicKeyToken; //*pcbPublicKeyToken = cbPublicKeyToken; return S_OK; } // --------------------------------------------------------------------------- // ByteArrayFreer // --------------------------------------------------------------------------- void ByteArrayFreer(LPBYTE pbPublicKeyToken) { g_pfnStrongNameFreeBuffer(pbPublicKeyToken); } //#pragma managed namespace FusionADF { __gc public class AssemblyManifestParser { public: // --------------------------------------------------------------------------- // AssemblyManifestParser constructor // --------------------------------------------------------------------------- AssemblyManifestParser() { _dwSig = 'INAM'; _pMDImport = NULL; _rAssemblyRefTokens = NULL; _cAssemblyRefTokens = 0; _rAssemblyModuleTokens = NULL; _cAssemblyModuleTokens = 0; *_szManifestFilePath = TEXT('\0'); _ccManifestFilePath = 0; *_szAssemblyName = TEXT('\0'); _pvOriginator = NULL; _dwOriginator = 0; _name = NULL; _version = NULL; *_szPubKeyTokStr = TEXT('\0'); _pktString = NULL; _procArch = NULL; _language = NULL; _hr = S_OK; instanceValid = false; initCalledOnce = false; } // --------------------------------------------------------------------------- // AssemblyManifestParser destructor // --------------------------------------------------------------------------- ~AssemblyManifestParser() { SAFERELEASE(_pMDImport); SAFEDELETEARRAY(_rAssemblyRefTokens); SAFEDELETEARRAY(_rAssemblyModuleTokens); } bool InitFromFile(String* filePath) { LPCOLESTR lstr = 0; HRESULT hr; if(initCalledOnce) return false; initCalledOnce = true; try { lstr = static_cast(const_cast(static_cast(Marshal::StringToHGlobalAuto(filePath)))); } catch(ArgumentException *e) { // handle the exception return false; } catch (OutOfMemoryException *e) { // handle the exception return false; } hr = Init(lstr); if(hr != S_OK) return false; instanceValid = true; return true; } bool IsInstanceValid() { return instanceValid; } bool HasInitBeenCalled() { return initCalledOnce; } // --------------------------------------------------------------------------- // GetAssemblyIdentity // --------------------------------------------------------------------------- AssemblyIdentity* GetAssemblyIdentity() { return new AssemblyIdentity(_name, _version, _pktString, _procArch, _language); } // --------------------------------------------------------------------------- // GetNumDependentAssemblies // --------------------------------------------------------------------------- int GetNumDependentAssemblies() { return _cAssemblyRefTokens; } // --------------------------------------------------------------------------- // GetDependentAssemblyInfo // --------------------------------------------------------------------------- DependentAssemblyInfo* GetDependentAssemblyInfo(int nIndex) { WCHAR szAssemblyName[MAX_PATH]; const VOID* pvOriginator = 0; const VOID* pvHashValue = NULL; DWORD ccAssemblyName = MAX_PATH, cbOriginator = 0, ccLocation = MAX_PATH, cbHashValue = 0, dwRefFlags = 0; INT i; LPWSTR pwz=NULL; mdAssemblyRef mdmar; ASSEMBLYMETADATA amd = {0}; String *name = NULL, *pktString = NULL, *procArch = NULL, *language = NULL; Version *version = NULL; // Verify the index passed in. if (nIndex >= _cAssemblyRefTokens) { _hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); goto exit; } // Reference indexed dep assembly ref token. mdmar = _rAssemblyRefTokens[nIndex]; // Default allocation sizes. amd.ulProcessor = amd.ulOS = 32; amd.cbLocale = MAX_PATH; // Loop max 2 (try/retry) for (i = 0; i < 2; i++) { // Allocate ASSEMBLYMETADATA instance. IF_FAILED_EXIT(AllocateAssemblyMetaData(&amd)); // Get the properties for the refrenced assembly. IF_FAILED_EXIT(_pMDImport->GetAssemblyRefProps( mdmar, // [IN] The AssemblyRef for which to get the properties. &pvOriginator, // [OUT] Pointer to the PublicKeyToken blob. &cbOriginator, // [OUT] Count of bytes in the PublicKeyToken Blob. szAssemblyName, // [OUT] Buffer to fill with name. MAX_PATH, // [IN] Size of buffer in wide chars. &ccAssemblyName, // [OUT] Actual # of wide chars in name. &amd, // [OUT] Assembly MetaData. &pvHashValue, // [OUT] Hash blob. &cbHashValue, // [OUT] Count of bytes in the hash blob. &dwRefFlags // [OUT] Flags. )); // Check if retry necessary. if (!i) { if (amd.ulProcessor <= 32 && amd.ulOS <= 32) { break; } else DeAllocateAssemblyMetaData(&amd); } // Retry with updated sizes } // Allow for funky null locale convention // in metadata - cbLocale == 0 means szLocale ==L'\0' if (!amd.cbLocale) { amd.cbLocale = 1; } else if (amd.szLocale) { WCHAR *ptr; ptr = StrChrW(amd.szLocale, L';'); if (ptr) { (*ptr) = L'\0'; amd.cbLocale = ((DWORD) (ptr - amd.szLocale) + sizeof(WCHAR)); } } else { _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } //Name name = new String(szAssemblyName); //Version version = new Version(amd.usMajorVersion, amd.usMinorVersion, amd.usBuildNumber, amd.usRevisionNumber); //Public Key Token if (cbOriginator) { IF_ALLOC_FAILED_EXIT(pwz = new WCHAR[cbOriginator*2 +1]); IF_FAILED_EXIT(BinToUnicodeHex((LPBYTE)pvOriginator, cbOriginator, pwz)); pktString = new String(pwz); SAFEDELETEARRAY(pwz); } //Architecture procArch = S"x86"; //Language if (!(*amd.szLocale)) language = S"*"; else language = new String(amd.szLocale); _hr = S_OK; exit: DeAllocateAssemblyMetaData(&amd); SAFEDELETEARRAY(pwz); if(_hr != S_OK) return NULL; else return new DependentAssemblyInfo(new AssemblyIdentity(name, version, pktString, procArch, language), NULL); } // --------------------------------------------------------------------------- // GetNumDependentFiles // --------------------------------------------------------------------------- int GetNumDependentFiles() { return _cAssemblyModuleTokens; } // --------------------------------------------------------------------------- // GetDependentFileInfo // --------------------------------------------------------------------------- DependentFileInfo* GetDependentFileInfo(int nIndex) { LPWSTR pszName = NULL; DWORD ccPath = 0; WCHAR szModulePath[MAX_PATH]; mdFile mdf; WCHAR szModuleName[MAX_PATH]; DWORD ccModuleName = MAX_PATH; const VOID* pvHashValue = NULL; DWORD cbHashValue = 0; DWORD dwFlags = 0; LPWSTR pwz=NULL; String *name = NULL, *hash = NULL; // Verify the index. if (nIndex >= _cAssemblyModuleTokens) { _hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); goto exit; } // Reference indexed dep assembly ref token. mdf = _rAssemblyModuleTokens[nIndex]; // Get the properties for the refrenced assembly. IF_FAILED_EXIT(_pMDImport->GetFileProps( mdf, // [IN] The File for which to get the properties. szModuleName, // [OUT] Buffer to fill with name. MAX_CLASS_NAME, // [IN] Size of buffer in wide chars. &ccModuleName, // [OUT] Actual # of wide chars in name. &pvHashValue, // [OUT] Pointer to the Hash Value Blob. &cbHashValue, // [OUT] Count of bytes in the Hash Value Blob. &dwFlags)); // [OUT] Flags. //name name = new String(szModuleName); //hash if (cbHashValue) { IF_ALLOC_FAILED_EXIT(pwz = new WCHAR[cbHashValue*2 +1]); IF_FAILED_EXIT(_hr = BinToUnicodeHex((LPBYTE)pvHashValue, cbHashValue, pwz)); hash = new String(pwz); SAFEDELETEARRAY(pwz); } _hr = S_OK; exit: SAFEDELETEARRAY(pwz); if(_hr != S_OK) return NULL; else return new DependentFileInfo(name, hash); } private: DWORD _dwSig; HRESULT _hr; WCHAR _szManifestFilePath __nogc[MAX_PATH]; DWORD _ccManifestFilePath; WCHAR _szAssemblyName __nogc[MAX_CLASS_NAME]; IMetaDataAssemblyImport *_pMDImport; PBYTE _pMap; mdAssembly *_rAssemblyRefTokens; DWORD _cAssemblyRefTokens; mdFile *_rAssemblyModuleTokens; DWORD _cAssemblyModuleTokens; LPVOID _pvOriginator; DWORD _dwOriginator; String* _name; Version* _version; WCHAR _szPubKeyTokStr __nogc[MAX_PKT_LEN]; String* _pktString; String* _procArch; String* _language; bool instanceValid; bool initCalledOnce; // --------------------------------------------------------------------------- // Init // --------------------------------------------------------------------------- HRESULT Init(LPCOLESTR szManifestFilePath) { WCHAR __pin *tempFP = _szManifestFilePath; WCHAR __pin *temp_szAssemblyName = _szAssemblyName; WCHAR __pin *temp_szPubKeyTokStr = _szPubKeyTokStr; LPBYTE pbPublicKeyToken = NULL; DWORD cbPublicKeyToken = 0; DWORD dwFlags = 0, dwSize = 0, dwHashAlgId = 0; INT i; ASSEMBLYMETADATA amd = {0}; const cElems = ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE; // ********** First, work on getting metadata from file. // ********** ------------------------------------------ IF_NULL_EXIT(szManifestFilePath, E_INVALIDARG); _ccManifestFilePath = lstrlenW(szManifestFilePath) + 1; memcpy(tempFP, szManifestFilePath, _ccManifestFilePath * sizeof(WCHAR)); IF_ALLOC_FAILED_EXIT(_rAssemblyRefTokens = new(mdAssemblyRef[cElems])); IF_ALLOC_FAILED_EXIT(_rAssemblyModuleTokens = new(mdFile[cElems])); // Create meta data importer if necessary. if (!_pMDImport) { IMetaDataAssemblyImport *temp_pMDImport; // Create meta data importer _hr = CreateMetaDataImport((LPCOLESTR)tempFP, &temp_pMDImport); IF_TRUE_EXIT(_hr == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT), _hr); IF_FAILED_EXIT(_hr); _pMDImport = temp_pMDImport; } // ********** Next, get the assembly identity fields. // ********** --------------------------------------- mdAssembly mda; // Get the assembly token. if(FAILED(_hr = _pMDImport->GetAssemblyFromScope(&mda))) { // This fails when called with managed module and not manifest. mg does such things. _hr = S_FALSE; // this will convert CLDB_E_RECORD_NOTFOUND (0x80131130) to S_FALSE; goto exit; } // Default allocation sizes. amd.ulProcessor = amd.ulOS = 32; amd.cbLocale = MAX_PATH; // Loop max 2 (try/retry) for (i = 0; i < 2; i++) { // Create an ASSEMBLYMETADATA instance. IF_FAILED_EXIT(AllocateAssemblyMetaData(&amd)); LPVOID temp_pvOriginator; DWORD temp_dwOriginator; // Get name and metadata IF_FAILED_EXIT(_pMDImport->GetAssemblyProps( mda, // [IN] The Assembly for which to get the properties. (const void **)&temp_pvOriginator, // [OUT] Pointer to the Originator blob. &temp_dwOriginator, // [OUT] Count of bytes in the Originator Blob. &dwHashAlgId, // [OUT] Hash Algorithm. temp_szAssemblyName, // [OUT] Buffer to fill with name. MAX_CLASS_NAME, // [IN] Size of buffer in wide chars. &dwSize, // [OUT] Actual # of wide chars in name. &amd, // [OUT] Assembly MetaData. &dwFlags // [OUT] Flags. )); _pvOriginator = temp_pvOriginator; _dwOriginator = temp_dwOriginator; // Check if retry necessary. if (!i) { if (amd.ulProcessor <= 32 && amd.ulOS <= 32) break; else DeAllocateAssemblyMetaData(&amd); } } // Allow for funky null locale convention // in metadata - cbLocale == 0 means szLocale ==L'\0' if (!amd.cbLocale) { amd.cbLocale = 1; } else if (amd.szLocale) { WCHAR *ptr; ptr = StrChrW(amd.szLocale, L';'); if (ptr) { (*ptr) = L'\0'; amd.cbLocale = ((DWORD) (ptr - amd.szLocale) + sizeof(WCHAR)); } } else { _hr = E_FAIL; goto exit; } // NAME is _szAssemblyName, pinned in temp_szAssemblyName, set to _name using the following code: _name = new String(temp_szAssemblyName); // VERSION is _version, set using the following code: _version = new Version(amd.usMajorVersion, amd.usMinorVersion, amd.usBuildNumber, amd.usRevisionNumber); // PUBLICKEYTOKEN is being figured out if (_dwOriginator) { if(FAILED(_hr = ByteArrayMaker(_pvOriginator, _dwOriginator, &pbPublicKeyToken, &cbPublicKeyToken))) { goto exit; } if(FAILED(_hr = BinToUnicodeHex(pbPublicKeyToken, cbPublicKeyToken, temp_szPubKeyTokStr))) { goto exit; } ByteArrayFreer(pbPublicKeyToken); _pktString = new String(temp_szPubKeyTokStr); } // LANGUAGE is _language, set using the following code: if (!(*amd.szLocale)) _language = S"*"; else _language = new String(amd.szLocale); // PROCESSOR ARCHITECTURE is _procArch, set using the following code: _procArch = S"x86"; // ********** Next, get the dependent assemblies. // ********** ----------------------------------- if (!_cAssemblyRefTokens) { DWORD cTokensMax = 0; HCORENUM hEnum = 0; // Attempt to get token array. If we have insufficient space // in the default array we will re-allocate it. if (FAILED(_hr = _pMDImport->EnumAssemblyRefs( &hEnum, _rAssemblyRefTokens, ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE, &cTokensMax))) { goto exit; } // Number of tokens known. close enum. _pMDImport->CloseEnum(hEnum); hEnum = 0; // Insufficient array size. Grow array. if (cTokensMax > ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE) { // Re-allocate space for tokens. SAFEDELETEARRAY(_rAssemblyRefTokens); _cAssemblyRefTokens = cTokensMax; _rAssemblyRefTokens = new(mdAssemblyRef[_cAssemblyRefTokens]); if (!_rAssemblyRefTokens) { _hr = E_OUTOFMEMORY; goto exit; } DWORD temp_cART; // Re-get tokens. if (FAILED(_hr = _pMDImport->EnumAssemblyRefs( &hEnum, _rAssemblyRefTokens, cTokensMax, &temp_cART))) { goto exit; } _cAssemblyRefTokens = temp_cART; // Close enum. _pMDImport->CloseEnum(hEnum); hEnum = 0; } // Otherwise, the default array size was sufficient. else { _cAssemblyRefTokens = cTokensMax; } } // ********** Next, get the dependent files / modules. // ********** ---------------------------------------- if (!_cAssemblyModuleTokens) { DWORD cTokensMax = 0; HCORENUM hEnum = 0; // Attempt to get token array. If we have insufficient space // in the default array we will re-allocate it. if (FAILED(_hr = _pMDImport->EnumFiles(&hEnum, _rAssemblyModuleTokens, ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE, &cTokensMax))) { goto exit; } // Number of tokens known. close enum. _pMDImport->CloseEnum(hEnum); hEnum = 0; if (cTokensMax > ASM_MANIFEST_IMPORT_DEFAULT_ARRAY_SIZE) { // Insufficient array size. Grow array. _cAssemblyModuleTokens = cTokensMax; SAFEDELETEARRAY(_rAssemblyModuleTokens); _rAssemblyModuleTokens = new(mdFile[_cAssemblyModuleTokens]); if(_hr == S_OK) Console::WriteLine(S"Still OK 3"); if (!_rAssemblyModuleTokens) { _hr = E_OUTOFMEMORY; //Console::WriteLine(S"2 HR set, failure, going to exit"); goto exit; } DWORD temp_cAMT; // Re-get tokens. if (FAILED(_hr = _pMDImport->EnumFiles( &hEnum, _rAssemblyModuleTokens, cTokensMax, &temp_cAMT))) { //Console::WriteLine(S"3 HR set, failure, going to exit"); goto exit; } _cAssemblyModuleTokens = temp_cAMT; // Close enum. _pMDImport->CloseEnum(hEnum); hEnum = 0; } // Otherwise, the default array size was sufficient. else _cAssemblyModuleTokens = cTokensMax; } _hr = S_OK; exit: // ********** If everything worked, _hr will be S_OK. That is for caller to determine. // ********** ------------------------------------------------------------------------ DeAllocateAssemblyMetaData(&amd); return _hr; } //Functions not implemented HRESULT GetSubscriptionInfo(IManifestInfo **ppSubsInfo) { return E_NOTIMPL; } HRESULT GetNextPlatform(DWORD nIndex, IManifestData **ppPlatformInfo) { return E_NOTIMPL; } HRESULT GetManifestApplicationInfo(IManifestInfo **ppAppInfo) { return E_NOTIMPL; } HRESULT CQueryFile(LPCOLESTR pwzFileName,IManifestInfo **ppAssemblyFile) { return E_NOTIMPL; } }; }