C#调用Win32 api学习总结

时间:2023-02-23 09:57:27

从.NET平台调用Win32 API

Win32 API可以直接控制Microsoft Windows的核心,因为API(Application Programming Interface)本来就是微软留给我们直接控制Windows的接口。

一.    基础知识

Win32 API是C语言(注意,不是C++语言,尽管C语言是C++语言的子集)函数集。

1. Win32 API函数放在哪里?

Win32 API函数是Windows的核心,比如我们看到的窗体、按钮、对话框什么的,都是依靠Win32函数“画”在屏幕上的,由于这些控件(有时也称组件)都用于用户与Windows进行交互,所以控制这些控件的Win32 API函数称为“用户界面”函数(User Interface Win32 API),简称UI函数;还有一些函数,并不用于交互,比如管理当前系统正在运行的进程、硬件系统状态的监视等等……这些函数只有一套,但是可以被所有的Windows程序调用(只要这个程序的权限足够高),简而言之,API是为程序所共享的。为了达到所有程序能共享一套API的目的,Windows采用了“动态链接库”的办法。之所以叫“动态链接库”,是因为这样的函数库的调用方式是“随用随取”而不是像静态链接库那样“用不用都要带上”。

Win32 API函数是放在Windows系统的核心库文件中的,这些库在硬盘里的存储形式是.dll文件。我们常用到的dll文件是user32.dll和kernel32.dll两个文件。

这些dll文件是用C语言写的,源代码经C语言编译器编译之后,会以二进制可执行代码形式存放在这些dll文件中。为了能让程序使用这些函数,微软在发布每个新的操作系统的时候,也会放出这个系统的SDK,目前最新的是Win2003 SP1 SDK,据说Vista的马上就要放出来,而且已经把UI的API从核心库中分离出去以提高系统的稳定性了。SDK里有一些C语言的头文件(.h文件),这些文件里描述了核心dll文件里都有哪些Win32 API函数,在写程序的时候,把这些.h文件用#include"....."指令包含进你的程序里,你就可以使用这些Win32 API了。

C#语言也使用dll动态链接库,不过这些dll都是.NET版本的,具有“自描述性”,也就是自己肚子里都有哪些函数都已经写在自己的metadata里了,不用再附加一个.h文件来说明。现在,我们已经找到了问题的关键点:如何用.NET平台上的C#语言来调用Win32平台上的dll文件。答案非常简单:使用DllImport特性。

二.  小试

using System;

using System.Runtime.InteropServices;

class Program

{

[DllImport("User32.dll")]

public static extern int MessageBox(int h, string m, string c, int type);

static int Main()

{

MessageBox(0, "Hello Win32 API", "大爷", 4);

Console.ReadLine();

return 0;

}

}

1. 要使用DllImport这个特性(特性也是一种类),必须使用这一句using System.Runtime.InteropServices;

,导入“运行时->交互服务”。喔~~~~运行时的交互服务不就是“动态链接”吗?感谢Microsoft!

2. 然后我们就可以制造一个DllImport类的实例,并把这个实例绑定在我们要使用的函数上了。“特性类”这种类非常怪——制造类实例的时候不使用MyClass mc = new MyClass();这种形式,而是使用[特性类(参数列表)]这种形式;特性类不能独立存在,一定要用作修饰其它目标上(本例是修饰后面的一个函数),不同的特性可以用来修饰类、函数、变量等等;特性类实例在被编译的时候也不产生可执行代码,而是被放进metadata里以备检索。总之,你记住特性类很怪就是了,想了解更多就查查MSDN,懒得查就先这么记——不懂惯性定律不影响你学骑自行车。[DllImport("User32.dll")]是说我们要使用的Win32 API函数在User32.dll这个文件里。问题又来了:我怎么知道那么多API函数都在哪个dll文件里呢?这个你可以在MSDN里查到,位置是Root->Win32 and COM Development->Development Guides->Windows API->Windows API->Windows API Reference->Functions by Category。打开这页,你会看到有很多API的分类,API全在这里了。打开一个分类,比如Dialog Box,在Functions段,你会看到很多具体的函数,其中就有上面用到的MessageBox函数,点击进入。你将打开MessageBox的详细解释和具体用法。在这一页的底部,你可以看到一个小表格,里面有一项“Minimum DLL Version   user32.dll”就是说这个函数在user32.dll里。

3. 接下来就是我们的函数了。在C#里调用Win32函数有这么几个要点。第一:名字要与Win32 API的完全一样。第二:函数除了要有相应的DllImport类修饰外,还要声明成public static extern类型的。第三:函数的返回值和参数类型要与Win32 API完全一致!

从MSDN里摘出一张表来,是常用Win32数据类型与.NET平台数据类型的对应表:

Figure 2 Non-Pointer Data Types

Win32 Types Specification

CLR Type

char, INT8, SBYTE, CHAR 8-bit signed integer

System.SByte

short, short int, INT16, SHORT 16-bit signed integer

System.Int16

int, long, long int, INT32, LONG32, BOOL, INT  32-bit signed integer System.Int32

__int64, INT64, LONGLONG 64-bit signed integer

System.Int64

unsigned char, UINT8, UCHAR, BYTE 8-bit unsigned integer

System.Byte

unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR, __wchar_t

16-bit unsigned integer System.UInt16

unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT

32-bit unsigned integer System.UInt32

unsigned __int64, UINT64, DWORDLONG, ULONGLONG  64-bit unsigned integer System.UInt64

float, FLOAT Single-precision floating point

System.Single

double, long double, DOUBLE Double-precision floating point

System.Double

In Win32 this type is an integer with a specially assigned meaning; in contrast, the CLR provides a specific type devoted to this meaning.

有了这些东西,我们就能把一个Win32 API函数转成C#函数了。还拿MessageBox函数为例(看刚才给出的函数表),它的Win32原形如下:

int MessageBox(  HWND hWnd,   LPCTSTR lpText,    LPCTSTR lpCaption,  UINT uType );

函数名:MessageBox将保持不变。

返回值:int 将保持不变(无论是Win32还是C#,int都是32位整数)

参数表:H开头意味着是Handle,一般情况下Handld都是指针类型,Win32平台的指针类型是用32位来存储的,所以在C#里正好对应一个int整型。不过,既然是指针,就没有什么正负之分,32位都应该用来保存数值——这样一来,用uint(无符号32位整型)来对应Win32的H类型更合理。不过提醒大家一点,int是受C#和.NET CLR双重支持的,而uint只受C#支持而不受.NET CLR支持,所以,本例还是老老实实地使用了int型。

至于LPCTSTR是Long Pointer to Constant String的缩写,说白了就是——字符串。所以,用

http://m.blog.csdn.net/article/details?id=50930221

C#调用Win32 api学习总结的更多相关文章

  1. MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API(转)

    转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html 续上文[翻译]MSIL 教程(一) ,本文继续讲解数组.分支.循环 ...

  2. Python调用win32 API绘制正弦波

    Python调用win32 API新建窗口与直接创建窗口的流程相同 流程:注册窗口→创建窗口→显示窗口→更新窗口→消息循环 代码: # -*- coding: utf-8 -*- import win ...

  3. C#调用Win32 api时的内存操作

    一般情况下,C#与Win 32 Api的互操作都表现的很一致:值类型传递结构体,一维.二维指针传递IntPtr.在Win32 分配内存时,可以通过IntPtr以类似移动指针的方式读取内存.通过IntP ...

  4. nodejs 调用win32 api

    video 教程文件 win32 api >node -v v12.16.1 >npm install -g node-gyp >npm i @saleae/ffi >node ...

  5. 调用win32 api 函数SendMessage() 实现消息直接调用

    简单的调用例子, 适合初学者学习,当然 我也是初学者. #include <windows.h> #include <stdio.h> #include <stdlib. ...

  6. C&num;调用win32 api 操作其它窗口

    实现以下功能: 找到窗体 找到控件(也叫子窗体) 获取内容 获取位置 设置 位置 内容 鼠标点击 示范 1. 找窗体 以操作系统自带的计算器为例 string clWindow = "Cal ...

  7. C&num;调用win32 api程序实例

    1.声明static extern 方法,使用DllImport特性 class MyClass { [DllImport("kernel32", SetLastError = t ...

  8. win32 API 学习

    SendMessage 函数原型 LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam) 详情:百度百科     msd ...

  9. Win32&plus;API学习笔记:创建基本的窗口控件

    创建一个标签 CreateWindowEx(0, "static", "姓名:",                                        ...

随机推荐

  1. Random Javascript code snippets

    MollyPages.org"You were wrong case.To live here is to live." Home Pages / Database / Forms ...

  2. linux u-boot跟踪方法总结

    拿到一块板子,其中很重要的一项就是看电路图还有Datasheet. 这个真的很重要,首先你要知道cpu的架构是什么,armv7?arvmv5?还是其他的,哪个公司的芯片?是freescale 还是TI ...

  3. nyoj 106 背包问题

    点击打开链接 背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v ...

  4. mybatis0211 mybatis和spring整合

    1mybatis和spring整合 1.1 mybaits和spring整合的思路 .让spring管理SqlSessionFactory .让spring管理mapper动态代理对象和dao. 使用 ...

  5. codeforces500B

    New Year Permutation CodeForces - 500B User ainta has a permutation p1, p2, ..., pn. As the New Year ...

  6. Linux - 包不同安装方式

    rpm 软件包管理器 安装编译包好的二进制包 方式 rpm -ivh lynx # rpm安装 rpm -e lynx # 卸载包 rpm -e lynx --nodeps # 强制卸载 rpm -q ...

  7. js删除Array数组中的某个元素

    Array.prototype.indexOf = function (val) { ; i < this.length; i++) { if (this[i] == val) return i ...

  8. Java 线程类的一些常用方法

    线程类的一些常用方法: sleep(): 强迫一个线程睡眠N毫秒.  isAlive(): 判断一个线程是否存活.  join(): 等待线程终止.  activeCount(): 程序中活跃的线程数 ...

  9. easyui-datetimebox设置默认时分秒00&colon;00&colon;00

    datetimebox默认打开面板显示的是当前的时间,有个需求就是当打开面板时显示固定的”00:00:00”时间, 它本身有个方法spinner方法可以获得时间微调器对象,它所依赖的组件combo有个 ...

  10. 892&period; Surface Area of 3D Shapes

    问题 NxN个格子中,用1x1x1的立方体堆叠,grid[i][j]表示坐标格上堆叠的立方体个数,求这个3D多边形的表面积. Input: [[1,2],[3,4]] Output: 34 思路 只要 ...