我在 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));
}
最佳答案
我还没有深入研究该结构,但看起来生成的签名确实是正确的。这些结构中没有什么特别棘手的,并且所有类型都适当匹配。
问题可能出在 lppList 参数的编码上。您能否提供一个快速示例,说明如何 1) 取回此数据以及 2) 尝试编码 lppList 的代码。
如果在原始结构上使用#pragma pack,也可能会出现问题。 PInvoke Interop Assistant 不会尝试解释 pack 命令。您可能需要手动调整结构上的该设置。
编辑
其中一个问题可能是 lpPhysicalPositionName 和 lpPhysicalCashUnit 参数。尝试将它们切换为 IntPtr 与 String 并删除 Marshal 属性。
警告:我编写了这个工具,所以我对它的可靠性有很大的偏见:)
关于c# - P/调用互操作助手 : Is this actually correct?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1639721/