欢迎阅读theForger'sWin32API教程第二版(简体中文)作者:BrooksMiles译者:湛宗儒 本教程试图使用尽可能快和尽可能清晰的方法教你开始Win32API开发.它是以一个整体来组织的,所以在你提问之前请从头到尾看一遍...你的大多数问题很可能在文字中已被回答.每个章节以之前的章节为基础.我也在附錄A中附上了一些常见的错误的解決方法.如果你问一些在教程中已被回答的问题的话,看起来就有点不聪明了.·下载完整的范例源代码,在整个教程都有对代码的引用.·或是下载整个教程(包括源代码)至你自己的计算机上慢慢看.下到硬盘的版本可能不包括网络版本具有的一些如拼写更正之类的小规模修改. 如果你在一个別的站点上看此教程,请访问#winprog站点看最新的官方版本. ·想做点什么? ·需要进一步的帮助?目錄·基础1.开始学习2.一个简单的窗口3.处理消息4.理解消息循环5.使用资源6.菜单和图标7.对话框,图形界面设计者的好朋友8.非模态对话框9.标準控件:按钮,编辑框,列表框,靜态控件10.等等,我还想问...(对话框常见问题)·创建一个简单应用1.应用第一部分:在运行时创建控件2.应用第二部分:使用文件与常用对话框3.应用第三部分:工具栏与状态栏4.应用第四部分:多文档界面·图形设备界面1.位图,设备上下文与BitBlt2.透明位图3.定时器与动画4.文本,字体与顏色·工具与文档1.推荐的书与参考2.免费的VisualC++命令行工具3.免费的BorlandC++命令行工具·附表附表A:常见错误的解決方法附表B:为什要在学习MFC编程之前学习API附表C:关于资源文件 我听某些读者说教材中的源代码在一些很旧的Netscape浏览器中不能正确地換行,如果你遇到此问题请参考zip打包下载的源代码.想做点什么?你可以绝对免费地使用此文档,但是把在它放在互联网上的确是有些费用..如果你感觉它对你有帮助,也想回馈一些,我将很感谢你能捐赠任何数目的款项来协助支撐此网站.此页面每月大約有15,000个点击,并且在一直增加:) 再说一次,你完全沒有义务支付,你也不会因为支付而得到除了在此处之外的任何东西,但是你想协助的话,是很好的...就点那个PayPal图片就行.但愿你能享受閱读,Brook 我想对如下几个人做出的贡献表示感谢:YihHorng,ToddTroxell,TFrankZvovushe,SuzanneLorrin,SethMcCarus,CrispinaChong,JohnCrutchfield,ScottJohnstone,PatrickSears,JuanDemerutis,RichardAnthony,AlexFox,BobRudis,EricWadsworth,ChrisBlume.还有那些写信告诉我觉得此文档有用的那些读者.我很高兴!需要进一步的帮助? 一般地话我会免费回复求助邮件,或指出在哪里可以找到可供参考的资源. 现在我正忙于几个大项目,所沒有时间跟你写一些特定的范例或一定规模的软件项目.但是我愿意接项目:)尽管联系我.Copyright©1998-2003,BrookMiles(theForger).Allrightsreserved.开始学习这篇教程讲什么 这篇教程试图向你展现使用Win32API写程序的一些基础知识(还有常见的扩展知识).使用C语言,大多数的C++工具也可以编译.事实上从大多数语言的介绍文章可知,大多数语言皆可调用API,包括Java,汇编语言以及VisualBasic.但是我将不会提到这些语言的代码例子,你想使用其它语言的话,请自己参考相关资料,不过有好几个使用过此教程的人都对我说用上面的这些语言都是可行的. 本教程不会教你C语言,也不会教你怎么使用你喜欢的编译器(BorlandC++,VisualC++,LCC-Win32,等等).但是我将在附表中就我对编译器的所知提供一些说明. 如果你不知道macro或typedef是什么,或switch()语句如何工作,那你要先回去找一本好的C语言的教程学习一下.重要说明 在此文档的某些部分我将指出某些地方很重要.因为很多人在不閱读它们情況下造成理解困难,你如果不閱读,你很可能也陷入困难.第一个就是: 以zip打包的源代码范例不是可选可不选的!我沒有把所有的代码放在教程中,只放了那些与我正在讨论问题相关的.要想知道这里的代码怎么与其它部分配合,就必须去看zip文件中的源代码. 好!第二个: 把整个文档看完.如果你在读某章节遇到了问题,请耐心一点,很可能在后面一点就可以找到答案.如果你实在不能忍受这种无知的状态,请在到IRC频道上去提问或发出求助邮件之前至少跳过一点或在余下的文档中搜一下(是的,计算机可以搜索). 另外一点就是一个关于话题A的问题很可能在关于话题B或C的讨论中得到解答,也有可能是话题L.所以多看看,找一下. 好,东扯西拉暂时告一段落,我们来试些实际代码.最简单的Win32程序 如果你是一个完全的新手,就让我们来确认一下你可以编译一个基本的windows程序.把下面这些代码弄到你的编译器中去编译一下,如果一切正常你就得到有史以来最简易的程序之一. 记得以C来编译,不是以C++.可能沒有关系,但这里的代码都是C,在正确的轨道,行驶还是好些.大多数情況,你要做的就是把文件的扩展名写成.c而不是.cpp..如果这些话伤了你的脑筋的话,就把文件名写成test.c并用它就行了.#includewindows.hintWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow){MessageBox(NULL,Goodbye,cruelworld!,Note,MB_OK);return0;} 如果不行,首先閱读得到的任何错误提示,并在帮助文档或任何其它跟你编译器配套的文档中查找它们.确定你是以一个Win32GUI(不是Console)的工程/makefile/目标来编译的.不幸的是,这一点上我也帮不了什么,对于不同的编译器(不同的人),解決方法不同. 你可能得到一些警告说你沒有使用WinMain()传递的那些参数.这沒关系.现在我们确定你能编译一个程序了,我们来看一下代码...intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow) WinMain()是Windows中与DOS或UNIX的main()的等价物.这是你的程开始执行的入口.参数如下:HINSTANCEhInstance程序可执行模块的句柄(內存中的.exe文件).HINSTANCEhPrevInstance在Win32程序中总是为NULL.LPSTRlpCmdLine命令行参数组成的一个单字符串.不包括程序名字.intnCmdShow一个将要传递给ShowWindow()的整数,我们在后面进行讨论. hInstance用作装入资源或其它的以模块为单位的任务.一个模块是一个装入到你程序的exe或dll.对于本教程的大多数部分(如果不是全部的话),我们只关心一种模块,就是exe模块. hPrevInstance在Win16时代曾经用作你程序的前面已经运行的实例(如果有的话).现在已经不用了,在Win32中你忽略它就行了.调用规则 WINAPI指定调用规则并被定义为_stdcall.要是你不知道它是干什么用的,先不管它,在我们的这个教程中它对我们沒有影响.记住在这个位置我们需要它就是了.Win32数据类型 你会发现很多普通的关键字或类型在windows中有特定的定义.UINT是unsignedint,LPSTR是char*等等...你怎么用完全取決于你自己.你要是喜欢char*超过了LPSTR,那就用就是了.当然在你替換一个数据类型前你要确定你知道它是什么. 就记住一些容易记住的东西就夠了.LP前缀代表LongPointer.在Win32中,Long这个部分已经是过时的概念,不要管它.要是不知道指针是什么的话,你可以1)去找一本好的C语言教程,或2)直接往下读,弄得头脑混乱.我是推荐第一种方案的,但很多人使用第二种(我也是:).到时候別说我沒有提醒你. 接下来,一个C接在LP后面表示是常量指针.LPCSTR表示一个指向不会也不能被修改的常量字符串的指针.LPSTR指向的就不是常量的,可以被修改. 你可能还会看到一个T混在里面.现在不要管它,除非你打算与Unicode打交道,它沒有其它的意义.Copyright©1998-2003,BrookMiles(theForger).Allrightsreserved.一个简单的窗口范例:simple_window 有时候有人在IRC上问:”我怎么才实现一个窗口?”...我觉得不是一句两句能说得清楚.虽然一旦你搞清楚你要做什么后并不难,但是你的确需要做一些事情来使显示一个窗口;这些事情不是在聊天室中一下子说得清楚的.我总是喜欢先做一件事情然后来理解它...所以先给出一个简单窗口的代码稍后再做解释.#includewindows.hconstcharg_szClassName[]=myWindowClass;//Step4:theWindowProcedureLRESULTCALLBACKWndProc(HWNDhwnd,UINTmsg,WPARAMwParam,LPARAMlParam){switch(msg){caseWM_CLOSE:DestroyWindow(hwnd);break;caseWM_DESTROY:PostQuitMessage(0);break;default:returnDefWindowProc(hwnd,msg,wParam,lParam);}return0;}intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow){WNDCLASSEXwc;HWNDhwnd;MSGMsg;//Step1:RegisteringtheWindowClasswc.cbSize=sizeof(WNDCLASSEX);wc.style=0;wc.lpfnWndProc=WndProc;wc.cbClsExtra=0;wc.cbWndExtra=0;wc.hInstance=hInstance;wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);wc.hCursor=LoadCursor(NULL,IDC_ARROW);wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);wc.lpszMenuName=NULL;wc.lpszClassName=g_szClassName;wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION);if(!RegisterClassEx(&wc)){MessageBox(NULL,WindowRegistrationFailed!,Error!,MB_ICONEXCLAMATION|MB_OK);return0;}//Step2:CreatingtheWindowhwnd=CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,Thetitleofmywindow,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,240,120,NULL,NULL,hInstance,NULL);if(hwnd==NULL){MessageBox(NULL,WindowCreationFailed!,Error!,MB_ICONEXCLAMATIO