none
c# 操作C或C++ DLL:如何解析结构体中指向另一结构体的指针? RRS feed

  • 问题

  • 详细描述:
    C 的原型结构体
    typedef struct _wfs_result
    {
        REQUESTID       RequestID;
        HSERVICE        hService;
        SYSTEMTIME      tsTimestamp;//这个对应下面的SYSTEMTIME 结构
        HRESULT         hResult;
        union {
            DWORD       dwCommandCode;
            DWORD       dwEventID;
        } u;
        LPVOID          lpBuffer; //返回的指针,指向WFSIDCSTATUS 这个结构
    } WFSRESULT, * LPWFSRESULT;

    typedef struct _SYSTEMTIME {
        WORD wYear;
        WORD wMonth;
        WORD wDayOfWeek;
        WORD wDay;
        WORD wHour;
        WORD wMinute;
        WORD wSecond;
        WORD wMilliseconds;
    } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

    typedef struct _wfs_idc_status
    {
        WORD            fwDevice;
        WORD            fwMedia;
        WORD            fwRetainBin;
        WORD            fwSecurity;
        USHORT          usCards;
        WORD            fwChipPower;
        LPSTR           lpszExtra;
    } WFSIDCSTATUS, * LPWFSIDCSTATUS;


    C#对应定义的结构体:
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct _wfs_result
    {
                public UInt32 RequestID;
                public ushort hService;          
                public _SYSTEMTIME tsTimestamp;//对应下面的 _SYSTEMTIME
                public int hResult;
                public AnonymousStruct U;//对应下面的 AnonymousStruct 结构
                public IntPtr lpBuffer;//返回的指针,指向_wfs_idc_status 这个结构
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct _SYSTEMTIME
    {
                public UInt16 wYear;
                public UInt16 wMonth;
                public UInt16 wDayOfWeek;
                public UInt16 wDay;
                public UInt16 wHour;
                public UInt16 wMinute;
                public UInt16 wSecond;
                public UInt16 wMilliseconds;
    }

    [StructLayout(LayoutKind.Explicit)]
    public unsafe struct AnonymousStruct
    {
                [FieldOffset(0)]
                public UInt32 dwCommandCode;
                [FieldOffset(0)]
                public UInt32 dwEventID;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct _wfs_idc_status
    {           
                public UInt16 fwDevice;           
                public UInt16 fwMedia;           
                public UInt16 fwRetainBin;           
                public UInt16 fwSecurity;           
                public ushort usCards;           
                public UInt16 fwChipPower;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string lpszExtra;
    }

    通过Windows消息机制处理,我从WinForm的Message.LParam中获得了结构体(_wfs_result)的指针并将其转化为了_wfs_result的一个变量,通过这个变量可以正常访问其中定义的字段,唯有:“public IntPtr lpBuffer; //指向结构体(_wfs_idc_status)的指针”使用失败,该如何定义和操作结构体才能正确使用该指针呢?

    补充说明:我用WinForm窗体来接收C++编写的DLL发送过来的消息,DLL导出函数中将WinForm窗体句柄传给导出函数,其会将消息传送给WinForm。经测试证明:DLL传过来的消息Message.LParam指针可以转化为对应的结构体,就是该结构体内的指向另结构体的指针出错,不能转化为对于的结构体,但值有的。为什么呢?该如何解决这类问题?


    产生错误的代码: Status = (STATUS)Marshal.PtrToStructure(Result.lpBuffer, typeof(STATUS));  其中Status为STATUS类型的结构体,Result为RESULT类型的结构体变量。
    错误提示: 检测到FatalExecutionEngineError 运行时遇到了错误。此错误的地址为 0x661ffc37,在线程 0xe0c 上。错误代码为 0xc0000005。此错误可能是 CLR 中的 bug,或者是用户代码的不安全部分或不可验证部分中的 bug。此 bug 的常见来源包括用户对 COM-interop 或 PInvoke 的封送处理错误,这些错误可能会损坏堆栈。

    2011年7月14日 3:50

答案

  • 这个问题我通过5天的攻关,终于解决了。关键是 C# 中 public struct WFSRESULT
    这个结构的定义要改变一下:
    将原来的 
    [StructLayout(LayoutKind.Sequential)]
     public struct WFSRESULT
     {
    改为:(关键)
     [StructLayout(LayoutKind.Explicit)]
     public unsafe struct _wfs_result
     {
    这种方式的定义就可以了。
    2011年7月18日 1:23

全部回复