P/Invoke Interop Assistant: Is this actually correct?
I've got the following structs in C++: (Using pragma pack 1)
typedef struct _wfs_cdm_physicalcu
{
LPSTR lpPhysicalPositionName;
CHAR cUnitID[5];
ULONG ulInitialCount;
ULONG ulCount;
ULONG ulRejectCount;
ULONG ulMaximum;
USHORT usPStatus;
BOOL bHardwareSensor;
} WFSCDMPHCU, * LPWFSCDMPHCU;
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;
typedef struct _wfs_cdm_cu_info
{
USHORT usTellerID;
USHORT usCount;
LPWFSCDMCASHUNIT *lppList;
} WFSCDMCUINFO, * LPWFSCDMCUINFO;
P/Invoke Interop Assistant gives me the following output:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct WFSCDMPHCU {
/// LPSTR->CHAR*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string lpPhysicalPositionName;
/// CHAR[5]
[System.Runtime.InteropServices.Marshal开发者_Go百科AsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
public string cUnitID;
/// ULONG->unsigned int
public uint ulInitialCount;
/// ULONG->unsigned int
public uint ulCount;
/// ULONG->unsigned int
public uint ulRejectCount;
/// ULONG->unsigned int
public uint ulMaximum;
/// USHORT->unsigned short
public ushort usPStatus;
/// BOOL->int
public int bHardwareSensor;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct WFSCDMCASHUNIT {
/// USHORT->unsigned short
public ushort usNumber;
/// USHORT->unsigned short
public ushort usType;
/// LPSTR->CHAR*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string lpszCashUnitName;
/// CHAR[5]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
public string cUnitID;
/// CHAR[3]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=3)]
public string cCurrencyID;
/// ULONG->unsigned int
public uint ulValues;
/// ULONG->unsigned int
public uint ulInitialCount;
/// ULONG->unsigned int
public uint ulCount;
/// ULONG->unsigned int
public uint ulRejectCount;
/// ULONG->unsigned int
public uint ulMinimum;
/// ULONG->unsigned int
public uint ulMaximum;
/// BOOL->int
public int bAppLock;
/// USHORT->unsigned short
public ushort usStatus;
/// USHORT->unsigned short
public ushort usNumPhysicalCUs;
/// LPWFSCDMPHCU*
public System.IntPtr lppPhysical;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
public struct WFSCDMCUINFO {
/// USHORT->unsigned short
public ushort usTellerID;
/// USHORT->unsigned short
public ushort usCount;
/// LPWFSCDMCASHUNIT*
public System.IntPtr lppList;
}
However, when using Marshal.PtrToStruct (say, on WFSCDMCUINFO.lppList) I get garbage; when viewing memory using Visual Studio, I see the actual contents in another memory entry (not lppList per se).
Are these conversions correct? Is my trust in P/Invoke Interop Assistant misplaced?
EDIT:
This is the code I use to Marshal to/from IntPtr. I know the Thread idea sucks, but I'll get to that later...
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));
}
I haven't done a deep dive into the structure but it definitely looks like the generated signatures are correct. There is nothing particularly tricky in these structs and all of the types are appropriately matched.
What's likely the problem is the marshalling of the lppList parameter. Can you give a quick sample of how you 1) get this data back and 2) the code which attempts to marshal lppList.
Also there may be issues if #pragma pack was used on the original structure. The PInvoke Interop Assistant won't attempt to interpret pack commands. You may have to adjust that setting on the struct manually.
EDIT
One issue may be the lpPhysicalPositionName and lpPhysicalCashUnit parameters. Try switching them to IntPtr vs. String and removing the Marshal attribute.
Caveat: I wrote this tool so I'm heavily biased on it's reliability :)
精彩评论