VC入门必备--基础知识(二)
Windows下的程序的结构和组成元素
Windows下的程序的基本组成元素是代码, 用户界面资源(User Interface Resource)和动态链接的库模块(Library Module)。
代码,是应用程序的主要内容,Windows下的应用程序必须要有两个函数:
1、WinMain,它为操作系统提供了进入点(Entry Point),是所有Windows-Based应用程序都必须要有的函数。它也用来创建初始Window和启动Message检索;
2、Window Procedure,它用于处理所有从操作系统发送到Window的Message,每一个Window都有一个相关联的Window Procedure。Window Procedure用来决定Window的Client Area(即客户窗口,例如Notepad中用来写字的空白部分)显示什么以及如何响应用户的输入。Window Procedure处理Message时,既可以用专门添加的代码来处理Message,也可以直接把Message传递给默认的Window Procedure——DefWindowProc。一个Windows-Based应用程序可以包含多个不同名的Window Procedure。
用户界面资源,菜单(Menu),对话框(Dialog box)等图形用户界面的元素,就叫做资源。它们被当成模板(Template)储存在相应的可执行文件或DLL文件的只读(Read-Only)区域,当有需要时,Windows就调用这个资源区域并动态创建所需要的GUI元素。主要有以下几种资源:
Accelerator(快捷键表), 储存快捷键和相应的命令
Bitmap(位图),一种图形格式
Diablo Box,包含对话框的控件(Control), 布局和属性的细节
Icon(图标),一种特殊的位图
Menu(菜单),包含菜单及其选项的文本和布局
String Table(字符串表),储存字符串及其ID
Toolbar(工具栏),包含工具栏的布局和按钮的位图
Version(版本),储存程序的状态信息,例如程序名,作者,版权,版本号等
Cursor(光标),包含用于绘制光标的特殊的位图
库模块,主要是指在运行时可以被动态链接的二进制文件,即DLL。
默认的Window Procedure——DefWindowProc,是Windows系统提供的一个函数,用于处理某些通用的Win32-based应用程序的 Messages(例如最大化、最小话窗口,显示目录等)。如果DefWindowProc不能处理该Message,那么它就被忽略。
当一个应用程序被启动时,将会按顺序发生下列事件(上一节也提到过这个问题)
1、操作系统创建一个新进程和一个起始线程;
2、应用程序的代码被载入内存;
3、DLL也被载入内存(如果有的话);
4、从物理内存分配其他项目(例如数据,堆栈等)的空间,并被映射到虚拟地址空间中;
5、应用程序开始执行。
在Windows-Based应用程序中,Windows是应用程序和用户之间传递信息的主要方法。Windows-Based的应用程序为了接收从系统队列传来的Message,是通过以下方法实现的:
1、当Windows-Based的应用程序启动后,操作系统和这个应用程序就通过进入点(WinMain函数)联系起来。
2、应用程序创建一个或多个Windows,每个Window都包含有一个Window Procedure函数,用来决定Window显示什么以及Window如何响应用户的输入。
3、有专门的代码将Message队列中的Message循环检索出来,并传递给相应的Window Procedure,而不是直接传给Window。这样就可以使应用程序在Message被送到Window之前预先处理它。
到了下一节,我们将会用一个简单的源程序说明以上元素和步骤。
以下是本节新出现的专业名词
用户界面资源 = User Interface Resource
库模块 = Library Module
进入点 = Entry Point
客户窗口 = Client Area(例如Notepad中用来写字的空白部分)
菜单 = Menu
对话框 = Dialog box
模板 = Template
只读 = Read-Only
控件 = Control
快捷键表 = Accelerator
位图 = Bitmap
图标 = Icon
字符串表 = String Table
工具栏 = Toolbar
版本 = Version
光标 = Cursor
动态链接 = Dynamic Linking
源程序示例
本节列出了一个简单的源程序,来说明上两节的内容。请大家结合上两节的内容来看看下面的源程序,不需要完全看懂,只用理解大概的框架和流程就行了,注意黑体字部分。源程序如下:
// 摘自http://msdn.microsoft.com/library/partbook/win98dh/thewinmainprocedure.htm
// 包含头文件windows.h
#include <windows.h>
// 预先声明Message Handler,可以叫做任何名字,这里是MyWindowProcedure
LRESULT CALLBACK MyWindowProcedure(HWND,UINT,WPARAM,LPARAM);
// 以下是所有Windows程序都需要的WinMain函数
// WinMain主要用来实现三个功能:
// 1. 注册Window Class;
// 2. 在内存中创建Window并初始化Window的属性;
// 3. 创建一个Message Loop来检查Message Queue中有没有该Window的Message。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)
{
static char szAppName[] = “WinHello”; // 定义一个字符串
HWND hwnd; // 定义一个Window Handle变量
MSG msg; // 定义一个Message结构的变量,用来储存Message的信息
WNDCLASS wc; // 定义一个Window Class数据结构,用来储存Window Class的属性
//下面这段代码用来定义Window的属性,例如Message Handler的地址、窗口背景、光标和图标等
wc.style=CS_HREDRAW|CS_VREDRAW; // 设置style: 当窗口改变大小时就重新绘制窗口
wc.lpfnWndProc=(WNDPROC)MyWindowProcedure; // 设定Window Procedure
wc.cbClsExtra=0; // 用来储存Class Structure后的额外的数据,这里不需要
wc.cbWndExtra=0; // 用来储存Window Instance后的额外的数据,这里不需要
wc.hInstance=hInstance; // Window Procedure所在的Instance
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); // class的图标
wc.hCursor=LoadCursor(NULL,IDC_ARROW); // class的光标
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); // 背景刷
wc.lpszMenuName=NULL; // 菜单资源的名字,这里没有
wc.lpszClassName=szAppName; // 应用程序的名字
// 注册Window,通过调用API函数RegisterClass来实现
// 注册Window Class的一个目的就是将Window和Window Procedure关联起来
RegisterClass(&wc);
// 注册Window Class后,WinMain就调用CreateWindow函数来创建应用程序的Window
hwnd=CreateWindow(
szAppName, // 已注册的Class名字
“Hello, World – Windows_98 Style”, // Window名字
WS_OVERLAPPEDWINDOW, // Window风格
CW_USEDEFAULT, // Window起点的X坐标
CW_USEDEFAULT, // Window起点的Y坐标
CW_USEDEFAULT, // Window的宽度
CW_USEDEFAULT, // Window的高度
HWND_DESKTOP, // 父窗口的handle
NULL, // 菜单的handle
hInstance, // 应用程序instance的handle
NULL // window-creation数据的指针
);
// 以下两条语句用来显示Window
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
// 用while循环语句来检索并发送Messages
// 从Message Queue中检索Message,并将它放到变量msg中。
// 当收到”WM_QUIT”这个Message时,GetMessage函数就返回0,循环结束。而且WinMain函数也结束,程序终止。
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg); // 将Virtual-Key Messages转化为Character Messages
DispatchMessage(&msg); // 将Message发送到Window Procedure
}
return msg.wParam;
}
// MyWindowProcedure函数处理WM_PAINT和WM_DESTROY这两个Message,然后必须调用DefWindowProc去处理其他Message
LRESULT CALLBACK MyWindowProcedure(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps; // 定义一个PAINTSTRUCT结构的变量,用来储存绘制Window的Client Area的信息
HDC hdc; // 定义一个HDC变量
LPCTSTR text=”Welcome!”; // 定义一个LPCTSTR类型的字符串指针
// 用switch语句来处理WM_PAINT和WM_DESTROY这两个Message
switch(message)
{
case WM_PAINT:
// 下面5条语句是用来在屏幕上输出文字的,我们在后面的章节会详细讨论这个问题的,这里就不多说了
hdc=BeginPaint(hwnd,&ps);
RECT rect;
GetClientRect(hwnd,&rect);
TextOut(hdc,(rect.right-rect.left)/2,(rect.bottom-rect.top)/2,text,strlen(text));
EndPaint(hwnd,&ps);
return 0;
// 处理退出消息
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
// 调用默认的Window Procedure,使所有Message都可以被处理
return DefWindowProc(hwnd,message,wParam,lParam);
}
运行上面程序的步骤:
1、选菜单 File–>New…–>Projects–>Win32 Application
2、在Project Name中输入vchack_01_002_003(其它名字也行)
3、其他地方就保留默认值就行了,然后按”OK”
4、选中”An empty project”,然后按”Finish”
5、再按次”OK”
6、按Toolbar上的按钮”New Text File”新建一个空白文件
7、将以上源程序复制到那个空白文件中,然后按Toolbar上的按钮”Save”来储存文件,文件名为vchack_01_002_003.cpp
8、按左下角的”FileView”,然后按”vchack_01_002_003 files”旁边的”+”号展开这个目录
9、在”Source Files”上按鼠标右键,选”Add Files to Folder…”
10、选中vchack_01_002_003.cpp这个文件,然后按”OK”
11、选”Build”菜单中的”Build vchack_01_002_003.exe”
12、选”Build”菜单中的”Execute vchack_01_002_003.exe”来运行这个程序
以下是本节新出现的专业名词
类 = Class
窗口类 = Window Class
数据结构 = Data Structure
消息处理器 = Message Handler
实例 = Instance
句柄 = Handle
工程 = Project
多谢你阅读我的csdn blog,我已经建立了个人博客,基本把这里的文章都转到个人博客了,欢迎交流指教!
VC入门必备--基础知识(二)
http://www.jeanva.cn/post/57.html