首页 > 解决方案 > 如何从非托管代码中获取 .Net 框架程序集依赖项的 dll 名称?

问题描述

我正在尝试从 c++ 程序中获取 .net exe 或 dll 的程序集依赖项列表。目前我的目标平台是带有 .Net 更大 v4 的 Windows 10。我只发现了一些关于这个问题的主题,毕竟我创建了显示来自 .net pe 文件的程序集名称的测试程序。此示例演示如何从非托管 c++ 代码中获取程序集名称。

CComPtr<ICLRMetaHost> pMetaHost;
CComPtr<ICLRRuntimeInfo> pRuntime;
CComPtr<IMetaDataDispenser> pDisp;
CComPtr<IMetaDataAssemblyImport> pAssImport;

HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost,IID_ICLRMetaHost,(void **)&pMetaHost);

wchar_t fileVersion[MAX_PATH] = {};
DWORD dwBuffer = MAX_PATH;
hr = pMetaHost->GetVersionFromFile(file.c_str(),fileVersion,&dwBuffer);

hr = pMetaHost->GetRuntime(fileVersion,IID_ICLRRuntimeInfo,(void **)&pRuntime);

hr = pRuntime->GetInterface(CLSID_CorMetaDataDispenser,IID_IMetaDataDispenser,(void **)&pDisp);

hr = pDisp->OpenScope(file.c_str(), ofRead, IID_IMetaDataAssemblyImport, reinterpret_cast<IUnknown **>(&pAssImport));

mdAssemblyRef  Files[50] = { 0 };
ULONG numTokensOut = 0;
ULONG numTokensIn = 50;
HCORENUM hCoreEnum = NULL;

hr = pAssImport->EnumAssemblyRefs(&hCoreEnum, Files, numTokensIn, &numTokensOut);

for (ULONG j = 0; j < numTokensOut; ++j) {
    wchar_t publicKey[MAX_PATH];
    ULONG ulPublicKeyLen;
    wchar_t simpleName[MAX_PATH];
    ULONG ulSimpleName;
    ASSEMBLYMETADATA assmd{};
    wchar_t hash[MAX_PATH];
    ULONG ulHash = MAX_PATH;
    DWORD dwAssemblyRefFlags;

    hr = pAssImport->GetAssemblyRefProps(Files[j], (const void**)&publicKey, &ulPublicKeyLen, simpleName, MAX_PATH, &ulSimpleName, &assmd, (const void**)&hash, &ulHash,&dwAssemblyRefFlags);
}
if (hCoreEnum)
    pAssImport->CloseEnum(hCoreEnum);

现在我需要将程序集绑定到特定的 dll 文件。我知道,这些文件位于 C:\Windows\Assembly 目录中,但在我的操作系统中有 GAC、.Net 2 和 .Net 4 的文件,以及用于 x32 和 x64 文件的单独文件夹。

我认为 IMetaDataAssemblyImport::FindAssembliesByName 可以帮助我选择特定文件,但我对这种方法有疑问。在文档中有此方法的注释:

您必须在调用 FindAssembliesByName 之前调用 CoInitializeEE(通过 COINITEE_DEFAULT)

此调用已弃用,我使用 ICLRRuntimeHost::Start 启动 CLR

CComPtr<ICLRRuntimeHost> pRuntimeHost;    
hr = pRuntime->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (LPVOID *)&pRuntimeHost);

hr = pRuntimeHost->Start();

现在我在 Start 方法期间遇到异常

抛出异常:读取访问冲突。ThreadStore::s_pThreadStore 为 nullptr。

我的方法正确吗?或者也许有更简单的方法?我认为启动 CLR 不是最好的方法,但我不知道如何避免它。也许我可以使用程序集中的 .Net 版本并在程序集目录中进行搜索,但在这种情况下,很难解决我必须使用的 dll 版本(x32 或 x64)。

标签: c++.netwindowsunmanaged

解决方案


我花了很多时间试图解决这个问题,但我没有找到解决方案。一般来说,有两个系统位置带有程序集,它们在其他文件夹中生成 2 或 3 个版本的 {name}.ni.dll,每个 dll 都有自己的依赖项。我在 DotNetPeLib 中搜索了信息,并向其作者提出了问题,并拒绝了这个想法。


推荐阅读