[英]Can you call from a C#/Winrt Component inside a base Win32 console template app (not WinForm/abstractions/wrappers or using the C++/Winrt template)?)
我有一个现有程序 win32 (x86) 控制台应用程序需要调用托管代码(C# 来自 a.Net .dll
)。 .dll
未暴露给 COM,但可以从 C#/WinRT 组件调用并由 C++/WinRT 控制台模板应用程序引用,但我似乎无法从 win32 x86 控制台应用程序调用它,即使安装了 C++/ WinRT NuGet package。我构建并运行了这个示例,但使用的应用程序始终使用 C++/WinRT 模板。 当我尝试使用基本 win32 应用程序重现示例时,出现错误REGDB_E_CLASSNOTREG Class not registered
。
我找到了另一个示例,展示了如何在不注册类的情况下从 win32 应用程序使用 C++/WinRT 组件。 我以为这就是我的答案。 但是,该过程涉及进入应用程序清单并通过在每次构建 C++/WinRT 组件时引用输出的.dll
文件来指定可激活的 WinRT 类。
问题在于: C#/WinRT 组件没有output (请参阅编辑)使用.dll
文件,只有.winmd
。.winmd
文件,我仍然可以引用类并构建我的项目,但我最终遇到相同的REGDB_E_CLASSNOTREG Class not registered
错误。 我假设 C++/WinRT 和 C#/WinRT 组件都会编译成某种中间语言的东西(见评论),但为什么 C++/WinRT output a .dll
和.winmd
而 C#/WinRT 只输出.winmd
文件? 我尝试使用WinRT.Runtime.dll
代替输出的.dll
但这也不起作用。
我不知所措。 我发布了另一个关于 C++/WinRT 模板与 win32 与 C++/WinRT NuGet package 之间的区别的问题。
主要问题:我能以某种方式在基本 win32 控制台应用程序中使用 C# .dll
(不是暴露的 COM)吗?
我意识到我正在使用特定于 UWP 的 C# Windows 运行时组件模板。这可能是构建时没有输出 .dll 的原因。
根据 Simon 的回复,我能够创建一个 C# WinRT 组件,它可以从 Win32 控制台应用程序调用。 这个 C# WinRT 组件DOES output a.dll 以及 .winmd。 我仔细阅读了 Simon 发布的关于使用 C++ 的文章,并设法让它与基本的 C# 功能一起使用。
REGDB_E_CLASSNOTREG
表示您要求的 class(无论它是 COM/WinRT 等)未注册/已知激活系统(托管在 combase.dll 中)。
问题可能出在您尝试使用免注册 WinRT 组件这一事实。
让我们以此示例作为 C# 组件的开始: 演练:创建 C#/WinRT 组件并从 C++/WinRT 使用它。 因此,只需创建 C# 组件,但不要创建 C++/WinRT 应用。 (我用的是Visual Studio 2019和.net5.0-windows10.0.19041.0)。
注意:C#/WinRT 确实会生成 a.dll(此处为SampleComponent.dll
),而不仅仅是元数据。
如果您不构建 C++/WinRT 应用程序,您仍然需要构建一个 regular.h 文件以使用 C# 组件。 C++/WinRT 会为你做这件事,但由于我们不使用这个工具,所以我们必须自己构建它。 为此,我们需要另外两个工具winmdidl.exe
和midlrt.exe
,您可以从Visual Studio 开发人员命令提示中找到它们。 .另请参阅如何:使用 winmdidl.exe 和 midlrt.exe 从 windows 元数据创建 .h 文件
因此,如果您遵循本教程,则从您拥有的SampleComponent.winmd
运行:
winmdidl SampleComponent.winmd
这将创建一个SampleComponent.idl
文件。 现在运行:
midlrt SampleComponent.idl /metadata_dir "C:\Windows\System32\WinMetadata"
这将创建多个文件(代理、存根等),但我们只需要SampleComponent.h
。 现在,像这样创建一个标准的 C++ 控制台应用程序(我不使用 C++/WinRT 我仍然使用Wrl
来简化我的代码,但这不是强制性的):
#include <windows.h>
#include <stdio.h>
#include <wrl.h>
#include <wrl/wrappers/corewrappers.h>
#include "path to SampleComponent.h"
#pragma comment(lib, "runtimeobject.lib")
using namespace Microsoft::WRL; // ComPtr
using namespace Microsoft::WRL::Wrappers; // RoInitializeWrapper, HStringReference, HString
using namespace Windows::Foundation; // GetActivationFactory, ActivateInstance
int main()
{
RoInitializeWrapper init(RO_INIT_MULTITHREADED);
HRESULT hr = init;
// all error checks on hr omitted
ComPtr<SampleComponent::IExampleClass> cls;
hr = ActivateInstance(HStringReference(RuntimeClass_SampleComponent_Example).Get(), &cls);
hr = cls->put_SampleProperty(42);
INT32 i;
hr = cls->get_SampleProperty(&i);
wprintf(L"%u\n", i);
ComPtr<SampleComponent::IExampleStatic> clsStatic;
hr = GetActivationFactory(HStringReference(RuntimeClass_SampleComponent_Example).Get(), &clsStatic);
HString str;
hr = clsStatic->SayHello(str.GetAddressOf());
wprintf(L"%s\n", str.GetRawBuffer(nullptr));
}
RuntimeClass_SampleComponent_Example
来自SampleComponent.h
,应该这样定义:
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_SampleComponent_Example[] = L"SampleComponent.Example";
如果编译并运行,hr 将是REGDB_E_CLASSNOTREG
,因为系统找不到'SampleComponent.Example'
组件。
因此,您必须执行的操作在此处进行了说明: 免注册 WinRT 的工作原理
您必须向项目添加一个扩展名为.manifest
的文件(任何名称都应适用于最新版本的 Visual Studio),例如:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CppConsoleApp"/>
<file name="WinRT.Host.dll">
<activatableClass
name="SampleComponent.Example"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
assemblyIdentity
的name
不是特别重要,特别重要的是file
和activatableClass
的name
:它必须与主机 dll 名称相同(这里必须是 C#/WinRT 提供的WinRT.Host.dll
)和class 您尝试激活的名称(对应于RuntimeClass_SampleComponent_Example
)。
您还必须复制 .exe 文件旁边所需的所有 C#/ WinRT文件。 That would be: SampleComponent.dll
, Microsoft.Windows.SDK.NET.dll
, WinRT.Host.dll
, WinRT.Host.runtimeconfig.json
, WinRT.Host.Shim.dll
, WinRT.Runtime.dll
.
请注意,您可以使用 C++/WinRT 来帮助构建WinRT.Host.runtimeconfig.json
。
现在,它应该可以工作了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.