c++ - 如何从非托管代码中获取 .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)。
解决方案
我花了很多时间试图解决这个问题,但我没有找到解决方案。一般来说,有两个系统位置带有程序集,它们在其他文件夹中生成 2 或 3 个版本的 {name}.ni.dll,每个 dll 都有自己的依赖项。我在 DotNetPeLib 中搜索了信息,并向其作者提出了问题,并拒绝了这个想法。
推荐阅读
- angular - Angular 2+ 自定义表单验证打破了表单方法
- javascript - 在不同屏幕尺寸上放大的 HTML Jumbotron 图像
- c++ - 非恒定操作的 DFS 时间复杂度
- reactjs - 如何导出在反应中动态加载的对象数组
- python - 如何聚合具有许多字符串列的 Pandas DF?
- python - 使用 Python 自定义数据库查询
- php - 使用 .env 拒绝用户 ''@'localhost' 的访问
- python - 随着时间的推移绘制多维数据(超过 3 个)
- c++ - String Class C++ 为什么反转的字符串没有正确构建?
- json - 根据默认构造函数的存在,在 Spring Data JPA 中发布和放置 HTTP 请求行为不端