如何从本机 C++ 调用 C# 库(使用 C++\CLI 和 IJW)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13293888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call a C# library from Native C++ (using C++\CLI and IJW)
提问by amalgamate
Background:As part of a larger assignment I need to make a C# library accessible to unmanaged C++ and C code. In an attempt to answer this question myself I have been learning C++/CLI the past few days/ weeks.
背景:作为更大任务的一部分,我需要使非托管 C++ 和 C 代码可以访问 C# 库。为了自己回答这个问题,过去几天/几周我一直在学习 C++/CLI。
There seems to be a number of different ways to achieve using a C# dll from unmanaged C++ and C. Some of the answers in brief appear to be: using Interlope services, Using .com. and regasm, Using PInvoke (which appears to go from C# to C++ only), and using IJW in the C++/CLR (which appears to be Interlope services). I am thinking it would be best to set up a library that is perhaps a CLR wrapper that uses IJW to call my C# dll on the behalf of native C++ and C code.
似乎有许多不同的方法可以使用来自非托管 C++ 和 C 的 C# dll 来实现。一些简短的答案似乎是:使用 Interlope 服务、使用 .com。和 regasm,使用 PInvoke(它似乎只从 C# 转到 C++),并在 C++/CLR(它似乎是 Interlope 服务)中使用 IJW。我认为最好设置一个库,它可能是一个 CLR 包装器,它使用 IJW 代表本机 C++ 和 C 代码调用我的 C# dll。
Specifics:I need to pass values of string as well as int to a C# dll from c++ code, and return void.
细节:我需要将字符串和 int 的值从 C++ 代码传递给 C# dll,并返回 void。
Relevance:Many companies have many excuses to mix and match C++, C and C#. Performance: unmanaged code is usually faster, interfaces: Managed interfaces are generally easier to maintain, deploy, and are often easier on the eyes, Managers tell us too. Legacy code forces us too. It was there (Like the mountain that we climbed). While examples of how to call a C++ library from C# are abundant. Examples of how to call C# libraries from C++ code are difficult to find via Googling especially if you want to see updated 4.0+ code.
相关性:许多公司有很多借口混合搭配 C++、C 和 C#。性能:非托管代码通常更快,接口:托管接口通常更容易维护、部署,并且通常更容易看,经理也告诉我们。遗留代码也迫使我们这样做。它就在那里(就像我们爬过的山一样)。虽然如何从 C# 调用 C++ 库的示例很多。通过谷歌搜索很难找到如何从 C++ 代码调用 C# 库的示例,特别是如果您想查看更新的 4.0+ 代码。
Software:C#, C++/CLR, C++, C, Visual Studio 2010, and .NET 4.0
软件:C#、C++/CLR、C++、C、Visual Studio 2010 和 .NET 4.0
Question details:OK multi-part question:
问题详情:OK 多部分问题:
Is there an advantage to using com objects? Or the PInvoke? Or some other method? (I feel like the learning curve here will be just as steep, even though I do find more information on the topic in Google Land. IJW seems to promise what I want it to do. Should I give up on looking for an IJW solution and focus on this instead?) (Advantage/ disadvantage?)
Am I correct in imagining that there is a solution where I write a wrapper that that utilizes IJW in the C++/CLR? Where can I find more information on this topic, and don't say I didn't Google enough/ or look at MSDN without telling me where you saw it there. (I think I prefer this option, in the effort to write clear and simple code.)
A narrowing of question scope: I feel that my true issue and need is answering the smaller question that follows: How do I set up a C++/CLR library that an unmanaged C++ file can use within visual studio. I think that if I could simply instantiate a managed C++ class in unmanaged C++ code, then I might be able work out the rest (interfacing and wrapping etc.). I expect that my main folly is in trying to set up references/#includes etc. within Visual Studio, thought clearly I could have other misconceptions. Perhaps the answer to this whole thing could be just a link to a tutorial or instructions that help me with this.
使用 com 对象有优势吗?还是 PInvoke?或者其他什么方法?(我觉得这里的学习曲线同样陡峭,即使我确实在 Google Land 中找到了有关该主题的更多信息。IJW 似乎承诺了我想要它做的事情。我应该放弃寻找 IJW 解决方案吗?而是专注于此?)(优势/劣势?)
我是否正确地想象有一个解决方案,我可以编写一个在 C++/CLR 中使用 IJW 的包装器?我在哪里可以找到关于这个主题的更多信息,不要说我没有足够的谷歌/或者在没有告诉我你在哪里看到它的情况下查看 MSDN。(我想我更喜欢这个选项,努力编写清晰简单的代码。)
缩小问题范围:我觉得我真正的问题和需要是回答以下较小的问题:如何设置非托管 C++ 文件可以在 Visual Studio 中使用的 C++/CLR 库。我认为,如果我可以简单地在非托管 C++ 代码中实例化一个托管 C++ 类,那么我也许可以解决其余的问题(接口和包装等)。我希望我的主要愚蠢之处在于尝试在 Visual Studio 中设置引用/#includes 等,但显然我可能会有其他误解。也许这整个事情的答案可能只是一个指向帮助我解决这个问题的教程或说明的链接。
Research:I have Googled and Binged over and over with some success. I have found many links that show you how to use an unmanaged library from C# code. And I will admit that there have been some links that show how to do it using com objects. Not many results were targeted at VS 2010.
研究:我一次又一次地在谷歌上搜索和 Bing 并取得了一些成功。我找到了许多向您展示如何使用 C# 代码中的非托管库的链接。我承认已经有一些链接展示了如何使用 com 对象来做到这一点。针对 VS 2010 的结果并不多。
References:I have read over and over many posts. I have tried to work through the most relevant ones. Some seem tantalizingly close to the answer, but I just can't seem to get them to work. I suspect that the thing that I am missing is tantalizingly small, such as misusing the keyword ref, or missing a #include or using statement, or a misuse of namespace, or not actually using the IJW feature properly, or missing a setting that VS needs to handle the compilation correctly, etc. So you wonder, why not include the code? Well I feel like I am not at a place where I understand and expect the code I have to work. I want to be in a place where I understand it, when I get there maybe then I'll need help fixing it. I'll randomly include two of the links but I am not permitted to show them all at my current Hitpoint level.
参考资料:我反复阅读了很多帖子。我试图通过最相关的工作。有些似乎非常接近答案,但我似乎无法让它们起作用。我怀疑我缺少的东西非常小,例如滥用关键字 ref,或缺少 #include 或 using 语句,或滥用名称空间,或实际上未正确使用 IJW 功能,或缺少 VS 的设置需要正确处理编译等。所以你想知道,为什么不包括代码?好吧,我觉得我不是在一个我理解并期望我必须工作的代码的地方。我想待在一个我能理解的地方,当我到达那里时,也许我需要帮助修复它。我将随机包含两个链接,但我不允许在当前的 Hitpoint 级别显示所有链接。
http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod
http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod
This calls code from managed and unmanaged code in both directions going from C++ to Visual Basic and back via C++CLR, and of course I am interested in C#.: http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice
这在从 C++ 到 Visual Basic 和通过 C++CLR 返回的两个方向上从托管和非托管代码调用代码,当然我对 C# 感兴趣。:http: //www.codeproject.com/Articles/9903/Calling -Managed-Code-from-Unmanaged-Code-and-Vice
采纳答案by amalgamate
I found something that at least begins to answer my own question. The following two links have wmv files from Microsoft that demonstrate using a C# class in unmanaged C++.
我发现一些东西至少开始回答我自己的问题。以下两个链接包含来自 Microsoft 的 wmv 文件,这些文件演示了在非托管 C++ 中使用 C# 类。
This first one uses a COM object and regasm: http://msdn.microsoft.com/en-us/vstudio/bb892741.
第一个使用 COM 对象和 regasm:http: //msdn.microsoft.com/en-us/vstudio/bb892741。
This second one uses the features of C++/CLI to wrap the C# class: http://msdn.microsoft.com/en-us/vstudio/bb892742. I have been able to instantiate a c# class from managed code and retrieve a string as in the video. It has been very helpful but it only answers 2/3rds of my question as I want to instantiate a class with a string perimeter into a c# class. As a proof of concept I altered the code presented in the example for the following method, and achieved this goal. Of course I also added a altered the {public string PickDate(string Name)} method to do something with the name string to prove to myself that it worked.
第二个使用 C++/CLI 的功能来包装 C# 类:http: //msdn.microsoft.com/en-us/vstudio/bb892742。我已经能够从托管代码实例化 ac# 类并检索视频中的字符串。它非常有帮助,但它只回答了我问题的 2/3,因为我想将一个带有字符串周长的类实例化到 ac# 类中。作为概念证明,我更改了示例中为以下方法提供的代码,并实现了这一目标。当然,我还添加了一个修改过的 {public string PickDate(string Name)} 方法来对名称字符串做一些事情来向自己证明它有效。
wchar_t * DatePickerClient::pick(std::wstring nme)
{
IntPtr temp(ref);// system int pointer from a native int
String ^date;// tracking handle to a string (managed)
String ^name;// tracking handle to a string (managed)
name = gcnew String(nme.c_str());
wchar_t *ret;// pointer to a c++ string
GCHandle gch;// garbage collector handle
DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
gch = static_cast<GCHandle>(temp);// converted from the int pointer
obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
date = obj->PickDate(name);
ret = new wchar_t[date->Length +1];
interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
wcscpy_s(ret, date->Length +1, p2);
return ret;
}
Part of my question was: What is better? From what I have read in many many efforts to research the answer is that COM objects are considered easier to use, and using a wrapper instead allows for greater control. In some cases using a wrapper can (but not always) reduce the size of the thunk, as COM objects automatically have a standard size footprint and wrappers are only as big as they need to be.
我的部分问题是:什么更好?从我在许多研究中读到的答案是,COM 对象被认为更易于使用,而使用包装器可以实现更好的控制。在某些情况下,使用包装器可以(但并非总是)减小 thunk 的大小,因为 COM 对象自动具有标准大小的占用空间,而包装器只需要它们的大小即可。
The thunk (as I have used above) refers to the space time and resources used in between C# and C++ in the case of the COM object, and in between C++/CLI and native C++ in the case of coding-using a C++/CLI Wrapper. So another part of my answer should include a warning that crossing the thunk boundary more than absolutely necessary is bad practice, accessing the thunk boundary inside a loop is not recommended, and that it is possible to set up a wrapper incorrectly so that it double thunks (crosses the boundary twice where only one thunk is called for) without the code seeming to be incorrect to a novice like me.
thunk(正如我上面使用的)是指在 COM 对象的情况下 C# 和 C++ 之间使用的空间时间和资源,以及在使用 C++/CLI 编码的情况下 C++/CLI 和本机 C++ 之间使用的空间时间和资源包装纸。所以我的答案的另一部分应该包括一个警告,即越过 thunk 边界超过绝对必要是不好的做法,不建议访问循环内的 thunk 边界,并且可能会错误地设置包装器以便它加倍 thunk (跨越边界两次,只需要一个 thunk )没有代码对于像我这样的新手来说似乎是不正确的。
Two notes about the wmv's. First: some footage is reused in both, don't be fooled. At first they seem the same but they do cover different topics. Second, there are some bonus features such as marshalling that are now a part of the CLI that are not covered in the wmv's.
关于 wmv 的两个注意事项。第一:一些镜头在两者中重复使用,不要被愚弄。起初它们看起来相同,但它们确实涵盖了不同的主题。其次,还有一些额外的功能,例如编组,现在是 CLI 的一部分,但 wmv 中没有涵盖这些功能。
Edit:
编辑:
Note there is a consequence for your installs, your c++ wrapper will not be found by the CLR. You will have to either confirm that the c++ application installs in any/every directory that uses it, or add the library (which will then need to be strongly named) to the GAC at install time. This also means that with either case in development environments you will likely have to copy the library to each directory where applications call it.
请注意,您的安装会产生一个后果,CLR 将找不到您的 C++ 包装器。您必须确认 c++ 应用程序安装在使用它的任何/每个目录中,或者在安装时将库(然后需要强命名)添加到 GAC。这也意味着在开发环境中的任何一种情况下,您可能都必须将库复制到应用程序调用它的每个目录。
回答by Smoke
You can do this fairly easily.
你可以很容易地做到这一点。
- Create an .h/.cpp combo
- Enable /clr on the newly create .cpp file. (CPP -> Right click -> Properties)
- Set the search path for "additional #using directories" to point towards your C# dll.
- 创建 .h/.cpp 组合
- 在新创建的 .cpp 文件上启用 /clr。(CPP -> 右键单击 -> 属性)
- 将“附加#using 目录”的搜索路径设置为指向您的 C# dll。
Native.h
本地文件
void NativeWrapMethod();
Native.cpp
本机.cpp
#using <mscorlib.dll>
#using <MyNet.dll>
using namespace MyNetNameSpace;
void NativeWrapMethod()
{
MyNetNameSpace::MyManagedClass::Method(); // static method
}
That's the basics of using a C# lib from C++\CLI with native code. (Just reference Native.h where needed, and call the function.)
这是将 C++\CLI 中的 C# 库与本机代码一起使用的基础知识。(只需在需要的地方引用 Native.h,然后调用该函数。)
Using C# code with managed C++\CLI code is roughly the same.
使用 C# 代码和托管 C++\CLI 代码大致相同。
There is a lot of misinformation on this subject, so, hopefully this saves someone a lot of hassle. :)
关于这个主题有很多错误信息,所以,希望这可以为某人省去很多麻烦。:)
I've done this in: VS2010 - VS2012 (It probably works in VS2008 too.)
我已经完成了:VS2010 - VS2012(它可能也适用于 VS2008。)
回答by jsmith
The absolute best way I have found to do this is create a c++/cli bridge that connects the c# code to your native C++. I would not recommend using COM objects to solve your problem. You can do this with 3 different projects.
我发现最好的方法是创建一个 c++/cli 桥,将 c# 代码连接到你的本地 C++。我不建议使用 COM 对象来解决您的问题。你可以用 3 个不同的项目来做到这一点。
- First Project: C# library
- Second Project: C++/CLI bridge (this wraps the C# library)
- Third Project: Native C++ application that uses the second project
- 第一个项目:C# 库
- 第二个项目:C++/CLI 桥(这包装了 C# 库)
- 第三个项目:使用第二个项目的本机 C++ 应用程序
A good visual/tutorial on this can be found here, and the best complete walkthrough that I have found to do this can be found here! Between those two links and a little grit you should be able to hammer out creating a C++/CLI bridge that allows you to use C# code in your native C++.
一个很好的视觉/教程可以在这里找到,我发现的最好的完整演练可以在这里找到!在这两个链接和一点点勇气之间,您应该能够创建一个 C++/CLI 桥接器,允许您在本机 C++ 中使用 C# 代码。
回答by 0lli.rocks
UPDATE 2018
2018 年更新
It seems like as if the solution does not work for Visual Studio 2017 and onwards. Unfortunately I am currently not working with Visual Studio and therefore cannot update this answer by myself. But kayleeposted an updated version of my answer, thank you!
该解决方案似乎不适用于 Visual Studio 2017 及更高版本。不幸的是,我目前没有使用 Visual Studio,因此无法自己更新此答案。但是kaylee发布了我的答案的更新版本,谢谢!
UPDATE END
更新结束
If you want to use COM, here's my solution for this problem:
如果您想使用 COM,这是我针对此问题的解决方案:
C# library
C# 库
First of all you need a COM compatible library.
首先,您需要一个兼容 COM 的库。
You already got one? Perfect, you can skip this part.
You have access to the library? Make sure it's COM compatible by following the steps.
- Make sure that you checkedthe "Register for COM interop" option in the properties of your project. Properties -> Build -> Scroll down -> Register for COM interop
你已经拿到了?完美,你可以跳过这部分。
你可以去图书馆吗?按照以下步骤确保它与 COM 兼容。
- 确保您选中了项目属性中的“注册 COM 互操作”选项。属性 -> 构建 -> 向下滚动 -> 注册 COM 互操作
The following screenshots shows where you find this option.
以下屏幕截图显示了您可以在何处找到此选项。


All the interfaces and classes that should be available need to have a GUID
namespace NamespaceOfYourProject { [Guid("add a GUID here")] public interface IInterface { void Connect(); void Disconnect(); } } namespace NamespaceOfYourProject { [Guid("add a GUID here")] public class ClassYouWantToUse: IInterface { private bool connected; public void Connect() { //add code here } public void Disconnect() { //add code here } } }
所有应该可用的接口和类都需要有一个GUID
namespace NamespaceOfYourProject { [Guid("add a GUID here")] public interface IInterface { void Connect(); void Disconnect(); } } namespace NamespaceOfYourProject { [Guid("add a GUID here")] public class ClassYouWantToUse: IInterface { private bool connected; public void Connect() { //add code here } public void Disconnect() { //add code here } } }
So that's pretty much what you have to do with your C# code. Let's continue with the C++ code.
所以这几乎就是你必须用你的 C# 代码做的事情。让我们继续 C++ 代码。
C++
C++
- First of all we need to import the C# library.
- 首先,我们需要导入 C# 库。
After compiling your C# library there should be a .tlb file.
编译 C# 库后,应该有一个 .tlb 文件。
#import "path\to\the\file.tlb"
If you import this new created file to your file.cpp you can use your object as a local variable.
如果您将这个新创建的文件导入到您的 file.cpp 中,您可以将您的对象用作局部变量。
#import "path\to\the\file.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
yourClass->Connect();
CoUninitialize();
}
- Using your class as an attribute.
- 使用您的类作为属性。
You will noticed that the first step only works with a local variable. The following code shows how to use it as a attribute. Related to thisquestion.
您会注意到第一步仅适用于局部变量。以下代码显示了如何将其用作属性。与这个问题有关。
You will need the CComPtr, which is located in atlcomcli.h. Include this file in your header file.
您将需要位于 atlcomcli.h 中的 CComPtr。将此文件包含在您的头文件中。
CPlusPlusClass.h
CPlusPlusClass.h
#include <atlcomcli.h>
#import "path\to\the\file.tlb"
class CPlusPlusClass
{
public:
CPlusPlusClass(void);
~CPlusPlusClass(void);
void Connect(void);
private:
CComPtr<NamespaceOfYourProject::IInterface> yourClass;
}
CPlusPlusClass.cpp
CPlusPlusClass.cpp
CPlusPlusClass::CPlusPlusClass(void)
{
CoInitialize(NULL);
yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
}
CPlusPlusClass::~CPlusPlusClass(void)
{
CoUninitialize();
}
void CPlusPlusClass::Connect(void)
{
yourClass->Connect();
}
That's it! Have fun with your C# classes in C++ with COM.
就是这样!使用 COM 使用 C++ 中的 C# 类玩得开心。
回答by gremwell
I did a bunch of looking around and found a relatively recent article by Microsoft detailing how it can be done (there is a lot of old infomration floating around). From the article itself:
我环顾四周,发现微软最近发表的一篇文章详细介绍了如何做到这一点(有很多旧的信息漂浮在周围)。从文章本身:
The code sample uses the CLR 4 hosting APIs to host CLR in a native C++ project, load and invoke .NET assemblies
代码示例使用 CLR 4 托管 API 在本机 C++ 项目中托管 CLR,加载和调用 .NET 程序集
https://code.msdn.microsoft.com/CppHostCLR-e6581ee0
https://code.msdn.microsoft.com/CppHostCLR-e6581ee0
Basically it describes it in two steps:
基本上它分两步描述:
- Load the CLR into a process
- Load your assembly.
- 将 CLR 加载到进程中
- 加载您的程序集。
回答by kayleeFrye_onDeck
The answer from 0lli.rocksis unfortunately either outdated or incomplete. My co-worker helped me get this working, and to be frank one or two of the implementation details were not remotely obvious. This answer rectifies the gaps and should be directly copyable into Visual Studio 2017 for your own use.
不幸的是,来自 0lli.rocks的答案已经过时或不完整。我的同事帮助我完成了这项工作,坦率地说,其中一两个实施细节并不明显。这个答案弥补了差距,应该可以直接复制到 Visual Studio 2017 中供您自己使用。
Caveats: I haven't been able to get this working for C++/WinRT, just an FYI. All sorts of compile errors due to ambiguity of the IUnknowninterface. I was also having problems getting this to work for just a library implementation instead of using it in the main of the app. I tried following the instructions from 0lli.rocks for that specifically, but was never able to get it compiling.
警告:我一直无法在 C++/WinRT 上使用它,仅供参考。由于IUnknown接口不明确导致的各种编译错误。我也遇到了问题,让它仅适用于库实现而不是在应用程序的主体中使用它。我尝试按照 0lli.rocks 中的说明进行操作,但始终无法编译。
Step 01: Create your C# Library
步骤 01:创建 C# 库
Here's the one we'll be using for the demo:
这是我们将用于演示的一个:
using System;
using System.Runtime.InteropServices;
namespace MyCSharpClass
{
[ComVisible(true)] // Don't forget
[ClassInterface(ClassInterfaceType.AutoDual)] // these two lines
[Guid("485B98AF-53D4-4148-B2BD-CC3920BF0ADF")] // or this GUID
public class TheClass
{
public String GetTheThing(String arg) // Make sure this is public
{
return arg + "the thing";
}
}
}
Step 02 - Configure your C# library for COM-visibility
步骤 02 - 为 COM 可见性配置 C# 库
Sub-Step A - Register for COM interoperability
子步骤 A - 注册 COM 互操作性
Sub-Step B - Make the assembly COM-visible
子步骤 B - 使程序集 COM 可见
Step 3 - Build your Library for the .tlbfile
第 3 步 - 为.tlb文件构建库
You probably want to just do this as Releasefor AnyCPUunless you really need something more specific.
你可能只想这样做Release,AnyCPU除非你真的需要更具体的东西。
Step 4 - Copy the .tlbfile into the source location for your C++ project
第 4 步 - 将.tlb文件复制到 C++ 项目的源位置
Step 5 - Import the .tlbfile into your C++ project
第 5 步 - 将.tlb文件导入您的 C++ 项目
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
return 0;
}
Step 6 - Don't panic when Intellisense fails
第 6 步 - 当 Intellisense 失败时不要惊慌
It will still build. You're going to see even more red-lined code once we implement the actual class into the C++ project.
它仍然会建立。一旦我们将实际的类实现到 C++ 项目中,您将看到更多的红线代码。
Step 7 - Build your C++ project to generate the .tlhfile
第 7 步 - 构建您的 C++ 项目以生成.tlh文件
This file will go into your intermediate object build directory once you build the first time
第一次构建后,此文件将进入您的中间对象构建目录
Step 8 - Assess the .tlhfile for implementation instructions
步骤 8 - 评估.tlh文件以获取实施说明
This is the .tlhfile that is generated in the intermediate object folder. Don't edit it.
这是.tlh在中间对象文件夹中生成的文件。不要编辑它。
// Created by Microsoft (R) C/C++ Compiler Version 14.15.26730.0 (333f2c26).
//
// c:\users\user name\source\repos\consoleapplication6\consoleapplication6\debug\mycsharpclass.tlh
//
// C++ source equivalent of Win32 type library MyCSharpClass.tlb
// compiler-generated file created 10/26/18 at 14:04:14 - DO NOT EDIT!
//
// Cross-referenced type libraries:
//
// #import "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb"
//
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
_TheClass : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_ToString (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
virtual HRESULT __stdcall Equals (
/*[in]*/ VARIANT obj,
/*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;
virtual HRESULT __stdcall GetHashCode (
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall GetType (
/*[out,retval]*/ struct _Type * * pRetVal ) = 0;
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
};
} // namespace MyCSharpClass
#pragma pack(pop)
In that file, we see these lines for the public method we want to use:
在该文件中,我们看到要使用的公共方法的这些行:
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
That means that the imported method will expect an input-string of type BSTR, and a pointer to a BSTRfor the output string that the imported method will return on success. You can set them up like this, for example:
这意味着导入的方法将需要一个类型为 的输入字符串BSTR,以及一个指向 a 的指针,BSTR用于导入的方法将在成功时返回的输出字符串。您可以像这样设置它们,例如:
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
Before we can use the imported method, we will have to construct it. From the .tlhfile, we see these lines:
在我们可以使用导入的方法之前,我们必须构造它。从.tlh文件中,我们看到以下几行:
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
First, we need to use the namespace of the class, which is MyCSharpClass
首先,我们需要使用类的命名空间,也就是 MyCSharpClass
Next, we need to determine the the smart pointer from the namespace, which is _TheClass+ Ptr; this step is not remotely obvious, as it's nowhere in the .tlhfile.
接下来,我们需要从命名空间中确定智能指针,即_TheClass+ Ptr;这一步不是很明显,因为它在.tlh文件中没有任何位置。
Last, we need to provide the correct construction parameter for the class, which is __uuidof(MyCSharpClass::TheClass)
最后,我们需要为类提供正确的构造参数,即 __uuidof(MyCSharpClass::TheClass)
Ending up with,
结束于,
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
Step 9 - Initialize COM and test the imported library
步骤 9 - 初始化 COM 并测试导入的库
You can do that with CoInitialize(0)or whatever your specific COM initializer happens to be.
您可以使用CoInitialize(0)或任何您的特定 COM 初始值设定项来做到这一点。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
CoInitialize(0); // Init COM
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
HRESULT hResult = obj->GetTheThing(thing_to_send, &returned_thing);
if (hResult == S_OK) {
std::wcout << returned_thing << std::endl;
return 0;
}
return 1;
}
Once again, don't panic when Intellisense freaks out. You're in Black Magic, Voodoo, & Thar Be Dragons territory, so press onward!
再一次,当 Intellisense 出现问题时不要惊慌。你在 Black Magic、Voodoo 和 Thar Be Dragons 领域,所以继续前进!

