P / Invoke Interop Assistant: Это действительно правильно? - PullRequest
2 голосов
/ 28 октября 2009

У меня есть следующие структуры в C ++: (с использованием пакета Pragma 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 неуместно?

EDIT:

Это код, который я использую для маршала в / из 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));
    }

1 Ответ

3 голосов
/ 28 октября 2009

Я не углубился в структуру, но, похоже, сгенерированные подписи верны. В этих структурах нет ничего особенно сложного, и все типы соответствуют друг другу.

Скорее всего, проблема в маршаллинге параметра lppList. Можете ли вы дать быстрый пример того, как вы 1) получаете эти данные обратно и 2) код, который пытается маршалировать lppList.

Также могут возникнуть проблемы, если #pragma pack был использован в исходной структуре. PInvoke Interop Assistant не будет пытаться интерпретировать команды пакета. Возможно, вам придется настроить этот параметр в структуре вручную.

EDIT

Одной из проблем могут быть параметры lpPhysicalPositionName и lpPhysicalCashUnit. Попробуйте переключить их на IntPtr vs. String и удалить атрибут Marshal.

Предостережение: я написал этот инструмент, поэтому я сильно склонен к его надежности :)

...