回 帖 发 新 帖 刷新版面

主题:[翻译]WinAPI编程指南

这是一份讲述WinAPI编程的指南,原文为英文,小弟准备陆续的将它翻译过来,一则是为了自己学习,再则是为了那些英文稍弱点的朋友提供点便利。(不过还是忠告一句,英文赶快学好)由于小弟水平有限,翻译的过程中难免有很多错误,请务必指出,小弟必欣然接受!如果您有什么意见或者建议,请直接与我联系:
      casm@163.com     QQ:21859891(常年隐身,加时请注明来意)
或登陆我的space,URL是:
http://spaces.msn.com/fetag
另外,对回帖的兄弟有点小小的要求。那些“顶”,“赞扬”之类的就免了,小弟是来“讨骂”的^_^ 。我要的是大家的交流,是您的建议。但骂归骂,请不要“伤及无辜”噢,这份文档只是我一个人翻译的,与父母无关。

译者注:API编程正在被人们渐渐的遗忘,现在还在用纯的API来编程的人已经是凤毛麟角了。在MFC,组件级编程泛滥的今天,还有多少人能体会到API的精髓呢?随着程序规模的不断增大,面向对象技术的不断普及,程序员的效率越来越高,但程序员的整体技术却在一步步的下降。封装技术的日臻完善,使编程也变成了普通的劳动。但是一流的程序员,还是在孜孜不倦的追求着背后的真相。
我只是个初学者,出于爱好和share的目的,准备陆续翻译这份Tutorial,如果文中有什么不恰当的地方或者翻译错误的地方,请您指正,我会很乐意接受您的建议!这是我的E-mail:casm@163.com
 
文档原文:http://www.winprog.org/tutorial/
 
起步
这份指南的内容
这份指南将要展示给您使用Win32 API来开发windows程序的基本方法。开发语言采用C语言,绝大多数C++编译器也都能够正常编译。事实上,指南中的大部分内容对于调用API的任何语言都是可用的,像JAVA,汇编语言,以及Visual Basic。但我不会用这些语言来编写任何的范例代码,先前也有很多人尝试将这份指南用其他的语言来实现,很可惜,成功的人很少。
这份指南不会教您什么是C语言,也不会教您如何应用特定的编译器(Borland C++, Visual C++,LCC-Win32,等等)。然而,我会在附录中提供一些我个人的使用编译器的经验。
如果您不知道宏或者typedef是什么,或者不知道switch语句是如何工作的,请您现在就放下这份文档,先去找一本介绍C语言的书读一读。
非常重要的注释
通常,在全文中,我会指出一些非常重要的东西,这些是必读的。因为它们常常被人理解的一团糟,如果您不读,您也很有可能陷入其中。
首先:
范例压缩包里的源代码是必读的!我不会在文档内包含全部的代码,只会包含那些与我们正在讨论的内容有关的部分。如果您想详细了解代码在程序中是作用,您必须去参看压缩包内提供的源代码。
其次:
读遍所有的内容!如果您在指南的某个部分有什么疑问,请耐心的继续读下去,很可能这个问题在后面不久就会回答。如果您非要立刻弄清这个问题,请暂时停下来,通过IRC或者Email寻求答案。
另外,请您记住,在课题A中涉及的问题,有可能在B或者C甚至L中才做出解答,所以还是先泛读一遍。
好了,这些就是我想说的全部内容,接下来让我们看一些实际的例子吧。
最简单的Win32程序
如果您完全是个初学者,至少您也要保证能够编译一个基本的windows程序。将下面的代码敲入您的编辑器,如果一切正常,您就能创建一个最基本的程序。
记得,要将它作为一个C源文件来编译,而不是C++源文件。虽然这可能没什么关系,但是,既然我们的代码完全是用C写的,就让它保证从开始的时候就向一个有益的方向前进吧。大多数情况下,都要求您的代码保存为a.c而不是a.cpp。如果这个名字很让您头疼,请将它保存为test.c。
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, "Goodbye, cruel world!", "Note", MB_OK);
    return 0;
}
如果程序报错了,首先请您看一下出错的信息您是否理解,在您的编译器的帮助或者联机文档中搜索下这个错误的描述。确保您的程序指明为Win32 GUI程序,而不是控制台程序。很抱歉,对于这个问题,我也没什么办法。因为根据编译器的不同,错误信息的提示也不同。(而且人与人也不同)
也有可能会有一些警告,类似于没有使用WinMain()函数中的参数,这很正常,不用理会。至此,我们已经建立了一个能正常运行的程序,让我们来分析一下这段代码....
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
   LPSTR lpCmdLine, int nCmdShow)
WinMain函数等价于DOS或者UNIX编程中的main()函数。这是我们的程序执行的入口点。参数的含义如下:
HINSTANCE hInstance
 程序执行模块的句柄。(内存中的.exe文件)
HINSTANCE hPrevInstance
 在Win32程序中总为NULL
LPSTR lpCmdLine
 一个字符串的命令行参数。不包括程序名
int nCmdShow
 一个可能传递给ShowWindow()函数的整数。我们稍候会解释。
hInstance主要用来装载资源和执行一些基于其它模块的功能。模块是指装载到程序中的exe或者dll文件。在本指南的大部分内容中,他们都是指exe文件。
hPrevInstance在过去的Win16程序中,用来指向一个已经运行了的程序的实例。现在已经不再使用了,在Win32中,你完全可以忽略这个参数。
调用方式
WINAPI指明了调用的方式,它被定义为_stdcall。即使您不明白,也不用担心。它并不影响我们的学习。记住在这里它是必需的就行了。
Win32数据类型
您可能发现了,许多关键字在windows下面都被重新定义了,例如UINT是unsigned int,LPSTR是char* 等等。至于用哪种写法完全取决于您自己。如果您觉得用char* 要比用LPSTR舒服,您尽可以自由的使用。只是要确定所使用数据类型能够正确的匹配。
其实只是记住几个要点就很容易理解了。LP前缀代表指向长整形的指针(long pointer)。在Win32中,long型是一种陈旧的类型了,不用担心。如果您不知道指针是什么,您有两种选择:1)去找本C的书读一读。 2)继续读下去,弄得一团糟。我强烈建议您选择第一种,但还是有很多人选择第二种(我已经说了哦:) 别怪我没提醒您哦!)
接下来是跟在LP后面的一个表示常量的字符C,LPSTR表示一个指向字符串常量的长指针,它指向的类型是不能够修改的。LPSTR是指向字符串的长指针,没有const关键字,是可以修改的。

回复列表 (共29个回复)

21 楼

译者注:API编程正在被人们渐渐的遗忘,现在还在用纯的API来编程的人已经是凤毛麟角了。在MFC,组件级编程泛滥的今天,还有多少人能体会到API的精髓呢?随着程序规模的不断增大,面向对象技术的不断普及,程序员的效率越来越高,但程序员的整体技术却在一步步的下降。封装技术的日臻完善,使编程也变成了普通的劳动。但是一流的程序员,还是在孜孜不倦的追求着背后的真相。
我只是个初学者,出于爱好和share的目的,准备陆续翻译这份Tutorial,如果文中有什么不恰当的地方或者翻译错误的地方,请您指正,我会很乐意接受您的建议!这是我的E-mail:casm@163.com
 
文档原文:http://www.winprog.org/tutorial/

应用资源

您可能总想看看这份文档末尾附录部分关于使用VC++和BC++资源的内容。
在我们进一步深入之前,我会简单介绍一下资源,这样就不用每节都要重写了。您不需要实际编译这一节的代码,这些仅仅是范例。
资源是预先定义的二进制数据,并以二进制的格式存储在可执行程序中。我们通过资源脚本文件创建一个资源,脚本文件扩展名为".rc"。商业化的编译器通常都带有一个可视化的资源编辑器,能够自动生成资源脚本文件不需要您自己创建。但有时,您必须要手动编写资源脚本文件,尤其是当您的编译器没有可视化编辑器,或者,你需要的一些特定功能编译器不支持。
不幸的是,不同的编译器对应的资源文件也不完全相同。我会尽力阐述它们的处理资源文件的公共特性。
包含在MSVC++中的资源编辑器使得手工编辑资源文件非常困难,因为它规定了固定的格式。您自己编写的资源文件,在保存的时候会被完全的破坏。总之,你不应该删除自动创建的.rc文件。但了解如何手动修改他们还是很有好处的。另一个让人讨厌的是,MSVC++会默认将资源文件的头文件命名为"resource.h",尽管您可能想取一个别的名字。为了使这份文档尽可能简单,我会遵守这些规定,但是在结尾的附录中,我会介绍如何更改。
首先,让我们看一个非常简单的资源脚本文件,一个图标。
#
include "resource.h"
IDI_MYICON ICON "my_icon.ico"

这就是全部的内容。IDI_MYICON是资源的标识符。ICON是类型,"my_icon.ico"包含资源的外部文件的名字(译者注:也就是资源的名字)。这个资源脚本文件可以在任何编译器上正常运行。
那么,这个#include "resource.h"又是做什么的呢?我们的程序需要标识那个图标,而最好的方法就是赋给它一个唯一的ID(IDI_MYICON)。我们可以通过创建"resources.h"文件来为图标指定一个ID,在这个文件和我们的资源脚本文件中,都包含这个ID。

#define IDI_MYICON  101

您看到了,我将IDI_MYICON指定为101。我们甚至可以忽略这个标识符的存在,在用到这个图标的地方直接用101来代替,但用IDI_MYICON会使我们的程序清晰很多,当有大量资源的时候,也容易记忆。
接下来再说说怎么添加一个菜单资源:

#include "resource.h"
IDI_MYICON ICON "my_icon.ico"
IDR_MYMENU MENU
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "E&xit", ID_FILE_EXIT
    END
END

IDR_MYMENU是资源的名字,MENU是资源的类型。这里有一个新的看点,您注意到上面的BEGIN和END了吗?有些资源编辑器或者编译器用 { 代替BEGIN,用 } 代替END。如果您的编译器支持这两种写法,您尽可以随便选一种来用。如果不同时支持,您就需要选用一种适合的写法了。
我们已经添加了一个新的标识符,ID_FILE_EXIT,为了在我们的程序中能够使用它,我们需要将它添加到资源文件的头文件resource.h中。

#define IDI_MYICON  101
#define ID_FILE_EXIT 4001

在大项目中创建并维护这些资源文件实在是一件非常伤神的事,这也是大多数人都喜欢用资源编辑器来管理资源的原因。They still screw up from time to time, and you could end up with multiple items with the same ID or a similar problem, and it's good to be able to go in and fix it yourself.(此处我还没想出恰当的语句来翻译,暂留) 
下面是一个演示使用资源文件的范例:

HICON hMyIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));

LoadIcon()和许多其它使用资源的函数的第一个参数都是当前程序的实例句柄(在WinMain()函数中指定或者像前面的范例程序一样,通过GetModuleHandle()函数获得)。第二个参数是资源的标识符。
您一定很想知道MAKEINTRESOURCE()有什么作用以及为什么LoadIcon()函数接受一个LPCTSTR类型的参数而不是我们传递给它的UINT类型的ID。MAKEINTRESOURCE()将一个整数(资源的ID就是一个整数)转化为它需要的LPCTSTR类型。这带给我们另一种标识资源的方法,就是用字符串。基本上没有人这样做了,我也不想深入地讲了,但是,最基本的是,如果你不通过#define语句将一个整型值赋给你的资源,那么资源的名字就会被当作一个字符串使用,在您的程序中可以这样:

HICON hMyIcon = LoadIcon(hInstance, "MYICON");

LoadIcon()和其它装载资源的API函数能够通过检查高位的值来判断传递给它的参数是一个整数,还是一个指向字符串的指针。如果高位是0(针对整数的值小于等于65535),就把它当作一个资源的ID值,这种方式限制了资源的ID值只能小于65535,除非您有很多很多资源文件,否则应该没什么问题的。如果高位不是0,那就把它当作一个指向资源名称的指针。千万别依靠API来做这种检查,除非在说明文档中已经详细说明。
例如,对菜单命令,像ID_FILE_EXIT就无效,因为它只能为整型值。

22 楼

楼主!不要放弃啊.....

期待下篇.........

23 楼

累了吧,休息下

24 楼

期待下篇啊~~

25 楼

实在抱歉,最近的几篇没有贴在这里,因为这里的回复限制不允许超过5000字,每次大都

需要我将文章分开来发,所以我决定以后不在这里继续发表了,如果有朋友感兴趣,可以

来我的space上面,大家共同讨论!

这是地址:

http://spaces.msn.com/fetag/

26 楼

请问怎样能将HIWORD和LOWORD分开并修改的两个值重新合并成一个LONG?

27 楼

LZ要是能做成CHM就好了~~~

支持下~~

28 楼

[quote]请问怎样能将HIWORD和LOWORD分开并修改的两个值重新合并成一个LONG?[/quote]

a=HIWORD(c)
b=LOWORD(c)

c=(a<<16)+(b&0xFFFF)

29 楼

楼主辛苦拉. 谢谢奉献..  ~

我来回复

您尚未登录,请登录后再回复。点此登录或注册