背景: 作为较大任务的一部分,我需要使非托管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
问题详细信息: 可以分为多个部分:
使用com对象有优势吗?还是PInvoke?还是其他方法?(尽管我确实在Google Land上找到了有关该主题的更多信息,但我觉得这里的学习曲线也一样陡峭。IJW似乎答应了我想要做的事情。我应该放弃寻找IJW解决方案并专注于此吗?)(优点/缺点?)
我是否能想到有解决方案,我编写了一个在C ++ / CLR中利用IJW的包装器?在哪里可以找到有关此主题的更多信息,不要说我对Google的了解不够//或不告诉我您在哪里看到MSDN的情况。(我认为我更喜欢使用此选项,以便编写清晰简单的代码。)
问题范围的缩小:我认为我真正的问题和需求是回答以下较小的问题:如何设置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来自非托管代码和服务的托管代码
我发现至少可以回答我自己的问题的东西。以下两个链接具有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。这也意味着,无论哪种情况,在开发环境中,您都可能必须将库复制到应用程序调用它的每个目录中。