Windows API开发
简介
Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外, 它同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程式达到开启视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应用程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口。
概要介绍
应用程序接口为:“‘计算机操作系统(Operating system)’或‘程序库’提供给应用程序调用使用的代码”。其主要目的是让应用程序开发人员得以调用一组例程功能,而无须考虑其底层的源代码为何、或理解其内部工作机制的细节。API本身是抽象的,它仅定义了一个接口,而不涉入应用程序如何实现的细节。
例如,图形库中的一组API定义了绘制指针的方式,可于屏幕上显示指针。当应用程序需要指针功能时,可引用、编译时链接到这组API,而运行时就会调用此API的实现(库)来显示指针。
应用程序接口是一组数量上千、极其复杂的函数和副程序,可让程序设计师做很多任务作,譬如“读取文件”、“显示菜单”、“在视窗中显示网页”等等。操作系统的API可用来分配存储器或读取文件。许多系统应用程序借由API接口来实现,像是图形系统、数据库、网络Web服务,甚至是在线游戏。
应用程序接口经常是软件开发工具包(SDK)的一部分。
分类
Windows API所提供的功能可以归为七类:
1.基础服务(Base Services),提供对Windows系统可用的基础资源的访问接口。比如像:文件系统(file system)、外部设备(device)、进程(process)、线程(thread)以及访问注册表(Windows registry)和错误处理机制(error handling)。这些功能接口位于 16位Windows下的kernel.exe、krnl286.exe或krnl386.exe系统文档中,以及32位Windows下的 kernel32.dll和advapi32.dll中。
2.图形设备接口(GDI),提供功能为:输出图形内容到显示器、打印机以及其他外部输出设备。它位于16位Windows下的gdi.exe;以及32位Windows下的gdi32.dll。
3.图形化用户界面(GUI),提供的功能有创建和管理屏幕和大多数基本控件(control),比如按钮和滚动条。接收鼠标和键盘输入,以及其他与GUI有关的功能。这些调用接口位于:16位Windows下的user.exe,以及32位Windows下的user32.dll。从Windows XP版本之后,基本控件和通用对话框控件(Common Control Library)的调用接口放在comctl32.dll中。
4.通用对话框链接库(Common Dialog Box Library),为应用程序提供标准对话框,比如打开/保存文档对话框、颜色对话框和字体对话框等等。这个链接库位于:16位Windows下的commdlg.dll中,以及32位Windows下comdlg32.dll中。它被归类为User Interface API之下。
5.通用控件链接库(Common Control Library),为应用程序提供接口来访问操作系统提供的一些高级控件。比如像:状态栏(status bar)、进度条(progress bars)、工具栏(toolbar)和标签(tab)。这个链接库位于:16位Windows下的commctrl.dll中,以及32位Windows下comctl32.dll中。。它被归类为User Interface API之下。
6.Windows外壳(Windows Shell),作为Windows API的组成部分,不仅允许应用程序访问Windows外壳提供的功能,还对之有所改进和增强。它位于16位Windows下的shell.dll中,以及32位Windows下的shell32.dll中(Windows 95则在 shlwapi.dll中)。 它被归类为User Interface API之下。
表达方式
[DllImport("libname",'Named Parameters')][public|private|internal] [Type] FunctionName(Type parameter1,Type parameter2...);
举例
C#中调用Windows API:
一、调用格式
using System.Runtime.InteropServices; //引用此名称空间,简化后面的代码
...
//使用DllImportAttribute特性来引入api函数,注意声明的是空方法,即方法体为空。
[DllImport("user32.dll")]
public static extern ReturnType FunctionName(type
arg1,type arg2,...);
//调用时与调用其他方法并无区别
可以使用字段进一步说明特性,用逗号隔开,如:
[ DllImport( "kernel32",EntryPoint="GetVersionEx" )]
DllImportAttribute特性的公共字段如下:
1、CallingConvention 指示向非托管实现传递方法参数时所用的 CallingConvention
值。
CallingConvention.Cdecl : 调用方清理堆栈。它使您能够调用具有 varargs 的函数。
CallingConvention.StdCall :
被调用方清理堆栈。它是从托管代码调用非托管函数的默认约定。
2、CharSet 控制调用函数的名称版本及指示如何向方法封送 String 参数。
此字段被设置为 CharSet 值之一。如果 CharSet 字段设置为
EntryPoint 的名称中追加字母“W”。如果此字段设置为 Ansi,则字符串将转换成 ANSI
字符串,同时向 DLL EntryPoint 的名称中追加字母“A”。大多数 Win32 API
使用这种追加“W”或“A”的约定。如果 CharSet 设置为 Auto,则这种转换就是与平台有关的(在
Windows NT 上为 Unicode,在 Windows 98 上为 Ansi)。CharSet
的默认值为 Ansi。CharSet 字段也用于确定将从指定的 DLL
导入哪个版本的函数。CharSet.Ansi 和 CharSet.Unicode 的名称匹配规则大不相同。对于
Ansi 来说,如果将 EntryPoint
设置为“MyMethod”且它存在的话,则返回“MyMethod”。如果 DLL
中没有“MyMethod”,但存在“MyMethodA”,则返回“MyMethodA”。对于 Unicode
来说则正好相反。如果将 EntryPoint
设置为“MyMethod”且它存在的话,则返回“MyMethodW”。如果 DLL
中不存在“MyMethodW”,但存在“MyMethod”,则返回“MyMethod”。如果使用的是
Auto,则匹配规则与平台有关(在 Windows NT 上为 Unicode,在 Windows 98 上为
Ansi)。如果 ExactSpelling 设置为 true,则只有当 DLL
中存在“MyMethod”时才返回“MyMethod”。
3、EntryPoint 指示要调用的 DLL 入口点的名称或序号。
如果你的方法名不想与api函数同名的话,一定要指定此参数,例如:
[DllImport("user32.dll",CharSet="CharSet.Auto",EntryPoint="MessageBox")]
public static extern int MsgBox(IntPtr hWnd,string
txt,string caption,int type);
4、ExactSpelling 指示是否应修改非托管 DLL 中的入口点的名称,以与 CharSet
字段中指定的 CharSet 值相对应。如果为 true,则当
DllImportAttribute.CharSet 字段设置为 CharSet 的 Ansi
值时,向方法名称中追加字母 A,当 DllImportAttribute.CharSet 字段设置为
CharSet 的 Unicode 值时,向方法的名称中追加字母 W。此字段的默认值是 false。
5、PreserveSig 指示托管方法签名不应转换成返回 HRESULT、并且可能有一个对应于返回值的附加
[out,retval] 参数的非托管签名。
6、SetLastError 指示被调用方在从属性化方法返回之前将调用 Win32 API
SetLastError。true 指示调用方将调用 SetLastError,默认为
false。运行时封送拆收器将调用 GetLastError 并缓存返回的值,以防其被其他 API
调用重写。用户可通过调用 GetLastWin32Error 来检索错误代码。
//举一个简单的例子 //例子比较完整 //实现鼠标移动到指定位置点击
1 //添加引用 2 using System.Runtime.InteropServices;
1 [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)] 2 static extern IntPtr FindWindow(string lpClassName, string lpWindowName);//寻找窗口列表中第一个符合指定条件的顶级窗口 3 4 [DllImport("user32.dll")] 5 public static extern int GetClientRect(IntPtr hWnd, out RECT lpRect);//获得客户区矩形 6 7 [DllImport("user32.dll")] 8 public static extern bool MoveWindow(IntPtr hWnd, long x, long y, long nWith, long nHeight, bool bRepaint);//改变指定窗口的位置和大小 9 10 [DllImport("user32.dll")] 11 public static extern bool SetForegroundWindow(IntPtr hWnd);//确保窗口置顶 12 13 [DllImport("user32")] 14 public static extern int SetCursorPos(long dx, long dy);//设置指针的位置 15 16 [DllImport("user32")] 17 public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);//模拟一次鼠标事件 18 19 [DllImport("user32.dll")] 20 static extern void BlockInput(bool Block);//锁定鼠标、键盘(不会锁定ctrl+alt+delete) 21 22 23 // 窗体矩形结构 24 [StructLayout(LayoutKind.Sequential)] 25 public struct RECT 26 { 27 public int Left; 28 public int Top; 29 public int Right;//宽 30 public int Bottom;//高 31 } 32 33 enum Mouse 34 { 35 MOUSEEVENTF_MOVE = 0x0001, //移动鼠标 36 MOUSEEVENTF_LEFTDOWN = 0x0002, //模拟鼠标左键按下 37 MOUSEEVENTF_LEFTUP = 0x0004, //模拟鼠标左键抬起 38 MOUSEEVENTF_RIGHTDOWN = 0x0008, //模拟鼠标右键按下 39 MOUSEEVENTF_RIGHTUP = 0x0010, //模拟鼠标右键抬起 40 MOUSEEVENTF_MIDDLEDOWN = 0x0020, //模拟鼠标中键按下 41 MOUSEEVENTF_MIDDLEUP = 0x0040, //模拟鼠标中键抬起 42 MOUSEEVENTF_ABSOLUTE = 0x8000//标示是否采用绝对坐标 43 } 44 45 //获得待测程序主窗体句柄 46 private static IntPtr FindMainWindowHandle(string caption, int delay, int maxTries) 47 { 48 IntPtr mwh = IntPtr.Zero; 49 bool formFound = false; 50 int attempts = 0; 51 while (!formFound && attempts < maxTries) 52 { 53 if (mwh == IntPtr.Zero) 54 { 55 Console.WriteLine("Form not yet found"); 56 Thread.Sleep(delay); 57 ++attempts; 58 mwh = FindWindow(null, caption); 59 } 60 else 61 { 62 Console.WriteLine("Form has been found"); 63 formFound = true; 64 } 65 } 66 if (mwh == IntPtr.Zero) 67 throw new Exception("Could not find main window"); 68 else 69 return mwh; 70 }
1 //使用 2 Process p = Process.Start("要打开的应用程序的地址"); 3 Thread.Sleep(1000); 4 if (p == null) Console.WriteLine("进程可能已经存在"); 5 6 //查找主窗口句柄 7 IntPtr mwh = FindMainWindowHandle("应用程序的标题,可以使用spy++查看", 100, 25); 8 //获取应用窗体大小 9 GetClientRect(mwh, out RECT rect); 10 //移动窗体 11 MoveWindow(mwh, 0, 0, rect.Right, rect.Bottom, false); 12 //确保窗口置顶 13 SetForegroundWindow(mwh); 14 15 BlockInput(true);//禁用鼠标键盘 16 17 //移动鼠标 18 SetCursorPos(711, 158); 19 20 //移动鼠标也可以使用mouse_event函数,但是我用这个必须相对定位和绝对定位一起使用才有效果,感觉定不准,建议使用SetCursorPos 21 //mouse_event(Convert.ToInt32(Mouse.MOUSEEVENTF_ABSOLUTE) | Convert.ToInt32(Mouse.MOUSEEVENTF_MOVE), 0, 0, 0, 0); 22 //mouse_event(Convert.ToInt32(Mouse.MOUSEEVENTF_MOVE), 320, 190, 0, 0); 23 //mouse_event(Convert.ToInt32(Mouse.MOUSEEVENTF_LEFTDOWN) | Convert.ToInt32(Mouse.MOUSEEVENTF_LEFTUP), 0, 0, 0, 0); 24 25 //左键按下、放开 26 mouse_event(Convert.ToInt32(Mouse.MOUSEEVENTF_LEFTDOWN) | Convert.ToInt32(Mouse.MOUSEEVENTF_LEFTUP), 0, 0, 0, 0); 27 28 BlockInput(false);
入门:https://www.cnblogs.com/M-Anonymous/p/9291315.html
WindowsAPI 开发手册: http://www.office-cn.net/t/api/index.html?findwindowex.htm