whats usar novedades new features espaƱol como c# struct pinvoke unmanaged

c# - novedades - Usar ref struct o clase con P/Invoke



new features c# (3)

Sé que este tema fue discutido muchas veces aquí, pero no pude encontrar la respuesta para mi situación específica.

Necesito llamar a C # un método C no administrado que toma un puntero en un objeto struct (no hablo C con fluidez:

int doStuff(MYGRID* grid, int x);

Pero la propia estructura hace referencia a otro objeto struct:

struct MYGRID { int hgap; int vgap; MYIMAGE* image; } struct MYIMAGE { int res; int width; int height; }

Y también necesito establecer directamente el puntero de imagen así:

MYGRID* pGrid = new MYGRID; MYIMAGE* pImage = new MYIMAGE; pGrid->image = pImage;

Entonces, mi pregunta es: ¿en el código C #, debería usar un objeto "struct" y pasarlo por "ref" como el asistente P / Invoke Interop me sugiere? Lo que significa el siguiente código:

MyGrid myGrid = new MyGrid(); MyImage myImage = new MyImage(); myGrid.image = Marshal.AllocHGlobal(Marshal.SizeOf(image)); // A IntPtr in my struct myGrid.image = Marshal.StructureToPtr(image, myGrid.image, false); doStuff(ref myGrid, 0);

O podría usar "clase" en lugar de "struct" para tener el siguiente código muy simple:

MyGrid myGrid = new MyGrid(); MyImage myImage = new MyImage(); myGrid.image = myImage; doStuff(myGrid, 0);

En el primer caso uso un "IntPtr" en mi estructura MyGrid, y solo un objeto MyImage en el segundo caso.


No, si MyImage fuera una clase, MyGrid.image sería una referencia administrada, que es diferente de un puntero.


No confunda la estructura de C # con la estructura de C ++. No són la misma cosa. AC # struct se usa para declarar un tipo de valor. Cuando agrega un tipo de valor en otro tipo, lo almacena directamente en la instancia que lo contiene en lugar de almacenar una referencia a una instancia almacenada en el montón. Una estructura C ++ es simplemente una clase donde todos los miembros por defecto son públicos.

En su caso, debido a que MYGRID contiene un puntero a MYIMAGE , debe usar la class como lo hace en su segundo ejemplo. Sin embargo, la ref en el parámetro myGrid debería eliminarse.

A continuación se muestra un código de muestra que he probado. El código de C ++:

#include "windows.h" struct MYIMAGE { int res; int width; int height; }; struct MYGRID { int hgap; int vgap; MYIMAGE* image; }; extern "C" __declspec(dllexport) int doStuff(MYGRID* grid, int x) { return 0; }

Declarando las clases C # y la función externa:

[StructLayout(LayoutKind.Sequential)] class MyGrid { public int hgap; public int vgap; public IntPtr image; } [StructLayout(LayoutKind.Sequential)] class MyImage { public int res; public int width; public int height; } [DllImport("MyDll")] static extern int doStuff(MyGrid grid, int x);

Llamar a la función externa:

MyImage image = new MyImage(); MyGrid grid = new MyGrid(); grid.image = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyImage))); Marshal.StructureToPtr(image, grid.image, false); doStuff(grid, 0);

Si activa la depuración no administrada en su proyecto C #, puede usar el depurador para ingresar a la función C ++ y verificar que las clases se hayan calculado correctamente.


Debajo está mi código de prueba, puedes tomarlo como referencia.

c # code - struct

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] struct Items { public double item1; public double item2; }

Código c # - clase de llamada

class ItemManager { [DllImport("CppLibrary.dll")] private static extern double Sum_(ref Items items); public static double Sum(Items items) { return Sum_(ref items); } }

c ++ cpp

double ItemManager::Sum(Items items) { return items.item1 + items.item2; }

encabezado c ++

class Items { public: double item1; double item2; }; class ItemManager { public: static double Sum(Items items); }; extern "C" __declspec(dllexport) double Sum_(Items * items) { return ItemManager::Sum( * items); }