P/Invoke Interop Assistant:这真的正确吗?
我在 C++ 中有以下结构:(使用 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 提供以下输出:
[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.MarshalAsAttribute(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;
}
但是,当使用 Marshal.PtrToStruct (例如,在 WFSCDMCUINFO.lppList 上)时,我得到垃圾;当使用 Visual Studio 查看内存时,我看到另一个内存条目中的实际内容(而不是 lppList 本身)。
这些转换正确吗?我对 P/Invoke Interop Assistant 的信任是否错误?
编辑:
这是我用来编组到 IntPtr 或从 IntPtr 编组的代码。我知道 Thread 的想法很糟糕,但我稍后会谈到......
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'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.MarshalAsAttribute(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));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我还没有深入研究该结构,但看起来生成的签名确实是正确的。这些结构中没有什么特别棘手的,并且所有类型都适当匹配。
问题可能出在 lppList 参数的编组上。您能否提供一个快速示例,说明如何 1) 取回此数据以及 2) 尝试编组 lppList 的代码。
如果在原始结构上使用#pragma pack,也可能会出现问题。 PInvoke Interop Assistant 不会尝试解释 pack 命令。您可能需要手动调整结构上的该设置。
编辑
一个问题可能是 lpPhysicalPositionName 和 lpPhysicalCashUnit 参数。尝试将它们切换为 IntPtr 与 String 并删除 Marshal 属性。
警告:我写了这个工具,所以我对它的可靠性有很大的偏见:)
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 :)