Портирование (неуправляемого) C++ к C# по сравнению с использованием C++ как DLL в приложении C#

Foreach использует Утку, Вводящую

Перефразирование или бесстыдно кража от блог Krzysztof Cwalinas на этом. Более интересные мелочи, чем что-нибудь.

Для Вашего объекта поддерживать foreach, Вы не делаете , должны реализовать IEnumerable. Т.е. это не ограничение, и оно не проверяется компилятором. То, что проверяется, - то, что

  • Ваш объект обеспечивает открытый метод GetEnumerator , который
    • не берет параметров
    • , возвращают тип, который имеет двух участников
      1. без параметров метод MoveNext что возвраты булевская переменная
      2. свойство Current с методом get что возвраты Объект

    , Например,

    class Foo
    {
        public Bar GetEnumerator() { return new Bar(); }
    
        public struct Bar
        {
            public bool MoveNext()
            {
                return false;
            }
    
            public object Current
            {
                get { return null; }
            }
        }
    }
    
    // the following complies just fine:
    Foo f = new Foo();
    foreach (object o in f)
    {
        Console.WriteLine("Krzysztof Cwalina's da man!");
    }
    

    6
    задан Jeff L 22 July 2009 в 17:51
    поделиться

    3 ответа

    Я бы сделал библиотеку-оболочку, используя C ++ / CLI, чтобы предоставить библиотеку C #. Это может оставить вашу библиотеку без изменений и просто обернуть ее для использования из .NET, обеспечивая лучшее из обоих вариантов.

    6
    ответ дан 16 December 2019 в 21:44
    поделиться

    Одна вещь, которую я нашел полезным, - это углубиться в C ++ / CLI при работе с неуправляемыми библиотеками C ++. Создайте управляемую оболочку с помощью C ++ / CLI и вызовите ее из кода C #. Управляемая оболочка может включать библиотеку (я предполагаю, что она статически связана) в свою DLL, а ссылка на проект - это все, что вам нужно для вашего кода C #.

    2
    ответ дан 16 December 2019 в 21:44
    поделиться

    Нет необходимости писать оболочку на C ++ / CLI. Вы можете напрямую использовать Platform Invoke из C #:

    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;
    }
    
    0
    ответ дан 16 December 2019 в 21:44
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: