如果删除未使用的引用 class,则 DLL 无法加载

DLL fails to load if unused ref class is removed

我 运行 遇到了一个非常奇怪的问题,试图在 UWP 应用程序中编译和使用 windows 运行时组件(VS2017 社区 15.9.13 和 NetCore.UniversalWindowsPlatform 6.2.8 , 编译时没有 /clr 但有 /ZW).

它基本上类似于 Grayscaletransform。运行时组件实际上按预期工作,现在我想删除一些未使用的代码。但是,一旦我将它从特定文件中删除并重新编译,它确实可以编译、链接,但 DLL 不再加载。

这是我必须放入的一些示例代码:

ref class DummyU sealed
{
public:
    DummyU() {}
};

DummyU^ CreateDummyU()
{
    return ref new DummyU();
}

代码只是让它工作,尽管它 a) 根本没有被引用并且 b) 没有做任何有用的事情。

删除结果:

Exception thrown at 0x0EFF322F (vccorlib140d_app.dll) in TestAppUWP.exe: 0xC0000005: Access violation reading location 0x00000000.

STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _Deref_out_ IActivationFactory** ppFactory)
{
    return Platform::Details::GetActivationFactory(Microsoft::WRL::Details::ModuleBase::module_, activatibleClassId, ppFactory);
}

dllexports.cpp 中的函数,它是 VS 的一部分。 module_ 变为 NULL

如果没有明确实例化 ref class,是否有人知道是否存在关于 windows 运行时未正确 initialized/used 的任何已知错误文件?

编辑 1:

这里是 link 完整的源代码:

您的组件的 .winmd 文件可能有误。用 C++ 制作的 WinRT 组件产生两个输出,dll 和 winmd。两者必须匹配。您可能从不同的版本中获得它们。

另一个可能的原因是清单错误。应用的清单 must include 所有引用的运行时组件。

顺便说一句,对于用经典 C++ 编写并公开 C API 的本机 DLL,部署更简单,您在包中包含一个 DLL,它们就可以工作,如果您正在使用 [DllImport]他们来自 C#。

更新: 您可以用以下代码替换 ref class,在我的电脑上有效。

struct ModuleStaticInitialize
{
    ModuleStaticInitialize()
    {
        Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
    }
};
static ModuleStaticInitialize s_moduleInit;

可能是 Microsoft 运行时某处的错误。

这里发生的是你有点混合模式。由于您已使用 /CX 标志编译 C++ 代码,因此您已告知编译器启用 winrt 扩展以生成 WinRT DLL。但实际上,您的代码 none 实际上是使用 CX 扩展来实现 类。您正在使用 WRL 和标准 C++。编译器查看 DLL,未找到 CX-style WinRT 类,因此不会设置模块。

这基本上是一个未经测试和不受支持的案例,因为您选择说要通过选择 UWP 组件库项目类型来公开 ref 类,但实际上并没有提供任何 ref 类。碰巧在引擎盖下,/CX 有效地使用了 WRL,因此您可以推动它并初始化状态以使其正常工作,但您有点破解了系统的实现细节。

我会推荐两个选项,两者都有效:只需将项目设为 non-CX Win32 DLL 并如上所述初始化模块。或者,更好的是,转到 C++ /WinRT,这将为你提供比 /CX 更好的 WinRT 类型支持,并允许你更轻松地在你的实现中混合经典 COM 类型。您只需关闭编译器开关中的 /CX 标志即可开始,然后相应地开始更新代码。