簡體   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