繁体   English   中英

您能否从基本 Win32 控制台模板应用程序中的 C#/Winrt 组件调用(不是 WinForm/abstractions/wrappers 或使用 C++/Winrt 模板)?

[英]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.exemidlrt.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>

assemblyIdentityname不是特别重要,特别重要的是fileactivatableClassname :它必须与主机 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM