移植(非托管)C++;使用C&x2B+;作为C#应用程序中的DLL 我有一个用普通的老C++编写的代码库(NO.NET/托管代码),我正在移植使用这个代码的应用程序C。我面临两个选择: 重写C++中的C++代码,实现相同的功能;李> 编译C++作为DLL,并将其作为C语言应用程序中的库。

移植(非托管)C++;使用C&x2B+;作为C#应用程序中的DLL 我有一个用普通的老C++编写的代码库(NO.NET/托管代码),我正在移植使用这个代码的应用程序C。我面临两个选择: 重写C++中的C++代码,实现相同的功能;李> 编译C++作为DLL,并将其作为C语言应用程序中的库。,c#,c++,dll,C#,C++,Dll,我对C#比较陌生,对在C#应用程序中使用非托管代码库(或者如果有的话)的含义非常不熟悉。代码本身大小适中;用C#重写可能只需要几天时间,但我的想法是,让代码保持原样也可以让我在其他应用程序中使用它(以及在UNIX上编译它,等等) 在做这个决定时,我应该注意哪些事情?在C#应用程序中使用DLL有什么主要缺点或缺陷吗?我会使用C++/CLI制作一个包装库,将库公开给C#。这会让你的库保持不变,只需将它打包为.NET提供最佳的两种选项。 < p>我发现一个有用的东西是深入研究处理非托管C++库时的情况

我对C#比较陌生,对在C#应用程序中使用非托管代码库(或者如果有的话)的含义非常不熟悉。代码本身大小适中;用C#重写可能只需要几天时间,但我的想法是,让代码保持原样也可以让我在其他应用程序中使用它(以及在UNIX上编译它,等等)


在做这个决定时,我应该注意哪些事情?在C#应用程序中使用DLL有什么主要缺点或缺陷吗?

我会使用C++/CLI制作一个包装库,将库公开给C#。这会让你的库保持不变,只需将它打包为.NET提供最佳的两种选项。

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

无需在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;
}
private static int SRCCOPY=0x00CC0020;
专用静态uint BI_RGB=0;
专用静态uint DIB_RGB_颜色=0;
[DllImport(“gdi32.dll”)]
私有静态外部bool DeleteObject(IntPtr-hObject);
[StructLayout(LayoutKind.Sequential)]
私有结构BITMAPINFO
{
公用事业单位规模化;
公共宽度;
公共高度;
公共短双翼飞机;
公共短比特计数;
公共单位双重压缩;
公共单位比西泽迈格;
公共int双xPelsPermeter;
公共int双向渗透计;
使用公共单元;
公共部门的重要性;
[Marshallas(UnmanagedType.ByValArray,SizeConst=256)]
公共单位[]cols;
}
公共静态位图下采样(位图输入,int bpp)
{
位图retval=null;
//我们将从C#调用此GDI功能。我们的计划:
//(1)将位图转换为GDI hbitmap(即复制非托管->托管)
//(2)创建GDI单色hbitmap
//(3)使用GDI“BitBlt”功能将hbitmap复制为单色(如上所述)
//(4)将monochrone hbitmap转换为位图(即复制非托管->托管)
IntPtr inputHandle=input.GetHbitmap();
//
//步骤(2):创建单色位图。
//
BITMAPINFO bmi=新的BITMAPINFO();
bmi.biSize=40;//BITMAPHEADERINFO结构的大小
bmi.biWidth=输入.Width;
bmi.biHeight=输入高度;
bmi.biPlanes=1;
bmi.biBitCount=(短)bpp;//1bpp或8bpp
bmi.biCompression=biu RGB;
bmi.biSizeImage=(uint)((input.Width+7)和0xfffff8)*input.Height/8);
bmi.biXPelsPerMeter=0;//不是很重要
bmi.biYPelsPerMeter=0;//不是很重要
//
//创建调色板。
//

uint numColors=(uint)1 Mono还允许您“端口”/在*nix上运行。比我快了20秒。但我找到了一个链接。:)使用C++/CLI包装器是最好的选择。P/Invoke会给您带来dll加载和版本控制问题。使用非托管库会让托管非托管编译的思路更加清晰。不过,请注意不要公开STL类。您可能会发现,您的低级代码使用非托管STL最终将使用托管版本,其中包含大量托管/非托管转换。仅供参考:DLL不是静态链接的。动态链接库。@yodaj007:我相信他建议将原始库静态链接到C++/CLI程序集,这是正确的。@yodaj007:@Reed Copsey说得比我更好。但我会告诉他till try:基于原始问题中提到的内容,原始库似乎是一个静态链接库。这意味着如果该库由C++/CLI项目使用,它将被编译到(并包含在中)C++和CLI。DLL.This看起来相当简单。比如STL容器和复杂自定义类型的编组,你不需要处理LoadLibrary或函数指针——C++ + CLI使复杂的C++库简单化。P/Unjk工作很好,只要库提供了一个C API,但是没有(容易)。用P/Unjk来封装C++类实例的方法。C对于C++类来说很好,但是C++类的效果不太好。但是如果你传递更复杂的结构,很难找出P/UncKE签名。如果不能找到可行的方法,则在托管的C++/CLI DLL中打包将简化被传递的结构。所有的结构。