简体   繁体   English

如何从本机 C++ 调用 C# 库(使用 C++\\CLI 和 IJW)

[英]How to call a C# library from Native C++ (using C++\CLI and IJW)

Background: As part of a larger assignment I need to make a C# library accessible to unmanaged C++ and C code.背景:作为更大任务的一部分,我需要使非托管 C++ 和 C 代码可以访问 C# 库。 In an attempt to answer this question myself I have been learning C++/CLI the past few days/ weeks.为了自己回答这个问题,过去几天/几周我一直在学习 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.似乎有许多不同的方法可以使用来自非托管 C++ 和 C 的 C# dll 来实现。一些简短的答案似乎是:使用 Interlope 服务、使用 .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).和 regasm,使用 PInvoke(似乎仅从 C# 转到 C++),并在 C++/CLR(似乎是 Interlope 服务)中使用 IJW。 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.我认为最好设置一个库,它可能是一个 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#.相关性:许多公司有很多借口混合搭配 C++、C 和 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.虽然如何从 C# 调用 C++ 库的示例很多。 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# 库的示例,特别是如果您想查看更新的 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 多部分问题:

  1. Is there an advantage to using com objects?使用 com 对象有优势吗? Or the PInvoke?还是 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?) (我觉得这里的学习曲线同样陡峭,即使我确实在 Google Land 中找到了有关该主题的更多信息。IJW 似乎承诺了我想要它做的事情。我应该放弃寻找 IJW 解决方案吗?而是专注于此?)(优势/劣势?)

  2. Am I correct in imagining that there is a solution where I write a wrapper that that utilizes IJW in the C++/CLR?我是否正确地想象有一个解决方案,我可以编写一个在 C++/CLR 中使用 IJW 的包装器? 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.我在哪里可以找到关于这个主题的更多信息,不要说我没有足够的谷歌/或者在没有告诉我你在哪里看到它的情况下查看 MSDN。 (I think I prefer this option, in the effort to write clear and simple code.) (我想我更喜欢这个选项,努力编写清晰简单的代码。)

  3. 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.缩小问题范围:我觉得我真正的问题和需要是回答以下较小的问题:如何设置非托管 C++ 文件可以在 Visual Studio 中使用的 C++/CLR 库。 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.).我认为,如果我可以简单地在非托管 C++ 代码中实例化一个托管 C++ 类,那么我也许可以解决其余的问题(接口和包装等)。 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.我希望我的主要愚蠢之处在于尝试在 Visual Studio 中设置引用/#includes 等,但显然我可能会有其他误解。 Perhaps the answer to this whole thing could be just a link to a tutorial or instructions that help me with this.也许这整个事情的答案可能只是一个指向帮助我解决这个问题的教程或说明的链接。

Research: I have Googled and Binged over and over with some success.研究:我一次又一次地在谷歌上搜索和 Bing 并取得了一些成功。 I have found many links that show you how to use an unmanaged library from C# code.我找到了许多向您展示如何使用 C# 代码中的非托管库的链接。 And I will admit that there have been some links that show how to do it using com objects.我承认已经有一些链接展示了如何使用 com 对象来做到这一点。 Not many results were targeted at VS 2010.针对 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?我怀疑我缺少的东西非常小,例如滥用关键字 ref,或缺少 #include 或 using 语句,或滥用名称空间,或实际上未正确使用 IJW 功能,或缺少 VS 的设置需要正确处理编译等。所以你想知道,为什么不包括代码? 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.我将随机包含两个链接,但我不允许在当前的 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

You can do this fairly easily.你可以很容易地做到这一点。

  1. Create an .h/.cpp combo创建 .h/.cpp 组合
  2. Enable /clr on the newly create .cpp file.在新创建的 .cpp 文件上启用 /clr。 (CPP -> Right click -> Properties) (CPP -> 右键单击​​ -> 属性)
  3. Set the search path for "additional #using directories" to point towards your C# dll.将“附加#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.这是将 C++\\CLI 中的 C# 库与本机代码一起使用的基础知识。 (Just reference Native.h where needed, and call the function.) (只需在需要的地方引用 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。)

UPDATE 2018 2018 年更新

It seems like as if the solution does not work for Visual Studio 2017 and onwards.该解决方案似乎不适用于 Visual Studio 2017 及更高版本。 Unfortunately I am currently not working with Visual Studio and therefore cannot update this answer by myself.不幸的是,我目前没有使用 Visual Studio,因此无法自己更新此答案。 But kaylee posted an updated version of my answer , thank you!但是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.按照以下步骤确保它与 COM 兼容。

    1. Make sure that you checked the "Register for COM interop" option in the properties of your project.确保您选中了项目属性中的“注册 COM 互操作”选项。 Properties -> Build -> Scroll down -> Register for COM interop属性 -> 构建 -> 向下滚动 -> 注册 COM 互操作

The following screenshots shows where you find this option.以下屏幕截图显示了您可以在何处找到此选项。

屏幕截图项目属性构建

  1. All the interfaces and classes that should be available need to have a GUID所有应该可用的接口和类都需要有一个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.所以这几乎就是你必须用你的 C# 代码做的事情。 Let's continue with the C++ code.让我们继续 C++ 代码。

C++ C++

  1. 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();
}
  1. 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 this question.这个问题有关。

You will need the CComPtr, which is located in atlcomcli.h.您将需要位于 atlcomcli.h 中的 CComPtr。 Include this file in your header file.将此文件包含在您的头文件中。

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.在 C++ 和 COM 中使用 C# 类玩得开心。

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++.我发现最好的方法是创建一个 c++/cli 桥,将 c# 代码连接到你的本地 C++。 You can do this with 3 different projects.你可以用 3 个不同的项目来做到这一点。

  • First Project: C# library第一个项目:C# 库
  • Second Project: C++/CLI bridge (this wraps the C# library)第二个项目:C++/CLI 桥(这包装了 C# 库)
  • Third Project: Native C++ application that uses the second project第三个项目:使用第二个项目的本机 C++ 应用程序

I recently created a simple GitHub Tutorial for how to do this here .我最近在此处创建了一个简单的 GitHub 教程来说明如何执行此操作。 Reading through that code with a little grit and 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# 代码。

As a bonus I added how to wrap a C# event down to a function pointer in C++ that you can subscribe to.作为奖励,我添加了如何将 C# 事件包装到 C++ 中您可以订阅的函数指针。

The answer from 0lli.rocks is unfortunately either outdated or incomplete.不幸的是,来自 0lli.rocks答案已经过时或不完整。 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.这个答案弥补了差距,应该可以直接复制到 Visual Studio 2017 中供您自己使用。

Caveats : I haven't been able to get this working for C++/WinRT, just an FYI.警告:我一直无法在 C++/WinRT 上使用它,仅供参考。 All sorts of compile errors due to ambiguity of the IUnknown interface.由于IUnknown接口的歧义导致的各种编译错误。 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.我尝试按照 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 .tlb file第 3 步 - 为.tlb文件构建库


You probably want to just do this as Release for AnyCPU unless you really need something more specific.除非您确实需要更具体的东西,否则您可能只想将其作为AnyCPU ReleaseAnyCPU

Step 4 - Copy the .tlb file into the source location for your C++ project步骤 4 - 将.tlb文件复制到 C++ 项目的源位置


在此处输入图片说明

Step 5 - Import the .tlb file 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 .tlh file步骤 7 - 构建 C++ 项目以生成.tlh文件


This file will go into your intermediate object build directory once you build the first time第一次构建后,此文件将进入您的中间对象构建目录

在此处输入图片说明

Step 8 - Assess the .tlh file for implementation instructions步骤 8 - 评估.tlh文件以获取实施说明


This is the .tlh file that is generated in the intermediate object folder.这是在中间对象文件夹中生成的.tlh文件。 Don't edit it.不要编辑它。

// 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 BSTR for the output string that the imported method will return on success.这意味着,所导入方法将期望类型的输入字符串BSTR ,和一个指向BSTR用于输出串导入的方法将返回成功。 You can set them up like this, for example:您可以像这样设置它们,例如:

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 .tlh file, we see these lines:.tlh文件中,我们看到以下.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 ;接下来,我们需要从命名空间中确定智能指针,即_TheClass + Ptr this step is not remotely obvious, as it's nowhere in the .tlh file.这一步不是很明显,因为它在.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.再一次,当 Intellisense 出现问题时不要惊慌。 You're in Black Magic, Voodoo, & Thar Be Dragons territory, so press onward!你在 Black Magic、Voodoo 和 Thar Be Dragons 领域,所以继续前进!

在此处输入图片说明

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 .第二个使用 C++/CLI 的功能来包装 C# 类: http : //msdn.microsoft.com/en-us/vstudio/bb892742 I have been able to instantiate ac# class from managed code and retrieve a string as in the video.我已经能够从托管代码实例化 ac# 类并检索视频中的字符串。 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 ac# class.它非常有帮助,但它只回答了我问题的 2/3,因为我想将一个带有字符串周长的类实例化到 ac# 类中。 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.当然,我还添加了一个修改过的 {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.从我在许多研究中读到的答案是,COM 对象被认为更易于使用,而使用包装器可以实现更好的控制。 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.在某些情况下,使用包装器可以(但并非总是)减小 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. thunk(正如我上面使用的)是指在 COM 对象的情况下 C# 和 C++ 之间使用的空间时间和资源,以及在使用 C++/CLI 编码的情况下 C++/CLI 和本机 C++ 之间使用的空间时间和资源包装纸。 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 边界超过绝对必要是不好的做法,不建议访问循环内的 thunk 边界,并且可能会错误地设置包装器以便它加倍 thunk (跨越边界两次,只需要一个 thunk )没有代码对于像我这样的新手来说似乎是不正确的。

Two notes about the wmv's.关于 wmv 的两个注意事项。 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.其次,还有一些额外的功能,例如编组,现在是 CLI 的一部分,但 wmv 中没有涵盖这些功能。

Edit:编辑:

Note there is a consequence for your installs, your c++ wrapper will not be found by the CLR.请注意,您的安装会产生一个后果,CLR 将找不到您的 C++ 包装器。 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.您必须确认 c++ 应用程序安装在使用它的任何/每个目录中,或者在安装时将库(然后需要强命名)添加到 GAC。 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.这也意味着在开发环境中的任何一种情况下,您可能都必须将库复制到应用程序调用它的每个目录。

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:基本上它分两步描述:

  1. Load the CLR into a process将 CLR 加载到进程中
  2. Load your assembly.加载您的程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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