你的位置:首页 > ASP.net教程

[ASP.net教程]关于c#调用c/c++ dll遇到的问题总结


  前段时间公司做了个winform程序,需要调用c 的dll去读取卡号的程序,期间遇到些问题,下面来分享下

   一、dll路径问题

    相信很多开发者都会遇到这个问题,我总结了下我现在有3总方式去解决这个问题;

           1.直接放在bin下面,跟exe文件在同一文件夹下,

           ps:调试代码的时候,如果是debug模式的话,就放bin/debug下,同理release 模式就放bin/debug下;如果这种方式不行的话,就试试第二种方式。

           2.放在C:\Windows\System32下;

           3.如果以上方式都不行的话就,那就只能写物理路径了。例

                    

[System.Runtime.InteropServices.DllImportAttribute(@"E:\Source\GPTagReaderDll", EntryPoint = "OpenPort", CallingConvention = CallingConvention.Cdecl)]    [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]    public static extern bool OpenPort(string pPortname, uint dBaud);

         该种方式只适合调一个dll的方式,如果调用的这个dll依赖于其他的dll的话这种方式是行不通的;这种方式还有局限性,如果发布出去,你得要求别人的机子上这个物理路径下必须有这个文件,但是 这个太不现实了

        除这3种方式外,还听说过写到环境变量里,不过这种方式没试过,就不在此提了。

        二、类型转换的问题

           下面是c的结构体:

typedef struct{  unsigned char DeviceIdentify[30];//Greenpow Usb IC card reader  unsigned short res; }FindDeviceAck_Struct;

    我们需要把它转换成c#的结构体:

    

  [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,    CharSet = System.Runtime.InteropServices.CharSet.Ansi,Pack =1)]  public struct FindDeviceAck_Struct  {    /// unsigned char[30]    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr,      SizeConst = 30)]    public string DeviceIdentify;    /// unsigned short    public ushort res;  }

  c# 跟c/c++类型的对应方式,可参考http://www.cnblogs.com/ausoldier/archive/2007/12/07/986141.html;

  我这里DeviceIdentify用String接收,但是出现了乱码,后来改成了

  [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,    CharSet = System.Runtime.InteropServices.CharSet.Ansi,Pack =1)]  public struct FindDeviceAck_Struct  {    /// unsigned char[30]    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray,      SizeConst = 30)]    public byte[] DeviceIdentify;        /// unsigned short    public ushort res;  }

    string 对应的是ByValTStr,byte[] 对应的是ByValArray,sizeconst指的是大小,pack=1表示按1字节对齐

   三、调用c里的方法

  c里的方法是BOOL FindDevice(FindDeviceAck_Struct &finddeviceack);

    刚开始我直接这样写,

    [System.Runtime.InteropServices.DllImportAttribute("GPTagReaderDll", EntryPoint = "FindDevice", CallingConvention = CallingConvention.Cdecl)]    public static extern bool FindDevice(FindDeviceAck_Struct finddeviceack);

   调用的时候

       

 FindDeviceAck_Struct findDeviceAck=new FindDeviceAck_Struct();        var result= NativeMethods.FindDevice(findDeviceAck);

   结果报了下面这个错误:尝试读取或写入受保护的程序。通常指示其他内存已经存在。

    后来同事提醒才注意到BOOL FindDevice(FindDeviceAck_Struct &finddeviceack)参数&finddeviceack 有个'&'。

           经改成

          

    [System.Runtime.InteropServices.DllImportAttribute("GPTagReaderDll", EntryPoint = "FindDevice", CallingConvention = CallingConvention.Cdecl)]    public static extern bool FindDevice(ref FindDeviceAck_Struct finddeviceack);

        这样就调用成功了