zoukankan      html  css  js  c++  java
  • C# PInvoke(DllImport使用) 进阶教程(一)转

    我们曾经熟悉的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的过程(引用图)

    tujie2


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

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

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

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

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

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

      注意:当非托管函数产生异常时,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, y);
    i++;
    Thread.Sleep(300);

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

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

    }
    }
    }
    复制代码

     

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

  • 相关阅读:
    1230: [Usaco2008 Nov]lites 开关灯
    1821: [JSOI2010]Group 部落划分 Group
    1819: [JSOI]Word Query电子字典
    1820: [JSOI2010]Express Service 快递服务
    3038: 上帝造题的七分钟2
    1854: [Scoi2010]游戏
    Codevs3278[NOIP2013]货车运输
    关于使用lazytag的线段树两种查询方式的比较研究
    算法模板——splay区间反转 1
    3223: Tyvj 1729 文艺平衡树
  • 原文地址:https://www.cnblogs.com/candyzhmm/p/5704614.html
Copyright © 2011-2022 走看看