使用C#调用非托管DLL函数
由于工作需要,学习了GDI+编程的一些知识。其中看到了一个比较好的Demo,深入的了解后,却发现自己对如何用C#调用非托管DLL函数也有了更好的理解,于是整理了一下,跟大家一起分享。
引用: 用C#来捕获屏幕的源程序代码(Capture.cs)
using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Drawing.Imaging ;
public class Form1 : Form
{
private Button button1 ;
private System.ComponentModel.Container components = null ;
public Form1 ( )
{
//初始化窗体中的各个组件
InitializeComponent ( ) ;
}
// 清除程序中使用过的资源
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
private void InitializeComponent ( )
{
button1 = new Button ( );
SuspendLayout ( ) ;
button1.Location = new System.Drawing.Point ( 64 , 40 ) ;
button1.Name = "button1" ;
button1.Size = new System.Drawing.Size ( 80 , 32 ) ;
button1.TabIndex = 0 ;
button1.Text = "捕获" ;
button1.Click += new System.EventHandler ( button1_Click ) ;
AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ;
ClientSize = new System.Drawing.Size ( 216 , 125 ) ;
Controls.Add ( button1 ) ;
MaximizeBox = false ;
MinimizeBox = false ;
Name = "Form1" ;
Text = "C#捕获当前屏幕!" ;
ResumeLayout ( false ) ;
}
//声明一个API函数
[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目标 DC的句柄
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的句柄
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光栅的处理数值
) ;
static void Main ( )
{
Application.Run ( new Form1 ( ) ) ;
}
private void button1_Click ( object sender , System.EventArgs e )
{
//获得当前屏幕的大小
Rectangle rect = new Rectangle ( ) ;
rect = Screen.GetWorkingArea ( this ) ;
//创建一个以当前屏幕为模板的图象
Graphics g1 = this.CreateGraphics ( ) ;
//创建以屏幕大小为标准的位图
Image MyImage = new Bitmap ( rect.Width , rect.Height , g1 ) ;
Graphics g2 = Graphics.FromImage ( MyImage ) ;
//得到屏幕的DC
IntPtr dc1 = g1.GetHdc ( ) ;
//得到Bitmap的DC
IntPtr dc2 = g2.GetHdc ( ) ;
//调用此API函数,实现屏幕捕获
BitBlt ( dc2 , 0 , 0 , rect.Width , rect.Height , dc1 , 0 , 0 , 13369376 ) ;
//释放掉屏幕的DC
g1.ReleaseHdc ( dc1 ) ;
//释放掉Bitmap的DC
g2.ReleaseHdc ( dc2 ) ;
//以JPG文件格式来保存
MyImage.Save ( @"c:/Capture.jpg" , ImageFormat.Jpeg );
MessageBox.Show ( "当前屏幕已经保存为C盘的capture.jpg文件!" ) ;
}
}
#endregion
上面的例子中,应用C#调用非托管DLL的函数如下:
[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目标 DC的句柄
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的句柄
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光栅的处理数值
) ;
在上面这段代码中,我将以分别介绍 DllImportAttribute属性、extern关键字 、IntPtr类型 这三个方面,向大家介绍如何应用C#调用非托管DLL函数。
C# 如何使用 DllImport Attribute(属性) 标识 DLL 和函数
System.Runtime.InteropServices.DllImportAttribute
从托管代码中访问非托管 DLL 函数之前,需要知道该函数的名称以及该 DLL 的名称,然后为 DLL 的非托管函数 编写 托管定义。
它将用到 static 和 extern 修饰符,此类型的公共静态成员对于多线程操作是安全的。
DllImport 属性提供非托管 DLL 函数的调用信息。
示例1 简单DllImportAttribute 应用
[DllImport("user32.dll")]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
示例2 如何将 DllImportAttribute 应用于方法。
[DllImport( "KERNEL32.DLL",
EntryPoint="MoveFileW",
SetLastError=true,
CharSet=CharSet.Unicode,
ExactSpelling=true,
CallingConvention=CallingConvention.StdCall
)
]
public static extern bool MoveFile(String src, String dst);
参数说明:
EntryPoint 指定要调用的 DLL 入口点。
SetLastError 判断在执行该方法时是否出错(使用 Marshal.GetLastWin32Error API 函数来确定)。
C#中默认值为 false。
CharSet 控制名称及函数中字符串参数的编码方式。默认值为 CharSet.Ansi。
ExactSpelling 是否修改入口点以对应不同的字符编码方式。
CallingConvention 指定用于传递方法参数的调用约定。默认值为 WinAPI。
该值对应于基于32位Intel平台的 __stdcall。
BestFitMapping 是否启用最佳映射功能,默认为 true。
最佳映射功能提供在没有匹配项时,自动提供匹配的字符。
无法映射的字符通常转换为默认的“?”。
PreserveSig 托管方法签名是否转换成返回 HRESULT,默认值为 true(不应转换签名)。
并且返回值有一个附加的 [out, retval] 参数的非托管签名。
ThrowOnUnmappableChar 控制对转换为 ANSI '?' 字符的不可映射的 Unicode 字符引发异常。
C# 关键字 extern 的使用
public static extern int MyMethod(int x);
外部修饰符 extern 用于指示外部实现方法,常与 DllImport 属性一起使用(DllImport 属性提供非托管 DLL 函数的调用信息)。
若将 abstract 和 extern 修饰符一起使用来修改同一成员是错误的。extern 将方法在 C# 代码的外部实现,而 abstract 意味着在此类中未提供此方法的实现。
因为外部方法声明不提供具体实现,所以没有方法体;
此方法声明只是以一个分号结束,并且在签名后没有大括号{ }。
示例3 接收用户输入的字符串并显示在消息框中
程序从 User32.dll 库导入的 MessageBox 方法。
using System.Runtime.InteropServices;
class MyClass
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
public static int Main()
{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}
}
运行结果: 输入"Hello"文本后,屏幕上将弹出一个包含该文本的消息框。
Enter your message: Hello
示例4 调用DLL进行计算
该示例使用两个文件 CM.cs 和 Cmdll.c 来说明 extern。
C 文件是从 C# 程序中调用的外部 DLL。
使用 Visual C++ 命令行将 Cmdll.c 编译为 DLL:
cl /LD /MD Cmdll.c
文件:Cmdll.c
// compile with: /LD /MD
int __declspec(dllexport) MyMethod(int i)
{
return i*10;
}
使用命令行编译 CM.cs:
csc CM.cs
这将创建可执行文件 CM.exe。
文件:CM.cs
using System;
using System.Runtime.InteropServices;
public class MyClass
{
[DllImport("Cmdll.dll")]
public static extern int MyMethod(int x);
public static void Main()
{
Console.WriteLine("MyMethod() returns {0}.", MyMethod(5));
}
}
运行此程序,MyMethod 将值 5 传递到 DLL 文件,该文件将此值乘以 10 返回。
运行结果:MyMethod() returns 50.
IntPtr 类型的说明
对于平台调用,应让参数为 IntPtr 类型,而不是 String 类型。使用 System.Runtime.InteropServices.Marshal 类所提供的方法,可将类型手动转换为字符串并手动将其释放。
IntPtr 类型被设计成整数,其大小适用于特定平台。
在 32 位硬件和操作系统中将是 32 位;
在 64 位硬件和操作系统中将是 64 位。
IntPtr 类型由支持指针的语言使用,并作为在支持与不支持指针的语言间引用数据的一种通用方式。它也可用于保持句柄。例如,IntPtr 的实例广泛地用在 System.IO.FileStream 类中来保持文件句柄。
IntPtr 类型符合 CLS,而 UIntPtr 类型却不符合。只有 IntPtr 类型可用在公共语言运行库中。此类型实现 ISerializable 接口。
来源:http://www.cnblogs.com/xugang/archive/2007/12/23/1011597.html
使用C#调用非托管DLL函数相关推荐
- C#调用非托管dll文件
C#调用非托管dll文件 C#中如何调用动态链接库DLL C#对两种类型动态库的使用 1.托管 2.非托管 C#调用非托管dll 一.C++头文件样子 解决方案: 二.使用DLLImport类 三.二 ...
- 关于C#调用非托管DLL,报“内存已损坏的”坑,坑,坑
因客户需求,与第三方对接,调用非托管DLL,之前正常对接的程序,却总是报"内存已损坏的异常",程序进程直接死掉,折腾到这个点(2018-05-11 00:26),终于尘埃落定,直接 ...
- C#调用非托管Dll
最近在项目中碰到需要调用非托管C++生成的dll,下面将自己遇到的问题,以及解决的办法总结如下: 1. 问题: 我们通常去映射dll的方法是使用 public c ...
- java 托管 非托管_java jni调用 非托管 dll
Step1: 编写java类,e.g.: //filename: HelloWorld.java public class HelloWorld{ public native void display ...
- 托管代码C#调用非托管C++ API, 封送嵌套结构体数组
一.前言: 最近这两天由于项目需要,提供给客户的C++ 动态库需要返回自定义结构体数组,网上也查了很多资料, 推荐一本书, <精通.NET互操作:P/Invoke.C++ Interop和COM ...
- C#调用非托管C++DLL:直接调用法
在实际软件开发过程中,由于公司使用了多种语言开发,在C#中可能需要实现某个功能,而该功能可能用其他语言已经实现了,那么我们可以调用其他语言写好的模块吗?还有就是,由于C#开发好的项目,我们可以利用re ...
- 关于Dll、Com组件、托管dll和非托管dll的理解
Com组件和dll区别: 1.普通dll不能通过regsvr32.exe来注册,而Com组件能通过regsvr32.exe注册. 2.Com组件是微软的一个协议,满足com组件协议的dll文件就是co ...
- C#调用非托管DLL--[1]基本步骤
托管DLL和非托管DLL的区别 狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环境生成的DLL文件. 托管DLL文件,可以在Dotnet环境通过 " ...
- Window Services的调试和非托管dll的引用及其他一些注意问题
一个asp.net项目,客户提出需求,需要增加即时短信提醒功能:因为项目中使用到GPRS模块做无线通讯,还可以用作发送短信,就用了这个GPRS模块发短信提醒: 这个即时短信提醒功能,计划用window ...
最新文章
- 接口访问次数_系统运行缓慢,CPU 100%,Full GC次数过多,这一招帮你全搞定
- 又一个创业者自杀:心生郁结,被曝曾卖房给员工发工资
- 解决eureka注册时使用ip而不是hostname
- maven重新指定仓库存储路径
- leetCode刷题(使用链表做加法)
- [轉].NET项目是否有必要升级到.NET 3.5 + VS 2008
- java利用栈求复杂表达式_java中的栈Stack的基本使用和应用(二) ——利用栈计算合法的算术表达,中缀表达式转后缀表达式...
- matlab 有公式 变量,matlab两个变量拟合公式x=0.40.450.50.550? 爱问知识人
- ZOJ-3953 Intervals,t
- 安装VMware时提示无效驱动器:D:\的解决办法
- OpenCore引导配置说明第十一版说明-基于OpenCore-0.6.4正式版
- 20张Python高清数据分析全知识地图,数据分析发展路线
- Learn OpenCV之Heatmap
- bootmgr快速修复win7_「科普」UEFI+GPT、Legacy+MBR引导模式介绍 引导修复
- ORACLE 考试的流程
- 阿里云盘内测邀请码是多少?阿里云盘邀请码获得方法
- 微软azure DNS服务器,什么是 Azure 专用 DNS?
- Smarty安装教程
- acm CodeForces 546A
- Git的基本概念和SourceTree的使用
热门文章
- 洛谷——P1423 小玉在游泳
- debian mysql目录_debian Squeeze配置apache php mysql环境,debian中apache目录结
- python循环三次跳出循环_Python3 跳出多重循环 for...else...
- error40无法打开到sql_技术分享|初识SQL优化之执行计划查看分析
- mysql-8.0.11安装步骤
- 【376天】每日项目总结系列113(2018.02.16)
- 在通往VR内容的道路上,音乐将成为一项重要助力
- 根据on,获取选中的元素
- sed个人习惯用法总结
- express : 无法将“express”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。express: command not found