好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C# PInvoke(DllImport使用) 进阶教程

C# PInvoke(DllImport使用) 进阶教程

# PInvoke(DllImport使用) 进阶教程(一)

 

目录导航:

1. 前言

2. 编写目的

3. 原理庖析

4. 使用P/Invoke

一、前言 (引用 截图 )

  

二、编写目的

            我们曾经熟悉的WindowsAPI, 我们曾经花费了大量精力写的代码,难道我们就要轻易放弃吗 不过当下微软已经把向下兼容性放在很重要的位置.
      C#程序员使用已有的代码来作为自己程序的一部分是很普通的事情.所以 NET 为了解决使用已有代码的问题作了很多方面的工作.比如说对于已有的C++
  代码 你可以使用 C++ 托管扩展 (managed extensions) 来进行封装 ,以及将会着重讲到的P/Invoke。

三、原理庖析

1) P/Invoke是什么?

       P/Invoke的全称是Platform Invoke (平台调用) 它实际上是一种函数调用机制通 过P/Invoke我们就可以调用非托管DLL中的函数 
  实际上很多NET基类库中定义的类 型内部部调用了从 Kernel32.dll , User32.dll , gdi32.dll 等非托管DLL中导出的函数。

2) 看一个最简单的例子

      //这个只是设置鼠标相对于屏幕位置的系统函数,当然还有许多API函数的位置是需 要公式计算的(例如:SendInput函数,位于user32.dll内)。

     [ DllImportAttribute (" user32.dll ",  EntryPoint =" SetCursorPos ")]

     [ return :MarshalAsAttribute ( UnmanagedType . Bool )]//可写可不写,定义如何封送返回参数

  public static extern  bool SetCursorPos(int X, int Y) ;

3) P/Invoke的过程(引用图)


   P/Invoke依次执行以下操作.(理解重要)

  1 查找包含该函数的非托管DLL

  2 将该非托管DLL加载到内存中

  3 查找函数在内存中的地址并将其参数按照函数的调用约定压栈

  注意事项:只在第一次调用函数时,才会查找和加载非托管DLL并查找函数在内存中的地址。

  4 将控制权转移给非托管函数

  注意:当非托管函数产生异常时,P/Invoke会将异常传递给托管调用方。但需要设置相关特性,后面 章节会有相关说明。

四、初次使用P/Invoke

  1). 要使用 P /Invoke 我们需要描述调用函数的原型. CLR 会使用这些信息进行调用.

    下面用一个简单的例子来说明如何使用 P /Invoke  在这个例子中我们将调用 SetCursorPos   这个 API 函数来做说明。

    该函数的定义是这样描述的:

?

函数功能:该函数把光标移到屏幕的指定位置。如果新位置不在由 ClipCursor函数设置的屏幕矩形区域之内,则系统自动调整坐标,使得光标在矩形之内。

 

函数原型:BOOL SetCursorPos( int X, int Y);  

 

参数:X:指定光标的新的X坐标,以屏幕坐标表示。Y:指定光标的新的Y坐标,以屏幕坐标表示。   

 

返回值:如果成功,返回非零值;如果失败,返回值是零  

 

备注:该光标是共享资源,仅当该光标在一个窗口的客户区域内时它才能移动该光标。

  2).开始使用

        为了在C#中正确的表示以上声明.我们需要将Win32 类型转换为对应的C#类型.int是四个字节的整数我们可以使用 int或者 uint .
    在这里两者的区别并不大,我选择使用int. 一来int更常用,二来 int是CLS兼容类型(这意味着在所有基于NET都具有这个类型). BOOL对应的则是bool .
    好了,我们可以写出 SetCursorPos(...) 函数的C#版本定义了

?

public static extern bool SetCursorPos( int X, int Y) ;

   这个声明已经告诉了运行时该如何调用 SetCursorPos(...) 函数. 下面就要告诉运行时应该到哪里去找到这个函数了.同样

  通过MSDN.我们可以知道 SetCursorPos(...) 函数被定义在 user32.dll  库 中.这意味着 SetCursorPos(...) 函数的运行时代码在 user32.dll 中.

  我们用 DIIlmport 属性来告诉运行时 SetCursorPos() 函数的位置

    [DIIImport(”user32.dll”)]

    好了!一切准备就绪了.下面就让我们来看看移动鼠标位置把。(让鼠标在动一会儿把..)

 using  System;
using System.Runtime.InteropServices;

namespace ConsoleTest
{

class Program
{

[DllImportAttribute( " user32.dll " , EntryPoint = " SetCursorPos " )]
[ return : MarshalAsAttribute(UnmanagedType.Bool)]
public static extern bool SetCursorPos( int x, int y);

// 该实例运行效果为 鼠标随机在屏幕内跳动
static void Main( string [] args)
{
Random r = new Random( unchecked (( int )DateTime.Now.Ticks));
int i = 1 ;
do
{
int x = r.Next( 0 , Screen.PrimaryScreen.Bounds.Width);
int y = r.Next( 0 , Screen.PrimaryScreen.Bounds.Height);
SetCursorPos(x, x);
i++;
Thread.Sleep( 300 );

} while (i < 100 );
Console.ReadKey();

// ^_^,如果你写个随机数无限循环,就可以让别人永远无法使用鼠标,除非关 // 机。自己试的时候别写死循环,小心关不掉。

}
}
}

 

  需要注意的一点是 DIIImport 属性允许你可以调用任意的 Win32 代码.这其中可能会有一些不怀好意的函数.
  所以在使用 P /Invoke 调用非托管代码时需要你完全信任所调用的函数。

 

本章节就讲到这里,下一个回合将讲解 DIIImport 其他属性,和复杂参数的封送。

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于C# PInvoke(DllImport使用) 进阶教程的详细内容...

  阅读:47次