C#调用非托管DLL函数

 [url=javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();]收藏[/url]Demo
#region C#捕获当前屏幕的例子
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的函数如下:


//声明一个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 // 光栅的处理数值 
  ) ;


C# 如何使用 DllImport Attribute(属性) 标识 DLL 和函数
System.Runtime.InteropServices.DllImportAttribute

从托管代码中访问非托管 DLL 函数之前,需要知道该函数的名称以及该 DLL 的名称,然后为 DLL 的非托管函数 编写 托管定义。

它将用到 static 和 extern 修饰符,此类型的公共静态成员对于多线程操作是安全的。

DllImport 属性提供非托管 DLL 函数的调用信息。


示例1  简单DllImportAttribute 应用

using System.Runtime.InteropServices;
[DllImport("user32.dll")]     
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
示例2  如何将 DllImportAttribute 应用于方法。
using System.Runtime.InteropServices;
[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;
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

// cmdll.c
// compile with: /LD /MD
int __declspec(dllexport) MyMethod(int i)
{
   return i*10;
}

使用命令行编译 CM.cs: 
csc CM.cs
这将创建可执行文件 CM.exe。

文件:CM.cs
// 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 接口。

转载于:https://www.cnblogs.com/jiangC/archive/2010/10/08/2769075.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值