Marshaling in C# and C++


Struktura parametrów w klasie C# musi mieć takie same odbicie w nagłówku C++ . Dodatkowo obiekty (MyStep, PCB) w strukturze w klasie C# muszą być z atrybutem UnmanagedType.Struct. Dodatkowo struktura CustomerPanel w C# nie może mieć atrybutu Pack=1. W definicji funkcji cppTestStructMyCustomerPanelArray() nie ma pointera dla myCustomerPanelArray[].

Struktury w C++ (header):

	typedef struct _MySinglePCB {
		int pcbID;
		int pcbNumber;
		int width;
		int height;
		int diagonal;
		bool panel;
	} MySinglePCB;

	typedef struct _MyStep {
		int stepX;
		int stepY;
	} MyStep;

	typedef struct _MyCustomerPanel {
		int myCounter;
		int id;
		int mySubIndex;	// idzie w parze z ID 
		int width;
		int height;
		int diagonal;
		MyStep step;
		MySinglePCB myPCB;
		bool located;
		float occupancy;
	} MyCustomerPanel;

Struktury w C# klasa CustomerPanel.cs:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct PCB
    {
        public int id;
        public int number;
        public int width;
        public int height;
        public int diagonal;
        [MarshalAs(UnmanagedType.I1)]
        public bool panel;
    }

    public struct MyStep
    {
        public int stepX;
        public int stepY;
    }


    // nie urzywac: Pack = 1
    [StructLayout(LayoutKind.Sequential)]
    public struct CustomerPanel
    {
        public int myCounter;
        public int id;
        public int mySubIndex;
        public int width;
        public int height;
        public int diagonal;
        [MarshalAs(UnmanagedType.Struct, SizeConst = 1)]
        public MyStep step;
        [MarshalAs(UnmanagedType.Struct, SizeConst = 1)]
        public PCB pcb;
        [MarshalAs(UnmanagedType.Bool)]
        public bool located;
        [MarshalAs(UnmanagedType.R4)]
        public float occupancy;
    }

Funkcja w C++:

HRESULT cppTestStructMyCustomerPanelArray(MyGerber * const ghw, MyCustomerPanel myCustomerPanelArray[])
{
  myCout("MyGerber.cpp: cppTestStructMyCustomerPanelArray()" << endl);
  myCout("sizeof(myCustomerPanelArray): " << sizeof(myCustomerPanelArray) << endl);

  myCustomerPanelArray[0].id = 19;
  myCustomerPanelArray[0].width = 166;
  myCustomerPanelArray[0].height = 255;
  myCustomerPanelArray[1].id = 29;
  myCustomerPanelArray[1].width = 299;
  myCustomerPanelArray[1].height = 397;
  myCustomerPanelArray[1].step.stepX = 2;
  myCustomerPanelArray[1].step.stepY = 3;
}

Funkcja w C#:

private const string myDLLfile = "pcbMergerLib2.dll"; 
DllImport(myDLLfile, CallingConvention = CallingConvention.Cdecl, EntryPoint = "cppTestStructMyCustomerPanelArray")]
internal static extern int myTestStructMyCustomerPanelArray(IntPtr hwnd, IntPtr myCustomerPanelPtr);

public cppWrapper()
{
  hwndGerber = MyGerber();
  Console.WriteLine("cppWrapper(): constructor: hwndGerber: {0:x}", hwndGerber);
}

CustomerPanelArray myCPA = new CustomerPanelArray();
int sizeCPA = Marshal.SizeOf(typeof(CustomerPanelArray));
Console.WriteLine("sizeCPA: {0}", sizeCPA);

IntPtr myCPAPtr = Marshal.AllocHGlobal(sizeCPA);
Marshal.StructureToPtr(myCPA, myCPAPtr, true);

myTestStructMyCustomerPanelArray(hwndGerber, myCPAPtr);  // call to DLL
myCPA = (CustomerPanelArray)(Marshal.PtrToStructure(myCPAPtr, typeof(CustomerPanelArray)));
Marshal.FreeHGlobal(myCPAPtr);

// sprawdzenie (i dziala)
Console.WriteLine("cpID\t cpWidth\t cpHeight\t cpOccup\t stepX\t stepY\t pcbID\t " +
                "pcbNr\t pcbWidth\t pcbHeight");
for (int i = 0; i < 8; i++)     // alokacja dla 8 (u)rzytkuf
{
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].id);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].width);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].height);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].step.stepX);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].step.stepY);

  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].pcb.id);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].pcb.number);
  Console.Write("[{0}] {1} \t", i, myCPA.myCustPanel[i].pcb.width);
  Console.Write("[{0}] {1} \n", i, myCPA.myCustPanel[i].pcb.height);
}  

I wynik:

MyGerber.cpp: MyGerber() ctor
MyMaxRectsBinPack.cpp: MyMaxRectsBinPack() ctor
MyGerber.cpp: MyGerber(): mrbp: 00CBAB60
MyGerber.cpp: MyGerber_New(): MyGerberPtr: 00C7D6A8
cppWrapper(): constructor: hwndGerber: 13096616
-- testing CustomerPanel Array --
sizeCPA: 512
MyGerber.cpp: cppTestStructMyCustomerPanelArray()
sizeof(myCustomerPanelArray): 4
cpID     cpWidth         cpHeight        cpOccup         stepX   stepY   pcbID   pcbNr   pcbWidth    pcbHeight
[0] 19  [0] 166         [0] 255         [0] 14.4        [0] 0   [0] 0   [0] 0   [0] 0   [0] 0   [0] 0
[1] 29  [1] 297         [1] 397         [1] 13.3        [1] 0   [1] 0   [1] 0   [1] 0   [1] 0   [1] 0
[2] 7   [2] 297         [2] 397         [2] 97.7        [2] 1   [2] 3   [2] 0   [2] 0   [2] 0   [2] 0
[3] 6   [3] 296         [3] 396         [3] 96.6        [3] 2   [3] 2   [3] 6   [3] 8   [3] 70  [3] 65
[4] 4   [4] 444         [4] 333         [4] 44.4        [4] 3   [4] 3   [4] 4   [4] 2   [4] 60  [4] 80
[5] 5   [5] 551         [5] 552         [5] 55.5        [5] 5   [5] 6   [5] 5   [5] 5   [5] 50  [5] 51
[6] 0   [6] 0   [6] 0   [6] 0   [6] 0   [6] 0   [6] 0   [6] 0   [6] 0   [6] 0
[7] 0   [7] 0   [7] 0   [7] 0   [7] 0   [7] 0   [7] 0   [7] 0   [7] 0   [7] 0
~cppWrapper(): destructor: hwndGerber: 13096616
MyGerber.cpp: MyGerber_Delete(): hw: 00C7D6A8
MyGerber.cpp: ~MyGerber() dtor
MyGerber.cpp: ~MyGerber(): mrbp: 00CBAB60
MyMaxRectsBinPack.cpp: ~MyMaxRectsBinPack() dtor
Press any key to continue . . .


Leave a Reply

Your email address will not be published. Required fields are marked *