调用c++动态库一般我们这样写
[DllImport("UCamer.dll", CallingConvention = CallingConvention.Winapi)]
public extern static void Disp_Destroy(IntPtr hShow);
DllImport的第一个参数UCamer.dll是动态库dll的路径,此dll放在程序运行的根目录或者c:windows/sytem32下
CallingConvention 参数是c#调用c++的方式 是个枚举 msdn解释如下
Cdecl 调用方清理堆栈。这使您能够调用具有 varargs 的函数(如 Printf),使之可用于接受可变数目的参数的方法。
FastCall 不支持此调用约定。
StdCall 被调用方清理堆栈。这是使用平台 invoke 调用非托管函数的默认约定。
ThisCall 第一个参数是 this 指针,它存储在寄存器 ECX 中。其他参数被推送到堆栈上。此调用约定用于对从非托管 DLL 导出的类调用方法。
Winapi 此成员实际上不是调用约定,而是使用了默认平台调用约定。例如,在 Windows 上默认为 StdCall,在 Windows CE.NET 上默认为 Cdecl。
从上面来看Winapi方式是根据系统自动选择调用规约的。 而thisCall是对c++类的调用方法。 所以 一般情况下我们选择Winapi就可以了。
c#调用dll另一个难点:数据类型转换
http://wenku.baidu.com/link?url=SihlxtHC-HMcEhq3izpd2bux8rNaKOMTpu8NPqjdYlLSwYSV1CqNJdVbxkaZm7OqaaSTEK-KUJqX5jbtkdpnUZ_38No4tsrgqCsf7Th5dqK
百度文库这篇文章基本把c++与c#的对应数据类型总结完了。但是为什么这里还要说呢
1,百度文库这篇文章,包括大部分度娘的类型转换的资料中 对c++中的返回值类型char[] 都转换成了char[] 没做任何改变。
c++中char占一个字节,assic编码。而c#中的char占2个字节(我是在中文版的vs中测试的)。
如果这样转换就会出现问题,很容易发生越界,或者读写到受保护的内存等问题。
解决方法是 把char[] 变成c#中的byte[] ,再用Encoding.Assic.getstring方法转换。
2,关于指针,c++所有的指针 在c#上用Intptr ,问题又来了。假如返回的Intptr是个数组指针,在c#中我们怎么读取数组里面的元素呢?
Marshal.Copy();
Marshal类是c#中专门把非托管内存转换成托管内存的神器,不需要unsafe。 Marshal中copy方法是最最常用的方法。里面有16个重载。能解决目前你能遇到的大部分问题。
msdn中对各个重载解释如下
名称 说明
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Byte[], Int32, IntPtr, Int32) 安全关键。将一维的托管 8 位无符号整数数组中的数据复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Char[], Int32, IntPtr, Int32) 安全关键。将数据从一维的托管字符数组复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Double[], Int32, IntPtr, Int32) 安全关键。将数据从一维的托管双精度浮点数组复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Int16[], Int32, IntPtr, Int32) 安全关键。将一维的托管 16 位有符号整数数组中的数据复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Int32[], Int32, IntPtr, Int32) 安全关键。将数据从一维的托管 32 位有符号整数数组复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Int64[], Int32, IntPtr, Int32) 安全关键。将一维的托管 64 位有符号整数数组中的数据复制到非托管内存指针。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Byte[], Int32, Int32) 安全关键。将数据从非托管内存指针复制到托管 8 位无符号整数数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Char[], Int32, Int32) 安全关键。将数据从非托管内存指针复制到托管字符数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Double[], Int32, Int32) 安全关键。将数据从非托管内存指针复制到托管双精度浮点数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Int16[], Int32, Int32) 安全关键。将非托管内存指针中的数据复制到托管 16 位有符号整数数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Int32[], Int32, Int32) 安全关键。将非托管内存指针中的数据复制到托管 32 位有符号整数数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Int64[], Int32, Int32) 安全关键。将非托管内存指针中的数据复制到托管 64 位有符号整数数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(IntPtr, Single[], Int32, Int32) 安全关键。将数据从非托管内存指针复制到托管单精度浮点数组。
公共方法 静态成员 受 Silverlight for Windows Phone 支持 受 Xbox 360 支持 Copy(Single[], Int32, IntPtr, Int32) 安全关键。将数据从一维的托管单精度浮点数组复制到非托管内存指针。
我们也可以使用共享内存的方式进行操作。部分代码如下
复制代码
//初始化返回图片的大小等信息
myContext = new VlcControlWpfRendererContext(width, height, System.Windows.Media.PixelFormats.Bgr24);
//创建共享内存区域
myBitmapSectionPointer = Win32Interop.CreateFileMapping(new IntPtr(-1), IntPtr.Zero, Win32Interop.PageAccess.ReadWrite, 0, myContext.Size, null);
//获取共享内存的首地址
map = Win32Interop.MapViewOfFile(myBitmapSectionPointer, Win32Interop.FileMapAccess.AllAccess, 0, 0, (uint)myContext.Size);
//把接收后的图片拷入共享内存区域
Win32Interop.CopyMemory(map, data, myContext.Size);
//把共享内存中的数组转换为图片
myBitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(myBitmapSectionPointer, myContext.Width, myContext.Height, myContext.PixelFormat, myContext.Stride, 0);
复制代码
这里是共享内存的辅助类 主要是一些api函数
其实Intptr本质也是一个Int,Int在c#中和Int32是一样的。所以基本上指针,Long,int在c#中都是int。只是这样些 方便大家知道他是c++中的什么类型,方便转换而已。
3,c++中的函数指针 与c#中的委托
这是c++中对函数指针的定义
typedef VOID (WINAPI *PUSERCALL)( PUCHAR pData, ULONG Length, PVOID pUserData );
对应c#中的例子如下
public delegate void PUSERCALL(IntPtr pData, uint Length, UInt32 pUserData);
4,我们知道int是占4个字节的。
下面这个是c++的一个方法
U_CAMER LONG WINAPI CAMER_GetPropery( HANDLE hCamer, _CMRCTL Propery );
假如我们把此函数翻译成c#中的下面这个函数
[DllImport("UCamer.dll", CallingConvention = CallingConvention.Winapi)]
public extern static Uint16 CAMER_GetPropery(IntPtr hCamer, CMRCTL Propery);
我们在c#调用此方法
uint16 m_HiWi_temp = (uint)BCamera.CAMER_GetPropery(m_hCamer, CMRCTL.OUT_SIZE);
发现一个很有趣的问题,此处调用没有问题。也有值,但是他是取的int32中4个字节的2个字节。
我们看原本c++对此函数的调用
*((PULONG)m_HiWi) = *((PULONG)m_Display) = CAMER_GetPropery( m_hCamer, OUT_SIZE );
m_hShow = Disp_Create( m_hWnd, m_HiWi[1], m_HiWi[0], m_nColor, (USERDRAW)((m_ReDrawLine == TRUE) ? DrawLine : NULL), this );
本来CAMER_GetPropery函数只返回了一个long类型。c++中通过指针的转换。把long类型转换成了 pulong,也是ulong的数组。
那c#中怎么我们该怎么调用呢
int m_HiWi_temp = BCamera.CAMER_GetPropery(m_hCamer, CMRCTL.OUT_SIZE);
byte[] m_byte_HiWi = BitConverter.GetBytes(m_HiWi_temp);
byte[] temp1 = new byte[2] { m_byte_HiWi[0], m_byte_HiWi[1] };
byte[] temp2 = new byte[2] { m_byte_HiWi[2], m_byte_HiWi[3] };
int width = BitConverter.ToInt16(temp1, 0);
int high = BitConverter.ToInt16(temp2, 0);
这里举这个例子是说c++有时真的就是返回一个int类型,但是在c++中可以轻松把int类型通过指针轻松转换成两个uint16的数组。所以c#中我们再转换的时候一定有注意了。
总结:其实数据类型的转换主要是对数据存储空间的转换,c++中的数据类型占用多大的空间,只要转换成c#中占同等空间的数据类型就可以了。只是c#看哪种数据类型在操作相应的操作方便些。
- c#WinForm程序调用vsto动态库,已解决
最近做一个vsto的项目,涉及到Form程序调用vsto动态库,弄了半天,搜了很多资料终于搞定了,把积累写下来备以后用.相关网址: https://stackoverflow.com/question ...
- C#调用C++动态库(dll)
在实际软件开发过程中,由于公司使用了多种语言开发,在C#中可能需要实现某个功能,而该功能可能用其他语言已经实现了,那么我们可以调用其他语言写好的模块吗?还有就是,由于C#开发好的项目,我们可以利用re ...
- C#总结(四)调用C++动态库
由于公司很多底层的SDK,都是C++开发,上层的应用软件却是C# Winform程序.在实际工作的过程中,就经常碰到了C# 程序调用C++ 动态库的问题.最近一直在和C++ 打交道,C# 怎么调用C+ ...
- Java调用dll动态库
最近项目里使用java调用dll动态库,因此研究了一下这方面的东西. 使用的工具包如下 <dependency> <groupId>net.java.dev.jna</g ...
- 【C#】 使用Gsof.Native 动态调用 C动态库
[C#] 使用Gsof.Native 动态调用 C动态库 一.背景 使用C# 开发客户端时候,我们经常会调用一些标准的动态库或是C的类库.虽然C# 提供的PInvoke的方式,但因为使用的场景的多变, ...
- python调用.net动态库
# python调用.net动态库 ### pythonnet简介------------------------------ pythonnet是cpython的扩展- pythonnet提供了cp ...
- Delphi XE7调用C++动态库出现乱码问题回顾
事情源于有个客户需使用我们C++的中间件动态库来跟设备连接通讯,但是传入以及传出的字符串指针格式都不正确(出现乱码或是被截断),估计是字符编码的问题导致.以下是解决问题的过程: 我们C++中间件动态库 ...
- 使用ctypes在Python中调用C++动态库
使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #in ...
- C# 调用C++动态库注意事项
C# 调用C++动态库注意事项 最近项目上需要在C#中调用C++,期间遇到不少坑,总结如下: 1.in const char* 对应C#中string 或 IntPtr 2.out const ...
随机推荐
- PHP执行过程
PHP执行过程 任何一种语言的源代码计算机都没有办法直接执行,需要转换成计算机能够识别的机器指令. PHP也是一门高级语言,也需编译(解释) PHP的解析过程: 1.请求源代码,进行词法解析, ...
- java集合 collection-list-LinkedList
import java.util.*; /* LinkedList:特有方法: addFirst(); addLast(); getFirst(); getLast(); 获取元素,但不删除元素.如果 ...
- 禁用Linux bash rm --force
防止无意的Linux bash rm --force 二.禁用rm -rf 因为rm -rf 删除文件的时候,经常会不小心将系统文件或者多个有用的目录删除掉.有两种方法:1,每次删除都用-i(inte ...
- springmvc学习(四)
1.使用 @CookieValue 绑定请求中的 Cookie 值 例子: java @RequestMapping(value="/testCookieValue") publi ...
- Headfirst设计模式的C++实现——状态模式(State)
state.h #ifndef _STATE_H_ #define _STATE_H_ class GumballMachine; class State { public: ; ; ; ; Stat ...
- NodeJS+Express+Socket.io的一个简单例子
关键字:NodeJS,Express,Socket.io. OS:Windows 8.1 with update pro. 1.安装NodeJS:http://nodejs.org/. 2.初始化一个 ...
- [转]python 之字典{}(Hashmap)
字典 python里的字典就像java里的HashMap,以键值对的方式存在并操作,其特点如下 通过键来存取,而非偏移量: 键值对是无序的: 键和值可以是任意对象: 长度可变,任意嵌套: 在字典里,不 ...
- com.mchange.v2.c3p0.ComboPooledDataSource
C3P0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSourc ...
- 《JavaScript设计模式与开发实践》-面向对象的JavaScript
设计模式 面向对象 动态类型语言 编程语言按照数据类型大体分为:静态类型语言和动态类型语言. 静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行时,待变量被赋予某个值之后,才 ...
- 使用ssh公钥实现免密码登录
使用ssh公钥实现免密码登录 ssh 无密码登录要使用公钥与私钥.linux下可以用用ssh-keygen生成公钥/私钥对,下面我以CentOS为例. 有机器A(10.207.160.34),B(10 ...