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