详细描述:  主要是由C#调用DLL库造成的问题。 现有两个C#结构体,是从C语言中翻译过来的。      第一个:       [StructLayoutAttribute(LayoutKind.Sequential)]
        public struct STATUS
        {
            public ushort fwDevice;
            public ushort fwMedia;
            public ushort fwRetainBin;
            public ushort fwSecurity;
            public ushort usCards;
            public ushort fwChipPower;
            [MarshalAsAttribute(UnmanagedType.LPStr)]
            public string lpszExtra;
        }       第二个:        [StructLayoutAttribute(LayoutKind.Sequential)]
        public struct  RESULT
        {
            public uint RequestID;
            public ushort hService;
            public int hResult;
            public int u;
            public IntPtr lpBuffer;    //指向第一个结构体的指针;
        }        通过消息处理,我从WinForm的Message.LParam中获得了一个第二个结构体(RESULT)的指针并将其转化为了RESULT的一个变量,通过这个变量可以正常访问其字段,唯有: “public IntPtr lpBuffer;   //指向第一个结构体(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 的封送处理错误,这些错误可能会损坏堆栈。     请求各位高手指教啊!我郁闷一个上午了,都没有找到解决方法。

解决方案 »

  1.   

    http://www.bianceng.cn/Programming/csharp/200911/11864.htm 
      

  2.   

    定义一个结构体,然后用 MemoryCopy API 把数据拷贝过来。
      

  3.   

    利用Marshal类将第一个struct封送到非托管内存,并返回指针,赋值给第二个结构体指针
    c#函数的调用:包含使用指针IntPtr替代结构体数组和读取IntPtr的方法
    view plaincopy to clipboardprint?
    HSCAN_MSG[] msg1 = new HSCAN_MSG[10];   
       for (int i = 0; i < msg1.Length; i++)   
       {   
       msg1[i] = new HSCAN_MSG();   
       msg1[i].pData = new byte[8];   
       }   
       IntPtr[] ptArray = new IntPtr[1];   
       ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);   
       IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));   
       Marshal.Copy(ptArray, 0, pt, 1);   
         
       int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);   
         
       textBoxStatus.Text += "\r\n" + "读取0口:" + count.ToString() + "帧数据";   
       for (int j = 0; j < 10; j++)   
       {   
       msg1[j] =   
       (HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))   
       , typeof(HSCAN_MSG));   
       textBoxStatus.Text += "\r\n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[1]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[2]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[3]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[4]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[5]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[6]).ToString()   
       + "|" + Convert.ToByte(msg1[j].pData[7]).ToString();   
       }  
    HSCAN_MSG[] msg1 = new HSCAN_MSG[10];
       for (int i = 0; i < msg1.Length; i++)
       {
       msg1[i] = new HSCAN_MSG();
       msg1[i].pData = new byte[8];
       }
       IntPtr[] ptArray = new IntPtr[1];
       ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);
       IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));
       Marshal.Copy(ptArray, 0, pt, 1);
      
       int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);
      
       textBoxStatus.Text += "\r\n" + "读取0口:" + count.ToString() + "帧数据";
       for (int j = 0; j < 10; j++)
       {
       msg1[j] =
       (HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))
       , typeof(HSCAN_MSG));
       textBoxStatus.Text += "\r\n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[1]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[2]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[3]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[4]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[5]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[6]).ToString()
       + "|" + Convert.ToByte(msg1[j].pData[7]).ToString();
       } 
      

  4.   

    谢谢大家的回复,我将的问题在重新描述一下吧:
    详细描述:
    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 的封送处理错误,这些错误可能会损坏堆栈。 
      

  5.   

    问题在这个地方:
    LPSTR lpszExtra; ==>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
      public string lpszExtra;LPSTR是字符指针,4个自己,而[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
      public string lpszExtra;是256个字节,这样两边结构体大小不一致!解决办法:
    改变C结构:
        char lpszExtra[256];
      

  6.   

    public IntPtr lpBuffer;//返回的指针,指向_wfs_idc_status 这个结构这个要定义成一个结构体的。而不是一个指针。
    或者定义为和_wfs_idc_status 一样大小的byte[],
    到时候,你可以把这个内存地址转换为指针,指针再转化为结构体。
    你就可以读取到其中的值了。
    或者直接读取byte[]的也可以,就是要根据对应的结构体每一个字段大小,
    读取相应的byte[]长度,然后转化为对应的结构体字段数据类型,就OK。
      

  7.   

    或者定义为和_wfs_idc_status 一样大小的byte[],
    到时候,你可以把这个内存地址转换为指针,指针再转化为结构体。
    你就可以读取到其中的值了。
    或者直接读取byte[]的也可以,就是要根据对应的结构体每一个字段大小,
    读取相应的byte[]长度,然后转化为对应的结构体字段数据类型,就OK。这个方法不能说是万能的,但是大部分情况下,也是好用的。
    因为定义和C++对应的结构体,有时候非常麻烦,不断的改变数据类型尝试也不成功。如果使用byte[]定义,只要定义的大小和C++中的结构体一样,就可以读取到数据。
    读取到数据后,再按照C++中的几个他做处理,比如整数、字符串等,花点时间,调试几次,就可以了。
      

  8.   

    public IntPtr lpBuffer;//返回的指针,指向_wfs_idc_status 这个结构这个要定义成一个结构体的。而不是一个指针。
    或者定义为和_wfs_idc_status 一样大小的byte[],
    到时候,你可以把这个内存地址转换为指针,指针再转化为结构体。
    你就可以读取到其中的值了。怎么将byte[] 这个内存地址转换为指针
      

  9.   

    关键是,_wfs_idc_status的字符指针是变长的,不能实现确定byte[]大小!
    Lz,我正在帮你写程序测试,报你一样的问题,正在调试,挑好了,发你!
      

  10.   

    mjp1234airen4385
    我按你提供的方式,将public IntPtr lpBuffer 定义为和_wfs_idc_status 一样大小的byte[],但是从获取的值中解析出来的值看不明白 返回的如下类式值
    "?\0\0\0\0\0\0\0\b\0?\f\0\0\0\0\0\0\0\0\0\0\0\0\0\0讪?毀?\0\0\0\0\0\0\0\0\0\0?\f.€嶴ystem.Configuration.ConfigurationPermissionAttribute, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aT\fUnrestricted\0\0?\fP?4鄩\0\0?\b\0\0\0\0\0\0\0?\0\0\0\0\0\0\0\0"
      

  11.   

    sdl2005lyx
     
    谢谢,是也在做XFS 的开发吗?
      

  12.   

    sdl2005lyx 有联系方式吗? 我的QQ:172970951 MSN:[email protected]
      

  13.   

    问题已经找到!这是我测试的程序:
    C++:
    typedef struct _wfs_idc_status
    {
    WORD fwDevice;
    WORD fwMedia;
    WORD fwRetainBin;
    WORD fwSecurity;
    USHORT usCards;
    WORD fwChipPower;
    LPSTR lpszExtra;
    } WFSIDCSTATUS, * LPWFSIDCSTATUS;typedef struct _wfs_result
    {  DWORD RequestID;
      WORD hService;
      SYSTEMTIME tsTimestamp;//这个对应下面的SYSTEMTIME 结构
      HRESULT hResult;
      union {
      DWORD dwCommandCode;
      DWORD dwEventID;
      } u;
      // LPVOID lpBuffer; //返回的指针,指向WFSIDCSTATUS 这个结构
      WFSIDCSTATUS *lpBuffer; 
    } WFSRESULT, * LPWFSRESULT;extern "C" void __declspec(dllexport) GetStauts(WFSRESULT* ret);
    void API_CALL GetStauts(WFSRESULT* ret)
    {
    WFSIDCSTATUS*  stat       = new WFSIDCSTATUS ;
    //注意,这里一定要new,用临时结构体变量,出了作用域范围就释放了,C#互操作那边就会异常
        memset (stat,   0, (sizeof(WFSIDCSTATUS))*1);
        stat->lpszExtra="测试123";
    stat->fwChipPower=1;
    stat->fwDevice=1;

    stat->lpszExtra="123";
        stat->fwChipPower=1;
    ret->hService=1;
    ret->lpBuffer=stat;
    }
      

  14.   

    C#互操作:
        [StructLayout(LayoutKind.Sequential)]
        public struct WFSRESULT
        {
          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 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 struct AnonymousStruct
        {
          [FieldOffset(0)]
          public UInt32 dwCommandCode;
          [FieldOffset(0)]
          public UInt32 dwEventID;
        }    [StructLayout(LayoutKind.Sequential)]
        public struct _wfs_idc_status
        {  
          public UInt16 fwDevice;  
          public UInt16 fwMedia;  
          public UInt16 fwRetainBin;  
          public UInt16 fwSecurity;  
          public ushort usCards;  
          public UInt16 fwChipPower;
          public string lpszExtra;
        }        [DllImport(@"E:\pvcs\utscada\Debug\ExamDll.dll", EntryPoint = "GetStauts")]
            public static extern void GetStauts(ref WFSRESULT ret);                WFSRESULT ret=new WFSRESULT();
                    GetStauts(ref ret);                _wfs_idc_status stat = (_wfs_idc_status)Marshal.PtrToStructure(ret.lpBuffer, typeof(_wfs_idc_status));
      

  15.   

    谢谢你 “sdl2005lyx” 我的C#调用C 动态库DLL 是第三方的是一个准标的,不能被修改。
    这个问题我通过5天的攻关,终于解决了。关键是 C# 中 public struct WFSRESULT
    这个结构的定义要改变一下:
    将原来的 
    [StructLayout(LayoutKind.Sequential)]
     public struct WFSRESULT
     {
    改为:(关键)
     [StructLayout(LayoutKind.Explicit)]
     public unsafe struct _wfs_result
     {
    这种方式的定义就可以了。