2009-07-22 13 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; 
} 
相關問題