当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 由MessageBox透视Win API的调用

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 由MessageBox透视Win API的调用


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-08-14   浏览: 180 ::
收藏到网摘: n/a

 下面我们来看看Windows平台下应用程序是怎么调用Windows提供的底层API服务运行的。

我们编写Win32SDK程序时,需要弹出对话框以作出友好的选择,MessageBox这个API函数就可以实现该功能。在开头要添加<windows.h>因为其包含了众多的API函数声明头文件。为了探究这个小小的MessageBox是怎么弹出来的,我们右击MessageBox,选择“Go to definition of MessageBox(转到定义) ”将打开<winuser.h>中的#define MessageBox MessageBoxW定义行,我们继续对MessageBoxW右击“Go to definition of MessageBox(转到定义) ”将转到MessageBoxW的函数原型声明处:

int

WINAPI

MessageBoxW(

    __in_opt HWND hWnd,

    __in_opt LPCWSTR lpText,

    __in_opt LPCWSTR lpCaption,

__in UINT uType);

我们在使用Windows窗口操作系统时,经常会蹦出大大小小的窗口,MessageBox只是Windows作为提示的对话框窗口单元。那么,MessageBoxW这个API函数到底在哪里实现的呢?应用程序是如何调用系统接口函数的呢?

动态链接库(.dll

实际上Windows API函数是定义在一些DLL中的, DLL 实现了代码封装,从这个角度来看DLL才是真正意义上的API函数包,它是非开源Windows操作系统提供给我们的底层接口。DLL的编制与具体的编程语言及编译器无关。

动态链接库dll文件(Linux中与之对应的是的.so存放在C:\WINDOWS\system目录和C:\WINDOWS\system32目录下,它在被应用程序调用时才同程序相链接。

其中最重要的DLLUser32.dll、Gdi32.dllKernel32.dll这三个库文件。这三个库文件中的API函数都在Windows.h头文件中进行了声明。从功能上进行分类,User32.dllWindows XP USER API Client DLL)定义了窗口管理函数,包括窗口的创建、显示、设置和移动等;Gdi32.dllGDI Client DLL)定义了图形设备函数(GDI),实现与设备无关的绘图功能;Kernel32.dllWindows NT BASE API Client DLL)定义了系统服务函数,包括诸如内存调度、进程管理等与操作系统有关的底层功能。我们可以通过VC6自带的Depends工具或Dll函数查看器来一窥内幕,见下图。

DLL文件包括了具体实现的代码编译后的结果(二进制的机器码),而头文件就是打开.dll库文件的钥匙。所以我们若要使用MessageBoxW只需#include <winuser.h>(已被<windows.h>包含)。

VS编译器自带的标准函数库<stdio.h><stdlib.h><string.h><math.h>中声明的函数可以到C:\Program Files\Microsoft Visual Studio 8\VC\crt\src中查看相关实现源代码。例如strcat.c中实现了strcatstrcpy函数。有些函数的实现还是要调用底层API,例如C标准库函数create用于创建文件,但它是靠调用CreateFilekernel32.dll函数来完成创建文件功能的;beginthread(process.h,thread.c)需要调用 CreateThreadkernel32.dll函数。

 

 

Windows将遵循下面的搜索顺序来定位 DLL 包含EXE文件的目录>进程的当前工作目录>Windows系统目录>Windows目录>列在 Path 环境变量中的一系列目录.

 

 

如果你在本机编写一个Windows应用程序,移植到其他机子上(当然也是Windows操作系统),有可能因为缺少相关DLL文件而无法执行。因为DLL是动态链接,就是随用随加载,这就是为什么我们玩3D游戏时经常弹出缺少d3dx9***.dll的错误提示。如果启动的程序调用了一个过期的DLL文件或不匹配的DLL文件,则会出现“未定义的动态链接调用”消息。

动态链接库除了实现代码的共享外,其模块封装特性使得应用程序在调用一个DLL的不同版本时,只要导出的函数名相同就不必进行重新编译链接。这样,软件产品在更新或升级时,客户程序不必进行改动。在开发软件产品时,对于通用功能的函数,一般以DLL的形式来实现。Windows设备驱动程序就是体现上述特点的动态链接库。

 

动态链接库的调用方式又分为隐式调用(也称静态调用,需要.lib文件)和显式调用(也称动态调用,LoadLibrary->GetProcAddress->FreeLibrary)。

 

静态链接库(.lib

在早期库的组织形式相对简单,里面的目标代码只能够进行静态链接,所以我们称为静态库,静态库的结构比较简单,其实就是把原来的目标代码放在一起,链接程序LINK根据每一份目标代码的符号表查找相应的符号(函数和变量的名字),找到的话就把该函数里面需要定位的进行定位,然后将整块函数代码放进可执行文件里,若是找不到需要的函数就报错退出。标准Turbo C2.0中的C库函数,例如scanfprintfmemcpystrcpy等,就是使用的静态库技术。
   
静态链接libLinux中与之对应的是的.a的两个特点:
    #1
链接后产生的可执行文件包含了所有需要调用的函数的代码,因此占用磁盘空间较大。
    #2
如果有多个(调用相同库函数的)进程在内存中同时运行,内存中就存有多份相同的库函数代码,因此占用内存空间较多。

以下是C程序的编译链接过程:(1)执行cl /c main.c;cl /c lib1.c;cl /c lib2.c生成了main.obj lib1.obj lib2.obj三个文件;(2)执行link /lib lib1.obj;link /lib lib2.obj#生成了2个文件lib1.lib lib2.lib;(3)执行link main.obj lib1.lib lib2.lib生成main.exe.

我们可以用记事本打开C:\Program Files\Microsoft Visual Studio\VC98\Lib中的USER32.LIB文件,其中有

__imp__MessageBoxA@16 _MessageBoxW@16  //    这里16为参数的字节数

? _MessageBoxW@16 USER32.dll USER32.dll/     889206797

静态链接库lib文件中存放的是接口函数申明的入口地址,dll中存放的是函数实体!当我们隐式调用dll时,需要在Link选项指明其对应的lib库。lib告诉编译器你的dll都导出了什么函数,以及这些函数的地址名称,运行的时候就根据这些信息到dll里面去找。

实际上用VC6.0新建一个Win32 Console Application时,我们查看Project Settings>Link>Object/library modules中发现VC默认已连接了kernel32.libuser32.libgdi32.lib等常用的lib文件。如果需要显式设置的话,比如在网络编程中需要添加WS2_32.LIB库,则可以在文件的开头使用 #pragma  comment(lib,"WS2_32.LIB")命令

在编写MFC项目时,我们打开Project Settings>GeneralMicrosoft Foundation Classes,里面有两种链接方式:Use MFC in a Static Library Use MFC in a Shared Library。对应在Visual Studio 2005中项目属性—>配置属性—>常规—>MFC的使用中设置链接方式。

如果选择Use MFC in a Shared Library的话,你编译后的程序中不包含MFC库,所以文件会比较小,但是如果你的程序直接移到一个没有安装过MFC的机器上时,可能会导致找不到MFCDLL,故发布时要带MFCDLL文件。如果选择Use MFC in a Static Library,那么编译后的程序就直接包含了调用MFC的部分的库,文件可能会大一些,但是可以直接移到其他机器上运行,即发布时不用带MFCDLL文件。