}
/*Results:
如单击提示框的"是(Y)"钮,则程序显示"退出(yes),代码IDYES是:
6"
or:
如单击提示框的"否(N)"钮,则程序显示"不打算退出(no),其代码IDNO是:
7"
*/
此程序可根据用户对提示框的不同响应而作出不同运行结果。
函数MessageBox的原型如下:
intMessageBox(
HWNDhWnd,//h表示句柄类型,为整型变量,它是提示框的父窗口
//(用于显示提示框的窗口)的句柄,NULL表示默认的父窗口是桌面
LPCTSTRlpText,//lp代表长整数指针类型。
此处为字符串,
//就是提示框所显示的提示信息
LPCTSTRlpCaption,//字符串,就是提示框的标题栏信息
UINTuType//u代表无符号整数类型。
此处为提示框类型,如下表所示
);//命名规则请看§9.1“匈牙利编程命名规则”。
提示框类型(uType)
内容
MB_ABORTRETRYIGNORE
提示框有三个按钮:
Abort、Retry和Ignore
MB_OK(默认值,即NULL)
提示框有一个按钮:
OK
MB_OKCANCEL
提示框有两个按钮:
OK和Cancel
MB_RETRYCANCEL
提示框有两个按钮:
Retry和Cancel
MB_YESNO
提示框有两个按钮:
Yes和No
MB_YESNOCANCEL
提示框有三个按钮:
Yes、No和Cancel
下面还将对窗口句柄作详细解释。
10.1.2工程的创建
前面§10.1.1所介绍的程序,虽能弹出提示框,供用户交互互动。
但其功能极其有限。
如须发挥真正的窗口功能,则应使用Windows编程技术来编写较为复杂的程序。
Windows编程分为两类项目:
Win32API编程和MFC编程。
Windows编程的第一类是Win32API编程。
第九章中提到,Win32API是32位Windows操作系统的应用程序编程接口(API,ApplicationProgrammingInterface)的简称。
程序简称为Win32程序。
现在Windows操作系统下运行的大多数应用程序都是Win32应用程序。
VisualC++6.0支持的Win32项目有如下四种:
(1)Win32Application:
【Win32应用程序】
(2)Win32ConsoleApplication:
【Win32控制台应用程序】
(3)Win32Dynamic-linkLibrary:
【Win32动态链接库】
(4)Win32Static-linkLibrary:
【Win32静态链接库】
本章主要介绍第一种,即Win32Application:
【Win32应用程序】项目。
通过向导(Wizard)建立Win32应用程序的初步框架文件(代码和资源等),它直接使用WindowsAPI编写程序而不用MFC库。
创建这类工程将会看到最真实的Windows应用程序,它没有经过MFC的层层封装,没有一系列的类声明,有的只是一个以WinMain为开始点的应用程序。
在这个应用程序中,由用户自己一步步地创建窗口、建立消息循环、接收Windows消息、发送Windows消息、编写自己的消息处理函数、撤销窗口等等。
所有的Windows应用程序的运行机制在这种程序中全对用户敞开。
第十一章末尾将很简单地介绍第三种,即Win32Dynamic-linkLibrary:
【Win32动态链接库】。
第十一章将介绍Windows编程的第二类:
MFC项目,它利用Windows系统的各种类,将它们组合起来构成了一个应用程序的框架,它的目的就是让程序员在此基础上来建立Windows系统下的应用程序。
MFC是“微软基础类”(MicrosoftFoundationClassLibrary)的缩写;但有些书上愿意称之为“框架基础类”(MainframeFoundationClass)。
总体上,MFC框架定义了应用程序的轮廓,并提供了用户接口的标准实现方法,程序员所要做的就是通过预定义的接口把具体应用程序特有的东西填入这个轮廓。
VC++提供了相应的工具来完成这个工作:
AppWizard可以用来生成初步的框架文件(代码和资源等);资源编辑器用于帮助直观地用图形来设计用户接口;ClassWizard用来协助添加代码到框架文件;最后即可编译生成应用程序。
MFC项目就是通过这样一个基础类库实现了应用程序特定的逻辑。
VisualC++6.0支持以下三种MFC项目:
(1)MFCActivexControlwizard:
MFC【ActiveX控件】向导
(2)MFCAppwizard[dll]:
MFC应用程序向导【dll动态库工程】
(3)MFCAppwizard[exe]:
MFC应用程序向导【exe可执行工程】
第十一章将讲解上述的第二和第三项。
Win32API编程不同于普通C++编程。
C++编程时,不必预先创建工程(project),只须在编完源程序文件后,由系统自动创建工程。
但在Win32API编程时,必须事先创建工程。
步骤如下:
(一)从File菜单中选择“New”(或使用快捷键Ctrl+N),此时出现名为New的对话框。
在此对话框中,单击或选择Projects标签。
在下拉菜单中选择“Win32Application”。
同时在“Projectname:
”域中填入工程名,例如HelloEveryOne。
此时系统为用户建立一个相同名称的子文件夹“HelloEveryOne”。
用户可以在“Location:
”域中选择或修改该子文件夹的路径。
同时保持另外两个域即“Createnewworkspace”和“Win32”的内容不变。
单击OK。
(二)此时出现一个名为“Win32Application–Step1of1”的对话框。
选择“Atypical“HelloWorld!
”application”选项。
单击“Finish”。
(三)此时又出现一个名为“NewProjectInformation”的对话框。
显示所创建的新工程的有关信息。
如果信息合适,可单击“OK”,创建过程结束。
如果信息有错,例如ProjectDirectory有错,则可单击“Cancel”,重新创建工程。
(四)工程创建之后,为用户提供一个源文件框架HelloEveryOne.cpp。
其中留出很多空位,标以“//TODO:
Placecodehere.”或“//TODO:
Addanydrawingcodehere...”等等,以供用户根据编程需要修改或补充必要的代码。
但用户不受此限制,可以在任何地方修改或补充代码。
本章的所有应用程序在建立过程中,都按照上述过程操作,建立工程后,只补充了主要源文件例如HelloEveryOne.cpp。
其余文件没有改动。
10.1.3头文件和系统生成的各类文件
以上两个例子中,主要头文件不再是iostream.h,而是windows.h。
这是Windows编程所用的最重要的头文件。
有关内容如下:
/*windows.h
MasterincludefileforWindowsapplications.*/
……
#include
#include
#include
#include
……
这四个头文件是必须包含的。
另外有一些头文件是有条件地包含的,故不在此提及。
四个头文件的主要内容为:
winbase.h--Thismoduledefinesthe32-BitWindowsBaseAPIs。
它包含所有内核函数的函数原型,还包含一些常量定义,例如:
#defineIGNORE0//Ignoresignal
#defineINFINITE0xFFFFFFFF//Infinitetimeout
winuser.h--USERproceduredeclarations,constantdefinitionsandmacros,它包含用户应用函数的函数原型、常量定义、宏定义等。
其中包括以上程序所用的函数MessageBox(……)。
wingdi.h–GDIproceduredeclarations,constantdefinitionsandmacros。
它包含图形设备接口(GDI,GraphicsDeviceInterface)函数的函数原型、常量定义、宏定义等。
windef.h--BasicWindowsTypeDefinitions。
它包含Windows编程所用基本数据类型定义。
例如第九和第十两章中用到的定义:
//函数调用约定
#defineCDECL_cdecl
#definePASCAL__stdcall
#defineCALLBACKPASCAL
#defineWINAPI__stdcall
#defineAPIENTRYWINAPI
//常量定义
#defineNULL0
或者#defineNULL((void*)0)
#defineFALSE0
#defineTRUE1
//数据类型定义
TypedefintINT;
typedefunsignedintUINT;
typedefunsignedlongDWORD;
typedefintBOOL;
typedefcharTCHAR,*PTCHAR;
typedefunsignedcharBYTE;
typedefunsignedshortWORD;
typedefUINTWPARAM;
typedefLONGLPARAM;
typedefLONGLRESULT;
#defineLOWORD(l)((WORD)(l))
#defineHIWORD(l)((WORD)(((DWORD)(l)>>16)&0xFFFF))
VC是一个集成开发工具,提供了软件代码自动生成和可视化的资源编辑功能。
按照以上§10.1.2所述三个步骤创建工程之后,系统同时为该工程建立以下各种类型的12个文件,下面简要地介绍它们:
(1)HelloEveryOne.cpp:
该应用程序的主要源文件框架。
(2)HelloEveryOne.h:
该应用程序的主要头文件。
(3)StdAfx.h和
(4)StdAfx.cpp:
这两个文件用于建立一个目标文件StdAfx.obj和一个预编译头文件HelloEveryOne.pch(precompiledheader(PCH))。
(5)resource.h:
用于定义新的资源ID。
(6)small.ico:
小图标文件,包含此应用程序的一个较小面积(16x16)的图标,它被包含于资源文件HelloEveryOne.rc中。
在将来创建的窗口中,此小图标被显示在窗口左上角。
(7)HelloEveryOne.ico:
图标文件,包含此应用程序的一个图标(32x32),它被包含于资源文件HelloEveryOne.rc中。
(8)HelloEveryOne.dsp:
工程文件(theprojectfile),文本格式。
此文件包含工程级别上的信息,用于建立单个工程或子工程等。
其它用户可分享该工程文件。
(9)HelloEveryOne.dsw:
工程区文件(theprojectworkspacefile),类似于工程文件。
当须要重新调试工程时,首先应调用这两个工程文件。
(10)HelloEveryOne.rc:
资源文件。
它包含程序所用的一系列窗口资源,包括图标、位图、和光标等。
可供用户直接编辑。
(11)HelloEveryOne.ncb:
无编译浏览文件,编译工程后会自动生成。
(12)ReadMe.txt:
此文件告诉用户,系统已为用户建立了一系列文件。
创建工程从而建立上述12个文件后,即可进行编译和连接的工作。
在用户编写完源文件HelloEveryOne.cpp(这是用户的主要工作)之后,系统将各类资源编译、将源文件StdAfx.cpp和HelloEveryOne.cpp编译,最后进行连接。
结果又建立了以下10个文件:
(13)HelloEveryOne.obj:
这是源文件HelloEveryOne.cpp编译后的目标文件。
(14)StdAfx.obj:
这是源文件StdAfx.cpp编译后的目标文件。
(15)HelloEveryOne.plg:
这是编译信息文件(HTML文件),保存了该程序的编译和连接过程的记录,包含编译时的error和warning信息。
(16)HelloEveryOne.pch:
预编译文件,文件非常大,存放着已经编译的部分代码,以便以后建立工程时不再编译它们,从而可以加快编译速度。
(17)HelloEveryOne.pdb:
数据库文件,记录了程序有关的一些数据和调试信息。
(18)HelloEveryOne.exe:
这是最主要的成果文件,程序的可执行文件。
(19)HelloEveryOne.res文件。
(20)HelloEveryOne.ilk文件。
(21)vc60.idb文件。
(22)vc60.pdb文件。
10.2典型程序之一---窗口中显示文本
10.2.1源文件
HelloEveryOne.cpp是一个最简单的例子,但却很典型。
现在详细分析一下。
[例1]创建一个窗口,并且在窗口中央显示文本“HelloEveryOne!
”。
创建工程之后,系统为该工程建立了该应用程序的主要源文件的框架,供用户填入必需的代码。
以下是填入代码后的源文件。
//HelloEveryOne.cpp:
Definestheentrypointfortheapplication.
#include"stdafx.h"
#include"resource.h"
//GlobalVariables:
HINSTANCEhInst;//currentinstance
TCHARszTitle[]="Demonstration!
";//Thetitlebartext
TCHARszWindowClass[]="HelloEveryOne!
";//contenttobeshown
//Forwarddeclarationsoffunctionsincludedinthiscodemodule:
ATOMMyRegisterClass(HINSTANCEhInstance);
BOOLInitInstance(HINSTANCE,int);
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
LRESULTCALLBACKAbout(HWND,UINT,WPARAM,LPARAM);
intAPIENTRYWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPSTRlpCmdLine,
intnCmdShow)
{
//TODO:
Placecodehere.
MSGmsg;
HACCELhAccelTable;
//Initializeglobalstrings
MyRegisterClass(hInstance);
//Performapplicationinitialization:
if(!
InitInstance(hInstance,nCmdShow))
{
returnFALSE;
}
hAccelTable=LoadAccelerators(hInstance,(LPCTSTR)IDC_HELLOEVERYONE);
//Mainmessageloop:
while(GetMessage(&msg,NULL,0,0))
{
if(!
TranslateAccelerator(msg.hwnd,hAccelTable,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
returnmsg.wParam;
}
//FUNCTION:
MyRegisterClass()
//PURPOSE:
Registersthewindowclass.
//COMMENTS:
//Thisfunctionanditsusageisonlynecessaryifyouwantthiscode
//tobecompatiblewithWin32systemspriortothe'RegisterClassEx'
//functionthatwasaddedtoWindows95.Itisimportanttocallthisfunction
//sothattheapplicationwillget'wellformed'smalliconsassociated
//withit.
ATOMMyRegisterClass(HINSTANCEhInstance)
{
WNDCLASSEXwcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=(WNDPROC)WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,(LPCTSTR)IDI_HELLOEVERYONE);
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=(LPCSTR)IDC_HELLOEVERYONE;
wcex.lpszClassName=szWindowClass;
wcex.hIconSm=LoadIcon(wcex.hInstance,(LPCTSTR)IDI_SMALL);
returnRegisterClassEx(&wcex);
}
//FUNCTION:
InitInstance(HANDLE,int)
//PURPOSE:
Savesinstancehandleandcreatesmainwindow
//COMMENTS:
//Inthisfunction,wesavetheinstancehandleinaglobalvariableand
//createanddisplaythemainprogramwindow.
BOOLInitInstance(HINSTANCEhInstance,intnCmdShow)
{
HWNDhWnd;
hInst=hInstance;//Storeinstancehandleinourglobalvariable
hWnd=CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
if(!
hWnd)
{
returnFALSE;
}
ShowWindow(hWnd,nCmdShow);
returnTRUE;
}
//FUNCTION:
WndProc(HWND,unsigned,WORD,LONG)
//PURPOS