P / Invoke Interop助手:这实际上是否正确?

时间:2009-10-28 19:58:50

标签: c# c++ interop pinvoke

我在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助手的信任错位了吗?

编辑:

这是我用来与IntPtr进行Marshal的代码。我知道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));
    }

1 个答案:

答案 0 :(得分:3)

我没有对结构进行深入研究,但看起来生成的签名肯定是正确的。在这些结构中没有什么特别棘手的,所有类型都适当匹配。

问题可能是lppList参数的编组问题。您能否快速了解1)如何获取此数据以及2)尝试编组lppList的代码。

如果在原始结构上使用了#pragma pack,也可能会出现问题。 PInvoke Interop Assistant不会尝试解释pack命令。您可能必须手动调整结构上的该设置。

修改

一个问题可能是lpPhysicalPositionName和lpPhysicalCashUnit参数。尝试将它们切换到IntPtr vs. String并删除Marshal属性。

警告:我写了这个工具,所以我对它的可靠性有很大的偏见:)