将C ++移植(非托管)到C#与在C#应用程序中使用C ++作为DLL

我有一个用简单的旧C ++(没有.NET /托管代码)编写的代码库,我正在将使用此代码的应用程序移植到C#。 我面临两个选择:

  1. 用C#重写C ++代码以实现相同的function;
  2. 将C ++编译为DLL并将其用作C#应用程序中的库。

我对C#比较陌生,并且对在C#应用程序中使用非托管代码库(或者甚至有任何代码库)的含义非常不熟悉。 代码本身大小适中; 在C#中重写可能只需要几天时间,但我的想法是将代码保留为允许我在其他应用程序中使用它(并在UNIX上编译它等)。

在做出这个决定时,我应该注意哪些事情? 在C#应用程序中使用DLL有任何重大缺点或缺陷吗?

我将使用C ++ / CLI创建一个包装库,以将库公开给C#。 这可以保持您的库不变,只需将其包装起来以便从.NET中使用,从而提供两种选择中的最佳选择。

我发现有用的一件事是在处理非托管C ++库时深入研究C ++ / CLI 。 使用C ++ / CLI创建托管包装器,并从C#代码中调用它。 托管包装器可以在其DLL中包含库(我假设它是静态链接的),并且您的C#代码只需要项目引用。

没有必要在C ++ / CLI中编写包装器。 您可以直接使用C#中的Platform Invoke:

http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx

编辑:如果您使用C ++ / CLI执行此操作,则需要执行LoadLibrary调用并创建函数指针。 这在C#中要容易得多。 这是来自上面链接的MSDN教程,但是我自己添加了评论:

class PlatformInvokeTest { [DllImport("msvcrt.dll")] // Specify the DLL we're importing from public static extern int puts(string c); // This matches the signature of the DLL function. The CLR automatically marshals C++ types to C# types. [DllImport("msvcrt.dll")] internal static extern int _flushall(); public static void Main() { puts("Test"); _flushall(); } } 

编辑:复杂类型也可以编组,但有必要定义结构。 这个例子取自我自己调用GDI +的代码。 我已经剪了一下。

 private static int SRCCOPY = 0x00CC0020; private static uint BI_RGB = 0; private static uint DIB_RGB_COLORS = 0; [DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); [StructLayout(LayoutKind.Sequential)] private struct BITMAPINFO { public uint biSize; public int biWidth; public int biHeight; public short biPlanes; public short biBitCount; public uint biCompression; public uint biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public uint biClrUsed; public uint biClrImportant; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public uint[] cols; } public static Bitmap Downsample(Bitmap input, int bpp) { Bitmap retval = null; // We will call into this GDI functionality from C#. Our plan: // (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed) // (2) Create a GDI monochrome hbitmap // (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above) // (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed) IntPtr inputHandle = input.GetHbitmap(); // // Step (2): create the monochrome bitmap. // BITMAPINFO bmi = new BITMAPINFO(); bmi.biSize = 40; // the size of the BITMAPHEADERINFO struct bmi.biWidth = input.Width; bmi.biHeight = input.Height; bmi.biPlanes = 1; bmi.biBitCount = (short)bpp; // 1bpp or 8bpp bmi.biCompression = BI_RGB; bmi.biSizeImage = (uint)(((input.Width + 7) & 0xFFFFFFF8) * input.Height / 8); bmi.biXPelsPerMeter = 0; // not really important bmi.biYPelsPerMeter = 0; // not really important // // Create the color palette. // uint numColors = (uint)1 << bpp; // 2 colors for 1bpp; 256 colors for 8bpp bmi.biClrUsed = numColors; bmi.biClrImportant = numColors; bmi.cols = new uint[256]; if (bpp == 1) { bmi.cols[0] = MAKERGB(0, 0, 0); bmi.cols[1] = MAKERGB(255, 255, 255); } else { for (int i = 0; i < numColors; i++) { bmi.cols[i] = MAKERGB(i, i, i); } } // // Now create the indexed bitmap // IntPtr bits0; IntPtr indexedBitmapHandle = CreateDIBSection(IntPtr.Zero, ref bmi, DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0); IntPtr sourceDC = GetDC(IntPtr.Zero); IntPtr hdc = CreateCompatibleDC(sourceDC); IntPtr hdc0 = CreateCompatibleDC(sourceDC); SelectObject(hdc, inputHandle); SelectObject(hdc0, indexedBitmapHandle); BitBlt(hdc0, 0, 0, input.Width, input.Height, hdc, 0, 0, SRCCOPY); retval = Bitmap.FromHbitmap(indexedBitmapHandle); // // Dispose of the crud // DeleteDC(hdc); DeleteDC(hdc0); ReleaseDC(IntPtr.Zero, sourceDC); DeleteObject(inputHandle); DeleteObject(indexedBitmapHandle); return retval; }