【问题标题】:Can't load WinRT Component unless I reference the project除非我引用该项目,否则无法加载 WinRT 组件
【发布时间】:2013-11-02 12:48:50
【问题描述】:

我遇到了一个奇怪的问题。我创建了一个 Windows 运行时组件(用于 Windows 应用商店),它通过一些 C# 包装类使一些遗留的 C/C++ 代码可用于 .NET。

我编写了一个引用 WRC 项目(同一解决方案中的两个项目)的测试工具商店应用程序(以下称为“test1”)。它调用组件,一切正常。

接下来我从 WRC 项目中获取以下输出文件:

MyWrtComponent.dll
MyWrtComponent.exp
MyWrtComponent.pdb
MyWrtComponent.pri
MyWrtComponent.winmd

...并尝试从另一个商店应用项目(“test2”)中使用它们。在这个项目中,我没有引用 MyWrtComponent 项目,而是添加了对 .winmd 文件的引用。一切正常,但是当我运行 test2 应用程序时,只要我尝试使用在 MyWrtComponent 中实现的 C# 类之一,就会从 mscorlib 收到 System.IO.FileNotFound 异常:

at System.StubHelpers.StubHelpers.GetWinRTFactoryObject(IntPtr pCPCMD)
at MyWrtComponent.MyWrtClass..ctor()

The specified module could not be found.
(Exception from HRESULT: 0x8007007E)

使用 MyWrtComponent 的发布版本和调试版本没有任何区别。

在 test2 上运行 ProcMon,我看到几次尝试加载 vccorlib120_app.DLL(或 vccorlib120d_app.DLL,如果我正在构建调试):

QueryOpen   F:\test2\bin\Debug\AppX\vccorlib120d_app.DLL    NAME NOT FOUND
QueryOpen   F:\test2\bin\Debug\AppX\vccorlib120d_app.DLL    NAME NOT FOUND
CreateFile  C:\Windows\SysWOW64\vccorlib120d_app.DLL    NAME NOT FOUND

我已确认此文件在我的 C:\Windows\SysWOW64 文件夹中不存在。我不知道这是否与我的问题有关。

当我运行test1时,搜索不同的位置,找到了文件:

QueryOpen   F:\test1\bin\Debug\AppX\vccorlib120d_app.DLL    NAME NOT FOUND
CreateFile  C:\Program Files\WindowsApps\Microsoft.VCLibs.120.00.Debug_12.0.20827.3_x86__8wekyb3d8bbwe\vccorlib120d_app.dll SUCCESS

我比较了两个测试项目的 bin\Debug\AppxManifest.xml,发现了一个重要的区别; test1 有以下内容,而 test2 没有:

<Dependencies>
  <PackageDependency Name="Microsoft.VCLibs.120.00.Debug" MinVersion="12.0.20827.3" />
</Dependencies>

如果我将这三行添加到 test2 的生成输出并运行应用程序,它可以工作,但这当然不是真正的修复。

有人明白这里发生了什么吗? MyWrtComponent 是否具有某种无法通信的依赖项,或者我应该做些什么来将 vccorlib120d_app.DLL 与我的运行时组件一起打包,或者...?

提前致谢。

【问题讨论】:

标签: c# visual-c++ windows-runtime windows-store-apps windows-8.1


【解决方案1】:

好吧,你在这里遇到了几个问题,第一个是你的 WinRT 组件使用 C++,你需要在你的应用程序中引用 Microsoft Visual C++ 运行时包,这是预期的由组件的最终用户(应用程序开发人员)执行,为此,请右键单击应用程序解决方案资源管理器中的 References 文件夹,然后转到 Windows->Extensions,从列表中选择 Microsoft Visual C++ Runtime Package可用的 SDK,然后单击确定。

其次,如果您打算自己保留此组件,最好引用该项目,因为它是更简单的方法,如果您打算分发它,那么您需要创建一个 SDK 以确保所有块是在一起的,注意这对于 C++ WinRT 组件是必要的,但对于 C# 或 VB.NET 组件不是,原因似乎是 C++ WinRT 组件被拆分为元数据(WinMD 文件)和实现(DLL 文件),甚至如果将它们并排放置,它们将无法相互识别,而在 C# 和 VB.NET 中,元数据及其实现位于同一个文件 (WinMD) 上。如果您想创建 SDK,请阅读 MSDN 上的this documentation

【讨论】:

    【解决方案2】:

    您的第二个版本违反了应用程序包要求。这表明您交付给商店的应用程序包嵌入了所有的依赖项,并且应用程序清单列出了所有这些依赖项。这是一个强大的 DLL Hell 对策,Store 用户根本没有希望解决您遇到的那种问题。

    添加对 .winmd 文件的引用使编译器满意,它包含足够的信息来编译您的源代码。但是下一步出错了,.winmd 文件没有为构建系统提供足够的信息来将应用程序包放在一起。它无法仅从 .winmd 文件中找出您的组件具有其他依赖项。您的主项目不依赖于 Microsoft.VCLibs,因为它是一个托管项目。

    并不是说您不能自己维护 appxmanifest。只是额外的工作太容易出错了,首先是它们在 Debug 与 Release 版本中有所不同。下一个 VS 更新会让你陷入困境,它无疑会更新 Microsoft.VCLibs,要求你更新清单中的版本号。

    使用项目引用是始终获得正确包的简单方法。

    【讨论】:

    • 我对这两个答案都投了赞成票,但我不得不为赏金选择一个,而 Rafael 的答案有对我有帮助的具体说明。谢谢汉斯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    相关资源
    最近更新 更多