P/Invoke Interop Assistant:这真的正确吗?

发布于 2024-08-09 17:20:29 字数 4914 浏览 4 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

堇年纸鸢 2024-08-16 17:20:29

我还没有深入研究该结构,但看起来生成的签名确实是正确的。这些结构中没有什么特别棘手的,并且所有类型都适当匹配。

问题可能出在 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 :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文