user-0 提问: 非托管dll引用，函数结构体调用报错

回复:
user: user-1
content: http://bbs.csdn.net/topics/391848714

user: user-0
content: ？？？

user: user-1
content: 不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件，或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。 比如： A将请求数据写到文件a.txt，写完后改名为aa.txt B发现aa.txt存在时，读取其内容，调用相应功能，将结果写到文件b.txt，写完后删除aa.txt，改名为bb.txt A发现bb.txt存在时，读取其内容，读完后删除bb.txt 以上A可以替换为任何一种开发语言或开发环境，B可以替换为任何一种与A不同的开发语言或开发环境。 除非A或B不支持判断文件是否存在、文件读写和文件更名。 但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢？  共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多，下面仅列出我现在能想到的： ·进程之间松耦合 ·进程可在同一台机器上，也可跨机，跨操作系统，跨硬件平台，甚至跨国。 ·方便调试和监视，只需让第三方或人工查看该临时文本文件即可。 ·方便在线开关服务，只需删除或创建该临时文本文件即可。 ·方便实现分布式和负载均衡。 ·方便队列化提供服务，而且几乎不可能发生队列满的情况（除非硬盘空间满） ·……  “跨语言、跨机，跨操作系统，跨硬件平台，跨国，跨*.*的”苦海无边， 回头是“使用共享纯文本文件进行信息交流”的岸！ 楼主无视本ID的回复，祝楼主泪奔一辈子！

user: user-0
content: 能来点干货吗？琢磨了这么久还是不会写了。老是报出：未能从程序集“EPC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中加载类型“report”，因为它在 8 偏移位置处包含一个对象字段，该字段已由一个非对象字段不正确地对齐或重叠。  就调用了简单的dll有这么难吗？泪奔了

user: user-2
content: C#的char是2个字节的，C的char是一个字节，所以你只要留意这个char类型的转换，基本上没什么问题的。然后就是字节对其问题，是不是4字节对齐需要测试，最好的方法是，C#和C语言里面各自检查最终的结构体长度，只要结构体长度一样，P/Invoke就不会出现内存问题，最多就是数据莫名其妙。 C语言里面直接用sizeof来获取结构体长度，C#里面用Marshal.SizeOf函数来获取，比较这个长度是参数问题检查的最好方法。

user: user-0
content: 就是函数运行到读取dll函数时出错了。怀疑是传参数不对，或结构体不对造成的。所以就提出结构体有联合体如何转c#语言，其他机构体基本和这个相同。 函数原型是：int test (int nDevHandle, AntId tAntId, DealReport *func) AntId结构体： #define ANTENNA_MAX_NUM (4)   typedef struct{       short wAntId[ANTENNA_MAX_NUM];    }AntId DealReport结构体 typedef struct Tag_Report{     union{         RoReport tRoReport;         EventReport tEventReport;     }report;     unsigned int  nResType; }Report;  *func是个回调函数，DealReport结构体比较复杂，是结构体中有联合体，比较复杂。 这些包括调用dll函数，怎么转到C#呢？

user: user-0
content: [StructLayout(LayoutKind.Sequential)]     public struct AntId     {        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]        public short[] wAntId;           } 在使用时报出，未将对象引用设置到对象的实例的错误。还有 c++中结构体中有联合体，转为c#这样子对吗 public struct Report      {          public reg report;        public uint nResType;      }      [StructLayout(LayoutKind.Explicit)]      public struct reg          {              [FieldOffset(0)]              public RoReport tRoReport;             [FieldOffset(0)]              public EventReport tEventReport;          }  求解答？？

user: user-2
content: 不要定义class，必须定义struct才行StructLayout特性是针对struct的，而不是class（也许可以，反正我没试过） 然后在struct内部如果要定义array，必须增加[MarshalAs(UnmanagedType.ByValArray,SizeConst=4)]这样的特性来指定数组大小，不然你的数组可以后期动态改变大小的，自然内存就不对了。

user: user-0
content: 有没有人我的问题啊

user: user-2
content: 主要是我不清楚的你全部类型，也不清楚你的具体错误信息，所以也不好确定最终的问题是哪里。 比如你发帖时问的是函数read ，后来又突然蹦出个函数DealReport，现在干脆有来个函数test。你到底有多少个函数，自己也没交代清楚，原型也没整理好，看得别人很累，知道吗？

user: user-0
content: #define ANTENNA_MAX_NUM (4)  typedef struct{      short wAntId[ANTENNA_MAX_NUM];   }AntId; 长度是4啊，具体怎么分配。不是提示未将对象引用设置到对象的实例的错误，就是跳到 举行函数为：     int cc = DidCapture.test((int)nDevHandle, tAntId, ref dealReport); int cc = DidCapture.startInventory((int)nDevHandle, tAntId, ref dealReport);报错。原型为：int test (int nDevHandle, AntId tAntId, DealReport *func) RoReport 和EventReport是结构体的。 c++到c#数据类型转换不太懂

user: user-2
content: MarshalAs只是在P/Invoke的时候告诉被调用函数，这个地方的数组给了多少长度。但是这个数组的内存空间还是需要你来分配的呀。非托管代码无法识别托管代码中的Array类型，因此需要给一个长度参数，就用那个MarshalAs特性来告知。 联合体部分没错，当然类型RoReport 和EventReport也必须是结构体才行，如果是引用类型，那还是要出问题的。

user: user-1
content: 仅供参考：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //

user: user-0
content: 请各位牛人帮一下忙，结构体还有结构体如何定义

user: user-0
content: c++函数原型 #define ANTENNA_MAX_NUM (4) typedef struct{     short wAntId[ANTENNA_MAX_NUM]; //天线1-4， 0表示天线未启用，1表示天线在用 }AntId; typedef void DealReport(Report *ptReport);回调函数 我定义的C#如下： 采用这种方法  public class Report     {         public reg report;         public uint nResType;//报告类型     }      [StructLayout(LayoutKind.Explicit)]     public struct reg         {             [FieldOffset(0)]             public RoReport tRoReport;            [FieldOffset(0)]             public EventReport tEventReport;         }  [StructLayout(LayoutKind.Sequential)]     public class AntId     {         public short[] wAntId = new short[4] { 0,0,0,0};     } 运行时报 “尝试读取或写入受保护的内存。这通常指示其他内存已损坏”这个错误。

user: user-3
content: 1. c/c++中的struct 和 union在c#总都对应struct， 2. 如果嵌套，依次定义就可以使用。         //这个是基础结构体    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]     public struct SStruct1     {        //...     ｝        //嵌套使用     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]     public struct SStruct2     {        public SStruct1 m1;  //成员        //others            ｝    3.Union也对应struct： union{         ReadParam              tReadParam;         WriteParam             tWriteParam;     }op;  这么翻译   [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]     public struct op     {          [FieldOffset(0)]         public  ReadParam tReadParam;             [FieldOffset(0)]         public WriteParam tReadParam;      ｝  4.基本类型，两种语言差不多，几乎可以直接对应  CharSet 和Pack 参数需要询问c/c++的提供方确认