[英]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)?)
I have an existing program win32 (x86) console app that needs to call managed code (C# from a.Net .dll
).我有一个现有程序 win32 (x86) 控制台应用程序需要调用托管代码(C# 来自 a.Net
.dll
)。 The .dll
is not exposed to COM, but can be called from a C#/WinRT Component and referenced by C++/WinRT Console Template app, BUT I can't seem to call it from a win32 x86 console app even after installing the C++/WinRT NuGet package. I've built and ran this example but the consuming apps are always using the C++/WinRT template. .dll
未暴露给 COM,但可以从 C#/WinRT 组件调用并由 C++/WinRT 控制台模板应用程序引用,但我似乎无法从 win32 x86 控制台应用程序调用它,即使安装了 C++/ WinRT NuGet package。我构建并运行了这个示例,但使用的应用程序始终使用 C++/WinRT 模板。 When I try to reproduce the example with a base win32 app, I get the error REGDB_E_CLASSNOTREG Class not registered
.当我尝试使用基本 win32 应用程序重现示例时,出现错误
REGDB_E_CLASSNOTREG Class not registered
。
I found another example showing how to consume a C++/WinRT component from a win32 app, without registering classes.我找到了另一个示例,展示了如何在不注册类的情况下从 win32 应用程序使用 C++/WinRT 组件。 I thought this was my answer.
我以为这就是我的答案。 However the process involves going into the application manifest and specify activatable WinRT classes by referencing the outputted
.dll
file whenever the C++/WinRT component builds.但是,该过程涉及进入应用程序清单并通过在每次构建 C++/WinRT 组件时引用输出的
.dll
文件来指定可激活的 WinRT 类。
Here's the problem: C#/WinRT components do not output a .dll
file, only the .winmd
.问题在于:
C#/WinRT 组件没有output (see Edit) With the .dll
文件,只有.winmd
。.winmd
file, I can still reference the classes and build my project, But I end up with the same REGDB_E_CLASSNOTREG Class not registered
error. (请参阅编辑)使用
.winmd
文件,我仍然可以引用类并构建我的项目,但我最终遇到相同的REGDB_E_CLASSNOTREG Class not registered
错误。 I assume both the C++/WinRT and C#/WinRT components would compile into something that is in an Intermediate Language (see comments), but why does C++/WinRT output a .dll
and a .winmd
, while C#/WinRT only outputs .winmd
files?我假设 C++/WinRT 和 C#/WinRT 组件都会编译成某种中间语言的东西(见评论),但为什么 C++/WinRT output a .dll
和.winmd
而 C#/WinRT 只输出.winmd
文件? I tried to use WinRT.Runtime.dll
in place of the outputted .dll
but that didnt work either.我尝试使用
WinRT.Runtime.dll
代替输出的.dll
但这也不起作用。
I'm at a loss.我不知所措。 I posted another question about the difference between the C++/WinRT template vs win32 with C++/WinRT NuGet package.
我发布了另一个关于 C++/WinRT 模板与 win32 与 C++/WinRT NuGet package 之间的区别的问题。
Main Problem: Can I use a C# .dll
(not COM exposed) in a base win32 console app somehow?主要问题:我能以某种方式在基本 win32 控制台应用程序中使用 C#
.dll
(不是暴露的 COM)吗?
I realized that I was using a C# Windows Runtime Component template that was specific to UWP. This might be why there was no outputted.dll when built.我意识到我正在使用特定于 UWP 的 C# Windows 运行时组件模板。这可能是构建时没有输出 .dll 的原因。
Following Simon's reply, I was able to create a C# WinRT component that can be called from a Win32 console app.根据 Simon 的回复,我能够创建一个 C# WinRT 组件,它可以从 Win32 控制台应用程序调用。 This C# WinRT component DOES output a.dll as well as.winmd.
这个 C# WinRT 组件DOES output a.dll 以及 .winmd。 I followed a bit closer to the article Simon posted about consuming with C++ and managed to get it to work with basic C# functions.
我仔细阅读了 Simon 发布的关于使用 C++ 的文章,并设法让它与基本的 C# 功能一起使用。
REGDB_E_CLASSNOTREG
means the class that you ask for (whatever it is COM/WinRT etc.) is not registered/known to the activation system (hosted in combase.dll). REGDB_E_CLASSNOTREG
表示您要求的 class(无论它是 COM/WinRT 等)未注册/已知激活系统(托管在 combase.dll 中)。
The problem probably comes from the fact you're trying to use a registration-free WinRT component.问题可能出在您尝试使用免注册 WinRT 组件这一事实。
Let's take this sample as a start for the C# component: Walkthrough: Create a C#/WinRT component and consume it from C++/WinRT .让我们以此示例作为 C# 组件的开始: 演练:创建 C#/WinRT 组件并从 C++/WinRT 使用它。 So, just create the C# component but don't create the C++/WinRT app.
因此,只需创建 C# 组件,但不要创建 C++/WinRT 应用。 (I use Visual Studio 2019 and.net5.0-windows10.0.19041.0).
(我用的是Visual Studio 2019和.net5.0-windows10.0.19041.0)。
Note: C#/WinRT does produce a.dll (here SampleComponent.dll
), not only metadata.注意:C#/WinRT 确实会生成 a.dll(此处为
SampleComponent.dll
),而不仅仅是元数据。
If you don't build the C++/WinRT app, you still need to build a regular.h file to use the C# component.如果您不构建 C++/WinRT 应用程序,您仍然需要构建一个 regular.h 文件以使用 C# 组件。 C++/WinRT does that for you, but since we don't use this tool, we must build it ourselves.
C++/WinRT 会为你做这件事,但由于我们不使用这个工具,所以我们必须自己构建它。 For that, we need two other tools
winmdidl.exe
and midlrt.exe
that you'll find from Developer Command Prompt for Visual Studio.为此,我们需要另外两个工具
winmdidl.exe
和midlrt.exe
,您可以从Visual Studio 开发人员命令提示中找到它们。 .See also How to: Use winmdidl.exe and midlrt.exe to create.h files from windows metadata .另请参阅如何:使用 winmdidl.exe 和 midlrt.exe 从 windows 元数据创建 .h 文件
So from the SampleComponent.winmd
that you have if you followed the tutorial, run:因此,如果您遵循本教程,则从您拥有的
SampleComponent.winmd
运行:
winmdidl SampleComponent.winmd
this will create a SampleComponent.idl
file.这将创建一个
SampleComponent.idl
文件。 Now run:现在运行:
midlrt SampleComponent.idl /metadata_dir "C:\Windows\System32\WinMetadata"
this will create multiple files (proxy, stub, etc.), but we only need SampleComponent.h
.这将创建多个文件(代理、存根等),但我们只需要
SampleComponent.h
。 Now, create a standard C++ console app like this (I don't use C++/WinRT I still use Wrl
to simplify my code, but this is not mandatory):现在,像这样创建一个标准的 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
is from SampleComponent.h
and should be defined like this: RuntimeClass_SampleComponent_Example
来自SampleComponent.h
,应该这样定义:
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_SampleComponent_Example[] = L"SampleComponent.Example";
If you compile that and run, hr will be REGDB_E_CLASSNOTREG
because the system cannot find the 'SampleComponent.Example'
component.如果编译并运行,hr 将是
REGDB_E_CLASSNOTREG
,因为系统找不到'SampleComponent.Example'
组件。
So what you must do is explained here: How Registration-free WinRT Works因此,您必须执行的操作在此处进行了说明: 免注册 WinRT 的工作原理
You must add a file to the project with the .manifest
extension (any name should work with recent versions of Visual Studio), for example like this:您必须向项目添加一个扩展名为
.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
's name
is not super important, what is super important is file
and activatableClass
's name
: it must be the same as the host dll name (here it must be WinRT.Host.dll
which is provided by C#/WinRT) and class name you're trying to activate (corresponding to RuntimeClass_SampleComponent_Example
). assemblyIdentity
的name
不是特别重要,特别重要的是file
和activatableClass
的name
:它必须与主机 dll 名称相同(这里必须是 C#/WinRT 提供的WinRT.Host.dll
)和class 您尝试激活的名称(对应于RuntimeClass_SampleComponent_Example
)。
You must also copy all the C#/WinRT files mess needed aside your.exe file.您还必须复制 .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
. That would be:
SampleComponent.dll
, Microsoft.Windows.SDK.NET.dll
, WinRT.Host.dll
, WinRT.Host.runtimeconfig.json
, WinRT.Host.Shim.dll
, WinRT.Runtime.dll
.
Note you can use C++/WinRT to help building WinRT.Host.runtimeconfig.json
.请注意,您可以使用 C++/WinRT 来帮助构建
WinRT.Host.runtimeconfig.json
。
And now, it should work.现在,它应该可以工作了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.