1.前言
本篇博文并非详细的C++/CLI教程,仅是博主就学习和实践总结的部分知识点记录。
第一次接触C++/CLI是2017年了,用C++编写底层库,C++/CLI编写wrapper层,在C#项目中进行调用,开发应用。
2.内容
- C++/CLI是一种混合编程,在.NET框架下混合使用.NET和C++语言进行编程,既可以使用native C++,又可以使用managed C++(托管C++),还可以使用.NET。
- 这就说明在C++/CLI中可以用native C++编写代码,可以调用C++库,可以编写托管代码和类,可以使用.NET语言,一种典型的应用是作为Wrapper封装层来封装C++库的类和接口、做C++/C#类型的转换,然后在C#应用程序中调用,开发便捷易用的应用程序。
- 关于native C++,托管C++,CLI,CLR等概念参考托管C++、C++/CLI、CLR-腾讯云开发者社区-腾讯云
- STL/CLR Library:The STL/CLR Library provides an interface similar to the C++ Standard Library containers for use with C++ and the .NET Framework common language runtime (CLR). STL/CLR is completely separate from the Microsoft implementation of the C++ Standard Library. STL/CLR is maintained for legacy support but is not kept up-to-date with the C++ standard. We strongly recommend using the native C++ Standard Library containers instead of STL/CLR whenever possible.
在C++/CLI中可以使用和C++标准库容器非常接近的容器,享受C++标准库容器的强大能力,当然不建议这种方式使用容器,建议直接使用native C++标准库;
STL/CLR Library Reference | Microsoft LearnLearn more about: STL/CLR Library Referencehttps://learn.microsoft.com/en-us/cpp/dotnet/stl-clr-library-reference?view=msvc-170 - 在涉及C++/C#参数转换时,可直接在C++/CLI项目中编写转换函数进行【C++到C#】或【C#到C++】的参数转换,注意基本类型(int/double/float等)不需要转换,而string、容器等需要转换;
- string转换:
//返回的值需要释放内存 wchar_t *ManagedStr2UnmanagedUniStr(String^ str) { IntPtr p = Marshal::StringToHGlobalUni(str); if (p == IntPtr::Zero) return(NULL); const wchar_t *pTemp = static_cast<const wchar_t *>(p.ToPointer()); if (pTemp == NULL) return NULL; size_t len = wcslen(pTemp) + 1; wchar_t *pOut = new wchar_t[len]; wcscpy_s(pOut, len, pTemp); Marshal::FreeHGlobal(p); return(pOut); } //非托管字符串转托管的Unicode字符串 String ^ UnmanagedStr2ManagedUniStr(wchar_t *str) { return Marshal::PtrToStringUni((IntPtr)str); }
-
可编写转换函数进行C++和C#间容器类型的转换,以便于在C#中调用带有标准C++ STL容器类型参数的C++接口;或将C#传递来的容器参数转换为C++ STL容器参数,以便调用底层C++库接口实现,
void Convert(List<LineWrapper^>^ lines, list<Line>& cLines) { if (!lines) return; for each (LineWrapper ^ line in lines) { cLines.push_back(*line->GetImplPtr()); } }
-
可直接在C++/CLI中编写wrapper类以便于在C#项目中使用以存在的功能强大的C++类,
public ref class LineWrapper { public: LineWrapper() { mImpl = new Line(); } LineWrapper(const Line* impl) { mImpl = new Line(*impl); } ~LineWrapper() { delete mImpl; } property Vector3Wrapperf^ Pt0 { Vector3Wrapperf^ get() { Vector3f pt = mImpl->pt0; return gcnew Vector3Wrapperf(pt.X, pt.Y, pt.Z); }; void set(Vector3Wrapperf^ pt) { mImpl->pt0.X = pt->X; mImpl->pt0.Y = pt->Y; mImpl->pt0.Z = pt->Z; }; } property Vector3Wrapperf^ Pt1 { Vector3Wrapperf^ get() { Vector3f pt = mImpl->pt1; return gcnew Vector3Wrapperf(pt.X, pt.Y, pt.Z); }; void set(Vector3Wrapperf^ pt) { mImpl->pt1.X = pt->X; mImpl->pt1.Y = pt->Y; mImpl->pt1.Z = pt->Z; }; } Line* GetImplPtr() { return mImpl; } private: Line* mImpl; };
-
对于native C++库中的模板类,在C++/CLI项目中需要继承方式实例化模板类,从而在C#项目中使用实例化的类,
template<typename T> public ref class Vector3Wrapper { public: static Vector3Wrapper^ BasicX = gcnew Vector3Wrapper; static Vector3Wrapper^ BasicY = gcnew Vector3Wrapper; static Vector3Wrapper^ BasicZ = gcnew Vector3Wrapper; static Vector3Wrapper^ Zero = gcnew Vector3Wrapper; public: property T X { void set(T x) { mImpl->X = x; } T get() { return mImpl->X; } } property T Y { void set(T y) { mImpl->Y = y; } T get() { return mImpl->Y; } } property T Z { void set(T z) { mImpl->Z = z; } T get() { return mImpl->Z; } } Vector3Wrapper() { mImpl = new Vector3<T>(); } Vector3Wrapper(const Vector3<T>* impl) { mImpl = new Vector3<T>(*impl); } Vector3Wrapper(T x, T y, T z) { mImpl = new Vector3<T>(x,y,z); } template<typename ST> Vector3Wrapper(Vector3Wrapper<ST>% other) { mImpl = new Vector3<T>(*other.mImpl); }; virtual ~Vector3Wrapper() { delete mImpl; }; public: void Normalize() { mImpl->Normalize(); }; // define other functions here Vector3<T>* GetImplPtr() { return mImpl; }; private: Vector3<T>* mImpl; }; public ref class Vector3Wrapperf : public Vector3Wrapper<float> { public: Vector3Wrapperf(float x, float y, float z) : Vector3Wrapper(x, y, z) {} Vector3Wrapperf(): Vector3Wrapper(){ } Vector3Wrapperf(const Vector3<float>* impl): Vector3Wrapper(impl){ } ~Vector3Wrapperf() { }; //define other functions here };
-
在C++/CLI项目中同样需要提取公共函数或类,便于使用,
3.参考文章
1、从C++到C++/CLI
https://www.cnblogs.com/feisky/archive/2009/11/22/1607999.htmlhttps://www.cnblogs.com/feisky/archive/2009/11/22/1607999.html2、相关博文:
C++/CLI 总结_array^ arr = gcnew-CSDN博客文章浏览阅读1.2k次,点赞5次,收藏14次。在Windows上,除非我们必须得用C++来写界面,否则我会选择避免,避免学习和使用MFC。替代的方案是用C#来做界面,然后用C++/CLI来连接C#和Native C++。那么问题来了,C++/CLI是何方神圣? 百度上对于C++/CLI是这么说的——“C++/CLI是静态C++对象模型到CLI的动态组件对象编程模型的捆绑。简而言之就是如何用C++在·NET中编程,而不是C#或Visual B..._array^ arr = gcnewhttps://blog.csdn.net/weixin_29130507/article/details/802673293、微软官方说明文档:
Generic Classes (C++/CLI) | Microsoft LearnLearn more about: Generic Classes (C++/CLI)https://learn.microsoft.com/en-us/cpp/extensions/generic-classes-cpp-cli?view=msvc-170.NET programming with C++/CLI | Microsoft LearnLearn how to use C++/CLI to create .NET apps and components in Visual Studio.https://learn.microsoft.com/en-us/cpp/dotnet/dotnet-programming-with-cpp-cli-visual-cpp?view=msvc-170Generic Functions (C++/CLI) | Microsoft LearnLearn more about: Generic functions (C++/CLI)https://learn.microsoft.com/en-us/cpp/extensions/generic-functions-cpp-cli?view=msvc-170
4、【原】C++与C#对常用数据结构封装的对比(STL vs System.Collections.Generic)https://www.cnblogs.com/cocoaleaves/archive/2009/05/30/1492269.html
5、Convert all values from dictionary into list in C++/CLIc++ cli - Convert all values from dictionary into list in C++/CLI - Stack Overflow
6、c++ - Cpp/Cli Convert std::map to .net dictionary - Stack Overflow
7、C++/CLI封装原生C++库供.NET项目调用-CSDN博客
8、Use C++ CLI template class in C#
.net - Use C++ CLI template class in C# - Stack Overflow
9、C++/CLI: functions inherited from template class are not visible in C#
.net - C++/CLI: functions inherited from template class are not visible in C# - Stack Overflow