How to allocate memory for an array of structure i

2019-09-05 14:46发布

问题:

Structure 1:

typedef struct _wfs_cdm_cu_info
{
    USHORT usTellerID;
    USHORT usCount;
    LPWFSCDMCASHUNIT * lppList;
} WFSCDMCUINFO, * LPWFSCDMCUINFO; 

Structure 2:

typedef struct _wfs_cdm_cashunit
{
    USHORT usNumber;
    USHORT usType;
    LPSTR lpszCashUnitName;
    CHAR cUnitID[5];
    CHAR cCurrencyID[3];
    ULONG ulValues;
    ULONG ulInitialCount;
    ULONG ulCount;
    ULONG ulRejectCount;
    ULONG ulMinimum;
    ULONG ulMaximum;
    BOOL bAppLock;
    USHORT usStatus;
    USHORT usNumPhysicalCUs;
    LPWFSCDMPHCU * lppPhysical;
} WFSCDMCASHUNIT, * LPWFSCDMCASHUNIT;

Structure 3:

typedef struct _wfs_cdm_physicalcu
{
    LPSTR lpPhysicalPositionName;
    CHAR cUnitID[5];
    ULONG ulInitialCount;
    ULONG ulCount;
    ULONG ulRejectCount;
    ULONG ulMaximum;
    USHORT usPStatus;
    BOOL bHardwareSensor;
} WFSCDMPHCU, * LPWFSCDMPHCU; 

C# structure:-

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct WFSCDMPHCU {     [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
 public string lpPhysicalPositionName;[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
 public string cUnitID;
 public uint ulInitialCount;
 public uint ulCount;
 public uint ulRejectCount;
 public uint ulMaximum;
 public ushort usPStatus;
 public int bHardwareSensor;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
    public struct WFSCDMCASHUNIT {
     public ushort usNumber;
     public ushort usType;         [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
     public string lpszCashUnitName;[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
     public string cUnitID;        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=3)]
     public string cCurrencyID;
     public uint ulValues;
     public uint ulInitialCount;
     public uint ulCount;
     public uint ulRejectCount;
     public uint ulMinimum;
     public uint ulMaximum;
     public int bAppLock;
     public ushort usStatus;
     public ushort usNumPhysicalCUs;
     public System.IntPtr lppPhysical;
    }

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
public struct WFSCDMCUINFO {    
 public ushort usTellerID;    
 public ushort usCount;      
 public System.IntPtr lppList;
}

DLLImport

[DllImport(@"Dispenser.dll")]
public static extern int CDM_SetCashUnit(out WFSCDMCUINFO cuinfo);

1)My main problem is How should I marshall or allocate memory for this structure to send data from C# to C++ ,the second and third structure being array of structure???

2)If I use pointer how efficient it would be.

3)If C++/CLI wrapper be used then how I could access it through C#.

It is been a long time I'm working and I m yet to figure out how should I fill the array of structures in C# .

Follwing code is what i try to figure out...

Marshal Code:

Facing an error of "to define an extension non generic static class"

 public static IntPtr GetIntPtr(this object obj) {
            try {
                var handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
                var thread = new Thread(() => {
                    Thread.Sleep(20000);
                    handle.Free();
                });
                thread.Start();

                return handle.AddrOfPinnedObject();
            } catch (ArgumentException) {
                var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));

                Marshal.StructureToPtr(obj, ptr, false);

                return ptr;
            }
        }

        public static T FromIntPtr<T>(this IntPtr ptr) {
            if (ptr == IntPtr.Zero)
                return default(T);

            return (T) Marshal.PtrToStructure(ptr, typeof (T));
        }

A link of C++ code, of how I have called the function is given.link

回答1:

This is my structure mapping in c#:

[StructLayout(LayoutKind.Sequential)]
public struct Message
{
    public uint MsgId;
    public uint DLC;
    public uint Interval;
    public uint Handle;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public byte[] Data;
};

C++ here:

    struct Message { 
    unsigned int MsgId;
    unsigned int DLC;
    unsigned int Interval;
    unsigned int Handle;
    unsigned char Data[64]; 

} ;

My method in c++ which needs such a structure as a parameter:

extern "C" __declspec(dllexport) int _stdcall MessageWrapper( Message *msg)

Here is how i call this method from C#:

            Message frame = new Message();
            frame.MsgId = (uint)MsgId;
            frame.DLC = (uint)Dlc;
            frame.Interval = (uint)Interval;
            frame.Data = new byte[64];


            int rawsize = Marshal.SizeOf(frame);
            IntPtr frameBuffer = Marshal.AllocHGlobal(rawsize);
            Marshal.StructureToPtr(frame, frameBuffer, false);

Call the method here:

            int response = HwWrapper.MessageWrapper(frameBuffer);

You may have some modifications made in c++ and you can read them back here in c#:

            frame = (Message)(Marshal.PtrToStructure(frameBuffer, typeof(Message)));


            Marshal.FreeHGlobal(frameBuffer);