2009-07-22 14 views
6

我有一个使用普通旧C++编写的代码库(无.NET /托管代码),并且正在移植使用此应用程序的应用程序代码到C#。我面临两种选择:移植(非托管)C++到C#与在C#应用程序中使用C++作为DLL

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

我对C#相对来说比较陌生,对于在C#应用程序中使用非托管代码库的影响还是很不熟悉的(或者甚至有)。代码本身大小适中,它可能只需要几天时间就可以用C#重写,但我的想法是,将代码保留为它可以让我在其他应用程序中使用它(并在UNIX上编译它等)。

做这个决定时我应该知道什么样的事情?在C#应用程序中使用DLL有什么主要缺点或陷阱吗?

+1

单声道还可以让你“端口”/在* nix上运行。 – Tim 2009-07-22 17:54:39

回答

6

我会制作一个使用C++/CLI向C#公开库的包装库。这可以让你的库保持不变,只需将它包装在.NET中使用,就可以提供这两种选择中最好的选择。

+1

击败我20秒。但是*我*去了并找到了一个链接。 :) – Randolpho 2009-07-22 17:55:03

+1

使用C++/CLI包装器是*要走的路。 P/Invoke会给你DLL加载和版本问题。使用非托管库将清除管理的非托管编译行。但是要小心暴露STL类。您可能会发现,您的低级代码需要使用非托管STL,最终会使用托管版本以及很多托管/非托管转换。 – plinth 2009-07-22 18:17:49

2

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

+0

仅供参考:DLL不是静态链接的。动态链接库。 – Amy 2009-07-22 18:12:10

0

不需要在C++/CLI中编写包装器。您可以直接使用平台调用从C#:

​​

编辑:如果你这样做使用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; 
} 
相关问题