一尘不染

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

c#

背景: 作为较大任务的一部分,我需要使非托管C 和C代码可以访问C#库。为了自己回答这个问题,我过去几天/几周一直在学习C / CLI。

从不受管理的C
++和C中使用C#dll似乎有许多不同的方法。简要地讲,一些答案似乎是:使用Interlope服务,使用.com。然后使用PInvoke(似乎仅从C#到C
)并在C / CLR中使用IJW(这似乎是Interlope服务)。我认为最好建立一个可能是CLR包装器的库,该库使用IJW代表本机C
++和C代码调用C#dll。

细节: 我需要将字符串以及int的值从c ++代码传递到C#dll,然后返回void。

相关性: 许多公司有很多借口来混合和匹配C
,C和C#。性能:非托管代码通常更快,接口:托管人员也告诉我们,托管接口通常更易于维护,部署,并且通常更易于使用。旧版代码也迫使我们。在那里(就像我们爬过的山一样)。虽然有很多关于如何从C#调用C
库的示例。通过Googling很难找到如何从C ++代码调用C#库的示例,特别是如果您想查看更新的4.0+代码。

软体: C#,C / CLR,C ,C,Visual Studio 2010和.NET 4.0

问题详细信息: 可以分为多个部分:

  1. 使用com对象有优势吗?还是PInvoke?还是其他方法?(尽管我确实在Google Land上找到了有关该主题的更多信息,但我觉得这里的学习曲线也一样陡峭。IJW似乎答应了我想要做的事情。我应该放弃寻找IJW解决方案并专注于此吗?)(优点/缺点?)

  2. 我是否能想到有解决方案,我编写了一个在C ++ / CLR中利用IJW的包装器?在哪里可以找到有关此主题的更多信息,不要说我对Google的了解不够//或不告诉我您在哪里看到MSDN的情况。(我认为我更喜欢使用此选项,以便编写清晰简单的代码。)

  3. 问题范围的缩小:我认为我真正的问题和需求是回答以下较小的问题:如何设置C / CLR库,非托管C 文件可以在Visual Studio中使用。我认为,如果我可以简单地在非托管C 代码中实例化托管C 类,那么我也许可以解决其余的问题(接口和包装等)。我希望我的主要愚蠢在于尝试在Visual Studio中设置引用/#includes等,显然我可能还会有其他误解。也许对这整件事的答案可能只是指向帮助我的教程或说明的链接。

研究:
我已经Google和Bing一遍又一遍,并取得了一些成功。我发现许多链接向您展示了如何使用C#代码中的非托管库。我将承认,有一些链接显示了如何使用com对象进行操作。针对VS
2010的结果并不多。

参考资料:
我已经阅读了很多篇文章。我试图通过最相关的工作。有些人似乎非常接近答案,但是我似乎无法让他们工作。我怀疑我所缺少的东西实在是太小了,例如滥用关键字ref,缺少#include或using语句,或者滥用命名空间,或者实际上并未正确使用IJW功能或缺少VS需要正确处理编译等。所以您想知道,为什么不包括代码?好吧,我觉得自己不在一个我理解并期望自己能工作的代码的地方。我想去一个我了解的地方,当我到达那里时,也许我需要帮助修复它。我将随机包含两个链接,但不允许在当前的生命值级别上全部显示它们。

http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-
and-Unmanaged-Cod

这会从C 到Visual Basic,再通过C
CLR双向调用托管和非托管代码中的代码,当然,我对C#感兴趣。http :
//www.codeproject.com/Articles/9903/Calling来自非托管代码和服务的托管代码


阅读 362

收藏
2020-05-19

共1个答案

一尘不染

我发现至少可以回答我自己的问题的东西。以下两个链接具有Microsoft的wmv文件,这些文件演示了如何在非托管C ++中使用C#类。

第一个使用COM对象并重新填充:http :
//msdn.microsoft.com/zh-cn/vstudio/bb892741。

第二部分使用C ++ / CLI的功能包装C#类:http : //msdn.microsoft.com/zh-
cn/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;
}

我的部分问题是:哪个更好?根据我在许多努力研究中所读到的内容,得出的答案是,COM对象被认为更易于使用,而使用包装器可以实现更好的控制。在某些情况下,使用包装器可以(但不总是)减小包装的大小,因为COM对象自动具有标准的尺寸占用空间,并且包装器的大小仅为所需的大小。

重击(如我上面所使用的)是指在COM对象的情况下在C#和C 之间以及在使用C / CLI进行编码的情况下在C / CLI和本机C
之间使用的时空和资源。包装纸。因此,我的回答的另一部分应包括警告,即超出绝对必要超过跨thunk边界是错误的做法,不建议在循环内访问thunk边界,并且可能会错误地设置包装器,从而使thunk翻倍(跨越边界两次,只需要一个重击),而代码对于像我这样的新手来说似乎是不正确的。

关于wmv的两个注释。首先:某些素材可以在两者中重复使用,请勿上当。乍一看,它们看起来是相同的,但它们确实涵盖了不同的主题。其次,有一些额外的功能,例如编组,现在已成为CLI的一部分,而wmv并未涵盖。

编辑:

请注意,这将对您的安装造成影响,CLR将找不到您的c 包装器。您将必须确认c
应用程序安装在使用它的任何/每个目录中,或者在安装时将库(然后需要强命名)添加到GAC。这也意味着,无论哪种情况,在开发环境中,您都可能必须将库复制到应用程序调用它的每个目录中。

2020-05-19