在合作开发时,C#时常需要调用C++DLL,当传递参数时时常遇到问题,尤其是传递和返回字符串是,现总结一下,分享给大家:

VC++中主要字符串类型为:LPSTR,LPCSTR, LPCTSTR, string, CString, LPCWSTR, LPWSTR等
但转为C#类型却不完全相同。

主要有如下几种转换:

将string转为IntPtr:IntPtr System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)

将IntPtr转为string:string System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)

类型对照:

BSTR ---------  StringBuilder

LPCTSTR --------- StringBuilder

LPCWSTR ---------  IntPtr

handle---------IntPtr

hwnd-----------IntPtr

char *----------string

int * -----------ref int

int &-----------ref int

void *----------IntPtr

unsigned char *-----ref byte

Struct需要在C#里重新定义一个Struct

CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str);

注意在每个函数的前面加上public static extern +返回的数据类型,如果不加public ,函数默认为私有函数,调用就会出错。

在C#调用C++ DLL封装库时会出现两个问题:

1. 数据类型转换问题 
2. 指针或地址参数传送问题

首先是数据类型转换问题。因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际上是将C++的数据类型与.NET的基本数据类型进行对应。

例如C++的原有函数是:

int __stdcall FunctionName(unsigned char param1, unsigned short param2)

其中的参数数据类型在C#中,必须转为对应的数据类型。如:

[DllImport(“ COM DLL path/file ”)] 
extern static int FunctionName(byte param1, ushort param2)

因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。其中的方法FunctionName必须声明为静态外部函数,即加上extern static声明头。我们可以看到,在调用的过程中,unsigned char变为了byte,unsigned short变为了ushort。变换后,参数的数据类型不变,只是声明方式必须改为.NET语言的规范。

我们可以通过下表来进行这种转换:

Win32 Types 
CLR Type

char, INT8, SBYTE, CHAR 
System.SByte

short, short int, INT16, SHORT 
System.Int16

int, long, long int, INT32, LONG32, BOOL , INT 
System.Int32

__int64, INT64, LONGLONG 
System.Int64

unsigned char, UINT8, UCHAR , BYTE 
System.Byte

unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t 
System.UInt16

unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT 
System.UInt32

unsigned __int64, UINT64, DWORDLONG, ULONGLONG 
System.UInt64

float, FLOAT 
System.Single

double, long double, DOUBLE 
System.Double

之后再将CLR的数据类型表示方式转换为C#的表示方式。这样一来,函数的参数类型问题就可以解决了。

现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变量,怎么办?

对于这种情况可以使用C#提供的非安全代码来进行解决,但是,毕竟是非托管代码,垃圾资源处理不好的话对应用程序是很不利的。所以还是使用C#提供的ref以及out修饰字比较好。

同上面一样,我们也举一个例子:

int __stdcall FunctionName(unsigned char &param1, unsigned char *param2)

在C#中对其进行调用的方法是:

[DllImport(“ file ”)] 
extern static int FunctionName(ref byte param1, ref byte param2)

看到这,可能有人会问,&是取地址,*是传送指针,为何都只用ref就可以了呢?一种可能的解释是ref是一个具有重载特性的修饰符,会自动识别是取地址还是传送指针。

在实际的情况中,我们利用参数传递地址更多还是用在传送数组首地址上。 
如:byte[] param1 = new param1(6);

在这里我们声明了一个数组,现在要将其的首地址传送过去,只要将param1数组的第一个元素用ref修饰。具体如下:

[DllImport(“ file ”)] 
extern static int FunctionName(ref byte param1[1], ref byte param2) 
  
文章出处:DIY部落(http://www.diybl.com/course/3_program/c++/cppjs/200886/134816.html)

C# 中调用DLL

为了能用上原来的C++代码,只好研究下从C# 中调用DLL
首先必须要有一个声明,使用的是DllImport关键字: 
包含DllImport所在的名字空间 
using System.Runtime.InteropServices; 
public class XXXX{

[DllImport(“MyDLL.dll")] 
public static extern int mySum (int a,int b); 
}

[DllImport(“MyDLL.dll")] 
public static extern int mySum (int a,int b); 
代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中 
在调用的时候 
在类中的时候 直接   mySum(a,b);就可以了 
在其他类中调用: XXXX. mySum(a,b); 
 
[DllImport(“MyDLL.dll”)]在申明的时候还可以添加几个属性 
[DllImport(“MyDLL.dll", EntryPoint=" mySum ",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall) 

EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。 
CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE) 
CallingConvention指示入口点的函数调用约定(默认WINAPI)(上次报告讲过的) 
SetLastError 指示被调用方在从属性化方法返回之前是否调用 SetLastError Win32 API 函数 (C#中默认false )

int 类型 
[DllImport(“MyDLL.dll")] 
//返回个int 类型 
public static extern int mySum (int a1,int b1); 
//DLL中申明 
extern “C” __declspec(dllexport)  int WINAPI mySum(int a2,int b2) 

//a2 b2不能改变a1 b1
//a2=..
//b2=...
 return a+b; 
}

//参数传递int 类型 
public static extern int mySum (ref int a1,ref int b1); 
//DLL中申明 
extern “C” __declspec(dllexport)  int WINAPI mySum(int *a2,int *b2) 

//可以改变 a1, b1
*a2=...
*b2=...
 return a+b; 
}

DLL 需传入char *类型 
[DllImport(“MyDLL.dll")] 
//传入值 
public static extern int mySum (string  astr1,string bstr1); 
//DLL中申明 
extern “C” __declspec(dllexport)  int WINAPI mySum(char * astr2,char * bstr2) 

//改变astr2 bstr 2  ,astr1 bstr1不会被改变
 return a+b; 
}

DLL 需传出char *类型 
[DllImport(“MyDLL.dll")] 
// 传出值
public static extern int mySum (StringBuilder abuf, StringBuilder bbuf ); 
//DLL中申明 
extern “C” __declspec(dllexport)  int WINAPI mySum(char * astr,char * bstr) 

//传出char * 改变astr bstr -->abuf, bbuf可以被改变
 return a+b; 

 
DLL 回调函数

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)

using System; 
using System.Runtime.InteropServices; 
public delegate bool CallBack(int hwnd, int lParam); //定义委托函数类型 
public class EnumReportApp 

[DllImport("user32")] 
public static extern int EnumWindows(CallBack x, int y); 
public static void Main() { 
CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0); 

public static bool Report(int hwnd, int lParam) 

Console.Write("Window handle is "); 
Console.WriteLine(hwnd); return true; 

}

DLL  传递结构  
BOOL PtInRect(const RECT *lprc, POINT pt);

using System.Runtime.InteropServices; 
[StructLayout(LayoutKind.Sequential)] 
public struct Point {
 public int x; 
public int y;
 } 
[StructLayout(LayoutKind.Explicit)] 
 public struct Rect 
 { 
[FieldOffset(0)] public int left; 
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right; 
[FieldOffset(12)] public int bottom;
 } 
Class XXXX { 
 [DllImport("User32.dll")] 
public static extern bool PtInRect(ref  Rect r, Point p); 
 }

DLL 回调函数,传递结构 想看的msdn里面都有专题介绍,看的我都是晕晕的:)

其他参考请搜索:

在C#程序设计中使用Win32类库
C#中调用C++托管Dll
如何在C#中加载自己编写的动态链接库

相关文章:Creating a P/Invoke Library

能用上DLL以后感觉还是很好的,原来的C++代码只要修改编译通过就可以了,
高兴没多久,发现.net2005居然可以用VB,VC开发智能设备项目,可以创建MFC智能设备项目
晕晕,难道可以直接用MFC来开发smartphone的程序了,赶紧看看,,,

C#调用C++Dll封装时遇到的一系列问题 参考相关推荐

  1. C#调用C++Dll封装时遇到的一系列问题

    最近帮底层开发的同时用C#重新封装一下dll,也就是用C#类来封装C++Dll里的方法,以供用户使用. 之前也用到过类似的应用,大多数问题都出在类型转换上,但是这次的应用层出不穷,所以在这里总结一下, ...

  2. [轉]c#简单调用DELPHI DLL封装窗体

    http://www.cnblogs.com/el-net/archive/2008/10/13/1309940.html dllimport Delphi dll dllimport dll Del ...

  3. c#调用c++dll接口及回调函数

    在合作开发时,C#时常需要调用C++DLL,当传递参数时时常遇到问题,尤其是传递和返回字符串是,现总结一下,分享给大家: VC++中主要字符串类型为:LPSTR,LPCSTR, LPCTSTR, st ...

  4. C#时常需要调用C++DLL

    在合作开发时,C#时常需要调用C++DLL,当传递参数时时常遇到问题,尤其是传递和返回字符串是,现总结一下,分享给大家: VC++中主要字符串类型为:LPSTR,LPCSTR, LPCTSTR, st ...

  5. C++ 中 对dll二次封装时,加载第三方库dll时 LoadLibrary 时错误代码126

    前提:  第三方dll名为 A.dll   我自己对A.dll又重新封装了一个B.dll  ,然后使用C程序进行测试,发现在B.dll中有加载A.dll的地方出错,错误代码为126. 具体代码如下: ...

  6. qt采用C++/CLI 方式调用C#dll的封装方法

    在qt中调用C++dll一般都可以直接使用,但是在调用C#版dll时,就有些麻烦了.本文采用C++/cli封装C#的dll的方式.实现了qt调用C#dll的方法. .h文件 #pragma once ...

  7. 多个类的DLL封装及调用

    网上大多是将函数封装成dll的教程,类的封装也是基本相似的. 创建DLL 在VS2010中新建一个win32->dll工程.如我建立的工程名为FaceDLL 添加facedll.h的头文件(里面 ...

  8. C/C++ DLL封装及调用

    目录 操作步骤 1. 创建dll 2. 创建测试程序 需求:C开发的控制台程序封装为dll,用于C++程序调用 开发环境:VS 2013 Pro 操作步骤 1. 创建dll 新建工程:C/C++ -& ...

  9. 调用matlab dll报错,c#调用MATLAB的dll时出错

    MATLAB是2014a,VS是2013的. 在C#中调用matlab生成的dll文件时,ceshi.Class1 yaoyi = new Class1();  对类进行实例时,抛出异常.异常为: 未 ...

最新文章

  1. Java 8快多少?
  2. java 发送cookie_java – 如何在response.sendRedirect()之后发送cookie?
  3. cocos2dx视频教程进阶篇--第1天--吃西瓜游戏。
  4. c语言 mysql 查询数字_c语言mysql查询数据库
  5. 每日一九度之题目1021:统计字符
  6. 〖Python 数据库开发实战 - MySQL篇④〗- MacOS 配置 MySQL 环境变量及安装MySQL图形化工具 - MySQL Workbench
  7. 【saas公司案例】易快报与浦发云资金
  8. 哪些植物最吸毒?这份植物“吸毒”手册千万要收好!
  9. android 清空剪贴板,清空剪贴板app
  10. 如何检查网站死链接 分享检查死链接方法
  11. Andriod OpenGL 教程 10 - 3D世界
  12. php phpunit_framework_testcase,开始使用PHPUnit
  13. 如何在 Ubuntu 中禁用 motd 欢迎消息
  14. 自己计算机的网络密码,怎么知道自己宽带上网的用户名密码,我打开电脑就能直接上网。...
  15. 【分享-免费OCR工具 在线+移动端】免费在线图片多国文字识别
  16. 关于Gradle新版插件依赖方式
  17. reids 5.0.4 cluster集群模式部署实操。
  18. 毕业设计-基于微信小程序的实验室信息管理系统
  19. 二进制转十进制 8421运算法
  20. android+iphone+共用字体,【报Bug】苹果和安卓手机 字体大小颜色字重都一样 效果却不同...

热门文章

  1. win10系统中环境变量path变成一行显示(配置环境)
  2. php+ok,php fscokopen实现数据异步调用代码
  3. oracle10g密钥,Oracle10G透明数据加密技术如何使用呢?
  4. java 线程交替输出,[java]java经典问题之线程交替打印数字
  5. mysql 开启innodb win版本_MySQL安装与启动——Windows系统下
  6. 这100道Linux常见面试题,看看你会多少?
  7. VHDL编码器和译码器的设计
  8. android getwindow 在fragment不能使用,Android Fragment 布局使用 fitsSystemWindows = true 无效解决方案...
  9. oracle11g nid,Oracle工具之nid命令的使用
  10. html循环自动点击事件,js循环遍历ul中li的点击事件,给给选中li添加css