none
.Net互操作:指针转换??? RRS feed

  • 问题

  • 在进行.Net互操作过程中,从非托管代码传过来一个指向结构体指针的指针,已知该结构体类型,如何解析它已获得它的内容?还有就是如果传过来的是LPBYTE类型的指针并知道它的长度,如何将其转化为C#的string类型?

    比如知道非托管结构体类型为TSTRUCT1 ,LPTSTRUCT1 *lppStruct 为指向结构体指针的指针,现在知道lppStruct的值如何从指针获得一个TSTRUCT1值?

    2010年10月19日 9:51

答案

  • 多谢,已经解决。关键代码:

    IntPtr PtrData = IntPtr.Zero; 

    WFSIDCCARDDATA Output = new WFSIDCCARDDATA();

    PtrData = Marshal.ReadIntPtr(mResult.lpBuffer, i * Marshal.SizeOf(typeof(IntPtr)));   //读WFSIDCCARDDATA地址;

    if (PtrData != IntPtr.Zero)

             Output = (WFSIDCCARDDATA)Marshal.PtrToStructure(PtrData, Output.GetType());

    • 已标记为答案 Mog Liang 2010年11月8日 2:42
    2010年10月27日 8:16

全部回复

  • 这几个问题在这里都回答过。指针转结构的问题,首先需要在 C# 里面定义该结构 (可能需要 StructLayout.Sequential,或者其他的 Attribute,如 MarshalAs),然后利用 System.Runtime.InteropServices.Marshal.PointerToStructure 方法将一个返回的托管指针 (IntPtr) 转成对应的 Struct 实例。

    LPBYTE 类型到 String 直接附加 MarshalAs(UnmanagedType.BStr) 到 string 参数的声明上。


    Mark Zhou
    2010年10月19日 10:00
  • 你所述可行,但与我的情况稍有不同,首先我得到的是一个指向结构体指针的指针,一个LpByte类型的指针,他们是由消息参数传给我的即:Message.LpParam参数得到,这种情况是不是有区别呢?

    2010年10月20日 0:29
  • 应该是可以的,加上 MarshalAs 指定其类型为 LPByte,有问题请再贴出详细信息。
    Mark Zhou
    2010年10月20日 9:08
  • 问题:指向结构体指针的指针其实内容为结构体数组,怎么读取其内容呢?我的做法如下,但是错的,请教了。

    for (int i = 0; i < 8; i++)
    {
           PtrData = Marshal.ReadIntPtr(mResult.lpBuffer, i * Marshal.SizeOf(typeof(WFSIDCCARDDATA)));
            Output[i] = (WFSIDCCARDDATA)Marshal.PtrToStructure(PtrData, Output[i].GetType());

    }

     其中:WFSIDCCARDDATA为结构体名字,mResult.lpBuffer为LPWFSIDCCARDDATA *lppCardData的指针,假设有8个结构体。怎么读取内容呢?

    2010年10月22日 6:10
  • mResult.lpBuffer 的 C# 对应类型是什么?是 IntPtr[] 还是 HandleRef?或 IntPtr?
    Mark Zhou
    2010年10月22日 9:16
  • 多谢,已经解决。关键代码:

    IntPtr PtrData = IntPtr.Zero; 

    WFSIDCCARDDATA Output = new WFSIDCCARDDATA();

    PtrData = Marshal.ReadIntPtr(mResult.lpBuffer, i * Marshal.SizeOf(typeof(IntPtr)));   //读WFSIDCCARDDATA地址;

    if (PtrData != IntPtr.Zero)

             Output = (WFSIDCCARDDATA)Marshal.PtrToStructure(PtrData, Output.GetType());

    • 已标记为答案 Mog Liang 2010年11月8日 2:42
    2010年10月27日 8:16
  • 详细描述:
    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 的封送处理错误,这些错误可能会损坏堆栈。

     

    也是出现了你反眏的问题,在解析_result.lpBuffer 转换成wfs_idc_status 结构时出错了。

    根据你给出的解决方案修改,在是程序执行 PtrData = Marshal.ReadIntPtr(_result.lpBuffer, i * Marshal.SizeOf(typeof(IntPtr)));//读_wfs_idc_status地址;出错了报"尝试读取或写入受保护的内存。这通常指示其他内存已损坏"
    代码如下:

    wfs_idc_status idc_status = new wfs_idc_status();
    IntPtr PtrData = IntPtr.Zero;
     for (int i = 1; i < 8; i++)
    {
         PtrData = Marshal.ReadIntPtr(_result.lpBuffer, i * Marshal.SizeOf(typeof(IntPtr)));//读_wfs_idc_status地址;
     }
     if (PtrData != IntPtr.Zero)
             idc_status = (common._wfs_idc_status)Marshal.PtrToStructure(PtrData, idc_status.GetType());

    搞了两天还没有搞出来,急人啊,请大侠多指点


    2011年7月13日 7:54