当对c++几种调用方式有了解以后我们可以试着写个c++动态连接库了,我们现在来写个简单的c++求和函数并把它封装成dll,供以后的c#调用

我们写dll的时候,个人认为,要写就要把dll写好,写标准,别的地方才能用得方便,接下来就带你们写个标准的dll

第一步,确定你要写哪些方法,根据这些方法我们创建一个头文件,我这边主要写个add();

例子如下:head.h

#ifdef api
#else
#define api extern "C" _declspec(dllimport)
#endif api int _stdcall add(int a,int b);

第二步:写函数主体部分add.dll

#define api extern "C" _declspec(dllexport)

#include "head.h"
#include "windows.h" int _stdcall add(int a,int b)
{
return a+b;
}

第三步:定义输出函数名文件 add.def(此文件先创建再添加到工程)

LIBRARY add/*这个名字要和输出dll名字一致*/
EXPORTS
add

编译连接,在debug目录下就可以找到生成的dll啦!

接下来我们开始在c#中调用这个dll

 [DllImport("RFDLL.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int add(int a, int b); public void ProjectMethod()
{
MessageBox.Show("5+5="+add(5,5).ToString());
}

到此,最简单最标准的dll调用就完成啦!

在调用c++过程中,你会遇到很多莫名的错误,像堆栈不对称错误是很多新手最容易犯错的,下面我就简单说说这类问题怎么解决

从.NET1.1升级到.NET2.0时出现的PInvokeStackImbalance错误
微软官方的解释(http://msdn2.microsoft.com/zh-cn/library/0htdy0k3.aspx)
如果 CLR 检测到平台调用之后的堆栈深度与 DllImportAttribute 属性指定的调用约定中以及托管签名的参数声明中提供的预期堆栈深度不匹配,则将激活 PInvokeStackImbalance 托管调试助手 (MDA)。
下面将举一个具体的例子
PCCamera类(UserLib.Device.PCCamera摄像头类)在从.NET1.1升级到.NET2.0时出现的PInvokeStackImbalance错误:
检测到 PInvokeStackImbalance
Message: 对 PInvoke 函数“WindowsApplication1!UserLib.Device.PCCamera::SendMessage”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。
错误首次发生在这一行代码: SendMessage(hWndC, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
经过分析发现所有调用SendMessage函数的地方都会出现以上错误
于是查看DLLImport:
[DllImport("User32.dll")]
private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, long lParam);
原来是因为WinAPI的long类型是32位的,而C#的long是64位的,这就导致堆栈不对称,引发错误.
在.NET2.0中加入了MDA(managed debugging assistant), 在平台调用时后会检查栈的指针, 如果发现不平衡, 就会抛出PInvokeStackImbalance异常; 而在.NET1.1中不会检查, 所以不会捕获到异常, 但在运行时会导致不稳定.
解决方法:
将最后一个”long lParam” 改为 “int wParam”, 因为C#中int是32位的. 并且将之后有涉及到SendMessage函数的参数适当地转成int型就可以了.
但是, 之后查阅了资料发现先前的解决方案还有不合适的地方, 应该将其中的 ”wParm” 和 ”lParm” 参数的类型都转成IntPtr类型,并且将后面涉及到的参数的 ”0” 改为 “IntPtr.Zero”. 因为如果使用int类型,那么这段代码在64位的Windows上面将会无法正常运行.
总结:
我们在调用WinAPI时要特别小心, 因为WinAPI和C#的数据类型不是完全一样, 就好像在WinAPI中的long类型在C#中就是int类型, 如果没有处理好类型问题, 就很可能会导致堆栈的不平衡,引发PInvokeStackImbalance错误, 但是这类错误在.NET1.1下不会被暴露出来, 所以在从.NET1.1升级到.NET2.0时要特别注意此类问题.

c#调用c++ dll(二)的更多相关文章

  1. c# 调用c++dll二次总结

    1.pinvoke结构不对称,添加语句(网上有) 2.含回调函数,成员参数的结构体必须完全,尽管自己用不到. 3.加深对c++指针的理解.一般情况下,类型加*等效于c++中的ref.但对于short* ...

  2. c# 调用c++DLL方法及注意事项

    引用命名空间 using System.Runtime.InteropServices 调用方法: 一.静态加载 用DllImprot方式来加载c++DLL.如下格式: //对应c++方法 //voi ...

  3. 【JNI】OPUS压缩与解压的JNI调用(.DLL版本)

    OPUS压缩与解压的JNI调用(.DLL版本) 一.写在开头: 理论上讲,这是我在博客园的第一篇原创的博客,之前也一直想找个地方写点东西,把最近做的一些东西归纳总结下,但是一般工程做完了一高兴就把东西 ...

  4. Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)

    文章目录:                   1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...

  5. C#调用VC dll输出参数

    最近做项目需要把以前Vc写的程序整合到VS2005来,用c#写的,以前VC的动态连接库写好了,重写比较麻烦,让C#调用VC dll就好了.但碰到了一个问题:VC中作为输出参数的char*类型的变量应该 ...

  6. 巧用C#做中间语言 实现Java调用.net DLL

    本文将详细为大家介绍一个java调用.net DLL的方法,以实现特殊的客户的特殊要求:“在Java项目中必须使用其提供的用.net写的DLL加密机制!” 环境与工具: ◆.net framework ...

  7. C# 调用外部dll(转)

    C# 调用外部dll   一.      DLL与应用程序 动态链接库(也称为DLL,即为"Dynamic Link Library"的缩写)是Microsoft Windows最 ...

  8. C#调用外部DLL介绍及使用详解

    一.      DLL与应用程序 动态链接库(也称为DLL,即为“Dynamic Link Library”的缩写)是Microsoft Windows最重要的组成要素之一,打开Windows系统文件 ...

  9. SOE 中调用第三方dll

    一.简介 在利用soe实现server的扩展的时候,有些时候,需要调用第三方的dll库.官网中给出了明确的说明,soe中是可以添加第三方的dll文件,但是一直没有测试.按照官方的步骤应该是一个非常的简 ...

随机推荐

  1. Java Spring 中你不知道的注入方式

    前言 在Spring配置文件中使用XML文件进行配置,实际上是让Spring执行了相应的代码,例如: 使用<bean>元素,实际上是让Spring执行无参或有参构造器 使用<prop ...

  2. ECSHOP在线手册布局参考图--通用活动页 group_list.dwt等

        A.购物车 1,设置方法 程序自动读取购物车的商品数量 2,代码相关 cart.lbi 中 {insert_scripts files='transport.js'} <div clas ...

  3. 人工智能-有限状态机(FSM)的学习

    首先声明:此文源于本人最近学习的一本书 <游戏人工智能编程案例精粹> FSM的定义: 一个有限状态机是一个设备,或是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作 ...

  4. html5非常火,他究竟与html4有何差别?

    HTML5是HTML标准的下一个版本号.越来越多的程序猿開始HTML5来构建站点.假设你同一时候使用HTML4和HTML5的话 ,你会发现用HTML5从头构建.比从HTML4迁移到HTML5要方便非常 ...

  5. hdu 5441 Travel 离线带权并查集

    Travel Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5441 De ...

  6. android内核读取file文件

    内核读取file文件的方法: char* file_read(const char * file_path) { struct file *file = NULL; //保存打开文件的文件指针变量 s ...

  7. iOS开发——适配篇&iOS9适配

    iOS9适配 1. Demo1_iOS9网络适配_ATS:改用更安全的HTTPS [摘要]iOS9把所有的http请求都改为https了:iOS9系统发送的网络请求将统一使用TLS 1.2 SSL.采 ...

  8. 学习笔记之Java程序设计实用教程

    Java程序设计实用教程 by 朱战立 & 沈伟 学习笔记之JAVA多线程(http://www.cnblogs.com/pegasus923/p/3995855.html) 国庆休假前学习了 ...

  9. Jordan Lecture Note-3: 梯度投影法

    Jordan Lecture Note-3:梯度投影法 在这一节,我们介绍如何用梯度投影法来解如下的优化问题: \begin{align} \mathop{\min}&\quad f(x)\n ...

  10. Linux添加环境变量与GCC编译器添加INCLUDE与LIB环境变量

    对所有用户有效在/etc/profile增加以下内容.只对当前用户有效在Home目录下的.bashrc或.bash_profile里增加下面的内容:(注意:等号前面不要加空格,否则可能出现 comma ...