c# - P/调用互操作助手 : Is this actually correct?

标签 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 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/

相关文章:

erlang - Threaded Erlang C-Node(cnode) 互操作性如何?

visual-c++ - 将 .Net ref (%) 转换为原生 (&)

c# - 从 javascript 调用 c# 函数背后的代码

C#:在其他方法中包装方法

c++ - 可以在成员初始化列表中调用虚函数吗?

c++ - 我可以使用 Putty 和 sublime 进行远程编译吗?

c# - 在外部应用程序中设置文本框的文本。 Win32 API

c# - 防止类被实例化

c# - 在同一个 NuGet 包中为 .Net 4.7.2 和 .Net 6.0 构建?

c++ - main() 如何处理不带省略号的可变数量的参数?