Windows程序设计基本概念

Windows程序设计基本概念

1. Windows运行机制-----消息驱动

消息驱动又叫做事件驱动,是Windows编程采用的程序设计思想。在这种程序结构中,程序没有明显的开始、结束,程序流程的控制由各种随机发生、不确定、没有预先设定顺序的事件的发生来触发。是一个不断产生消息和处理消息的过程。

也就是说程序一运行开始处于等待消息状态,取得消息以后,就对其做出相应进行处理,处理完以后又进入等待消息状态。这种程序结构与windows操作系统结合非常紧密,最明显一点就是消息的管理是由操作系统完成的。应用程序从操作系统获得消息的两种方式:一种就是应用程序调用windows提供的消息获取函数;另外一种就是回调函数,由操作系统自己调用。

1窗口:是Windows操作系统最重要最基本的一个概念。它是一个正在运行的应用程序相对应的矩形区域,通过它用户可以和应用程序进行交互。

2客户区:是窗口中最大的一块空白的矩形区域,是用户和系统进行交互的主要区域,一般用于显示应用程序的输出。

3标题栏:位于窗口顶部,用于显示应用程序名称的。

4菜单栏:位于标题栏下方,菜单栏列出了应用程序支持的大部分功能。 5图标:适用于提醒用户的一个小图像,代表一个应用程序。

6光标:Windows光标显示在屏幕上的一个小位图。

7工具栏:一般位于菜单栏下方,上面有一些位图按钮,代表一些常用功能。 8状态栏:位于这个窗口底端,用于输出菜单提示信息和一些其他详细信息。 9对话框:一种特殊的窗口,用于接受用户的输入输出。

10控件:对话框上的许多小窗口都是控件。如按钮,编辑框等都是控件。

2. Windows应用程序设计相关基本术语

1窗口:是应用程序操作的基本单元,是用户可以通过它和应用程序进行交互的接口环境,也是系统管理应用程序的基本单位。从程序运行的内存组织结构看,窗口对应一个数据结构WNDCLASS。

2实例:实际上实例就是一个可执行程序在内存中的拷贝。一个可执行程序运行多次,在内存中就有多个内存拷贝。系统是通过实例句柄来识别一个可执行程序的拷贝。

3句柄:系统用来识别不同对象或者同类对象的不同实例的“编号”。它是一个无符号整数。

几乎所有对对象的引用都是通过句柄来进行的。如使用HWND、HCURSOR、HDC。 4资源:构成应用程序的元素称为资源:菜单、工具条、位图、字符串等。

5窗口函数:用户通过窗口和应用程序交互时产生的消息,送给一个函数进行处理。该函数体结构大致由一个Switch结构组成,是消息驱动机制的发动机。

6图形设备接口:GDI(Graphic Device Interface)时Windows系统的重要组成部分。负责系统和用户或者绘图程序之间的信息交换,并控制输出设备上图形和文字的输出。最大的优点就是设备无关性:将程序员和设备相隔离,程序员不必关心物理设备的细节,直接调用相关的API函数就可以在输出设备上显示图形或者文字。

7回调函数:写好了等系统进行调用的函数。只能由系统自动调用。前面所说的窗口函数就是一个典型的回调函数。

3. Win32应用程序结构和执行原理

例 Win32应用程序结构分析和执行原理解释

使用Visual C++ 6.0建立一个简单的Win32应用程序:选择File菜单的New,在出现的对话框中,选择Projects栏目(新建工程),并点取其下的Win32 Application项,表示使用Win32环境创建应用程序。先在Locatin(路径)中填入"D:\TEST\",然后在Project Name(项目名称)中填入"MyWin",其它按照缺省设置)。单击OK按钮。

添加MyWin.cpp文件到工程,文件内容如下:

编译,运行该程序。运行结果为弹出一个简单的Windows窗口,提示:你好,我是简单的Win!点击鼠标右键,会谈出提示框:你按下了鼠标右键!

按下Esc键,会提示:你按下了ESC键!这是一个最简单的Win32应用程序,其他较复杂的Windows应用程序都是在这样的程序框架上扩展得到的。

下面对框架里边比较重要的函数进行解释说明。

1. WinMain()函数

WinMain()函数是应用程序开始执行时的入口点,通常也是应用程序结束任务退出时的出口点。它与DOS程序的main()函数起同样的作用,有一点不同的是,WinMain()函数必须带有四个参数,它们是系统传递给它的。WinMain()函数的原型如下:

int PASCAL WinMain( HINSTANCE hInstance, //当前实例句柄

HINSTANCE hPrevInstance, //前一个实例句柄

LPSTR lpCmdLine, int nCmdShow) //命令行字符 //窗口显示方式 第一个参数hInstance,是标识该应用程序当前的实例的句柄。它是HINSTANCE类型,HINSTANCE是Handle of Instance的缩写,表示实例的句柄。hInstance是一个很关键的数据,它唯一的代表该应用程序,在后面初始化程序主窗口的过程中需要用到这个 参数。这里有两个概念,一个是实例,一个是句柄。实例代表的是应用程序执行的整个过程和方法,一个应用程序如果没有被执行,只是存在 于磁盘上,那么就说它是没有被实例化的;只要一执行,则说该程序的一个实例在运行。句柄,顾名思义,指的是一个对象的把柄。在Windows中,有各种各 样的句柄,它们都是32位的指针变量,用来指向该对象所占据的内存区。句柄的使用,可以极大的方便Windows管理其内存中的各种对象。

第二个参数是hPrevInstance,它是用来标识该应用程序的前一个实例句柄。对于基于Win32的应用程序来说,这个参数总是NULL。这是因为在Win95操作系统中, 应用程序的每个实例都有各自独立的地址空间,即使同一个应用程序被执行了两次,在内存中也会为它们的每一个实例分配新的内存空间,所以一个应用程序被执行 后,不会有前一个实例存在的可能。也就是说,hPrevInstance这个参数是完全没有必要的,只是为了提供与16位Windows的应用程序形式上 的兼容性,才保留了这个参数。在以前的16位Windows环境下(如Windows3.2),hPrevInstance用来标识与hInstance 相关的应用程序的前一个句柄。 第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。如在Win95的"开始"菜单中单击"运行",输入"Mywin hello",则此参数指向的字符串为"hello"。

最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOW、SW_HIDE、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED等。

2. 注册窗口类

上面的例程中,创建主窗口的函数是InitMyWindow()。通常要对填充一个窗口类结构WNDCLASS, 然后调用RegisterClass()对该窗口类进行注册。每个窗口都有一些基本的属性,如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色、 处理窗口消息函数的名称等等。注册的过程也就是将这些属性告诉系统,然后再调用CreateWindow()函数创建出窗口。这好比人们量体裁衣。

typedef struct _WNDCLASS {

UINT style; //窗口的风格

WNDPROC lpfnWndProc; //指定窗口的消息处理函数的远指针

int cbClsExtra; //指定分配给窗口类结构之后的额外字节数

int cbWndExtra; //指定分配给窗口实例之后的额外字节数

HANDLE hInstance; //指定窗口过程所对应的实例句柄

HICON hIcon; //指定窗口的图标

HCURSOR hCursor; //指定窗口的鼠标

HBRUSH hbrBackground; //指定窗口的背景画刷

LPCTSTR lpszMenuName; //窗口的菜单资源名称

LPCTSTR lpszClassName; //该窗口类的名称

} WNDCLASS;

在Win95和WinNT的具有新界面特性的系统中,为了支持新的窗口界面特性,还有一种扩展的窗口类型WNDCLASSEX,它的定义如下:

typedef struct _WNDCLASSEX { UINT cbSize; //指定WNDCLASSEX结构的大小 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; //窗口的小图标 } WNDCLASSEX; 结构中相关成员这里进行简单解释一下,实际应用过程中查阅MSND。填充完毕后,调用RegisterClass函数进行窗口注册。函数原型如下:

ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );

该函数如调用成功,则返回一个非0值,表明系统中已经注册了一个名为MyWin的窗口类。如果失败,则返回0。

3. 创建窗口

当窗口类注册完毕之后,并不会有窗口显示出来,因为注册的过程仅仅是为创建窗口所做的准备工作。实际创建一个窗口的是通过调用CreateWindow()函数完成的。窗口类中已经预先定义了窗口的一般属性,而CreateWindow()中的参数可以进一 步指定一个窗口的更具体的属性,在MyWin程序中,是如下调用CreateWindow()函数来创建窗口的:

hwnd = CreateWindow( "MyWin", //创建窗口所用的窗口类的名称 "一个简单的Win32程序", //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格,定义为普通型 200, //窗口位置的x坐标 200, //窗口位置的y坐标 500, //窗口的宽度 400, //窗口的高度 NULL, //父窗口句柄 NULL, //菜单句柄 hInstance, //应用程序实例句柄* NULL ); //一般都为NULL

如果窗口创建成功,返回值是新窗口的句柄,否则返回NULL。

显示和更新窗口

窗口创建后,并不会在屏幕上显示出来,要真正把窗口显示在屏幕上,还得使用ShowWindow()函数,其原型如下:

BOOL ShowWindow( HWND hWnd, int nCmdShow ); 参数hWnd指定要显示得窗口的句柄,nCmdShow表示窗口的显示方式,这里指定为从WinMain()函数的nCmdShow所传递而来的值。

由于ShowWindow()函数的执行优先级不高,所以当系统正忙着执行其它的任务时,窗口不会立即显示出来,此时,调用UpdateWindow()函数以可以立即显示窗口。其函数原型如下:

BOOL UpdateWindow( HWND hWnd );

4. 消息循环

在Win32编程中,消息循环是相当重要的一个概念,看似很难,但是使用起来却是非常简单。在WinMain()函数中,调用InitWindow()函数成功的创建了应用程序主窗口之后,就要启动消息循环,其代码如下:

while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

Windows应用程序可以接收以各种形式输入的信息,这包括键盘、鼠标动作 、记时器产生的消息,也可以是其它应用程序发来的消息等等。Windows系统自动监控所有的输入设备,并将其消息放入该应用程序的消息队列中。Windows消息结构及分类在下一章节进行讲解。

GetMessage()函数还可以过滤消息,它的第二个参数是用来指定从哪个窗口的消息队列中获取消息,其它窗口的消息将被过滤掉。如果该参数为NULL,则GetMessage()从该应用程序线程的所有窗口的消息队列中获取消息。

第三个和第四个参数是用来过滤MSG结构中主消息值的,主消息值在wMsgFilterMin和wMsgFilterMax之外的消息将被过滤掉。如果这两个参数为0,则表示接收所有消息。 当且仅当GetMessage()函数在获取到WM_QUIT消息后,将返回0值,于是程序退出消息循环。

TranslateMessage()函数的作用是把虚拟键消息转换到字符消息,以满足键盘输入的需要。DispatchMessage()函数所完成的工作是把当前的消息发送到对应的窗口过程中去。

5. 消息处理函数

消息处理函数又叫窗口过程,在这个函数中,不同的消息将用switch语句分配到不同的处理程序中 去。Windows的消息处理函数都有一个确定的样式,即这种函数的参数个数和类型以及其返回值的类型都有明确的规定。在VC的说明书中,消息处理函数的 原型是这样定义的:

LRESULT CALLBACK WindowProc(

HWND hwnd, //接收消息窗口的句柄 UINT uMsg, //主消息值 WPARAM wParam, //副消息值 LPARAM lParam //副消息值 ); 如果你的程序中还有其它的消息处理函数,也都必须按照上面的这个样式来定义,但函数名称可以随便取。MyWin中的WinProc()函数就是这样一个典型的消息处理函数。

消息处理函数的四个参数是由GetMessage()函数从消息队列中获得MSG结构,然后分解后得到的。第二个参数uMsg和MSG结构中的message值是一致的,代表了主消息值。程序中用switch语句来将不同类型的消息分配到不同的处理程序中去。

WinProc()函数明确的处理了4个消息,分别是WM_KEYDOWN(击键消息)、WM_RBUTTONDOWN(鼠标右键按下消息)、WM_PAINT(窗口重画消息)、WM_DESTROY(销毁窗口消息)。

值得注意的是,应用程序发送到窗口的消息远远不止以上这几条,象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等这样频 频使用的消息就有几十条。为了减轻编程的负担,Windows的API提供了DefWindowProc()函数来处理这些最常用的消息,调用了这个函数后,这些消息将按照系统默认的方式得到处理。

因此,在switch_case语句中,只须明确的处理那些有必要进行特别响应的消息,把其余的消息交给DefWindowProc()函数来处理,是一种明智的选择,也是你必须做的一件事。

6. 结束消息循环

当用户按Alt+F4或单击窗口右上角的退出按钮,系统就向应用程序发送一条WM_DESTROY的消息。在处理此消息时,调用了 PostQuitMessage()函数,该函数会给窗口的消息队列中发送一条WM_QUIT的消息。在消息循环中,GetMessage()函数一旦检 索到这条消息,就会返回FALSE,从而结束消息循环,随后,程序也结束。

4. Windows应用程序编程接口

Windows操作系统对外通过两种接口提供服务:普通用户操作接口服务和程序员接口服务。其中用户操作接口服务是通过用户操作来进行完成的,而程序员接口服务是提供一系列底层的实现操作系统最基本的函数(接口)共程序员调度来完成相关功能。比如一个文件的拷贝,

普通用户可以通过鼠标菜单选择操作或者命令来完成,程序员可以通过程序代码调用相关文件操作的函数(API)来完成相同的功能。

所有这些系统底层、实现最基本功能、供程序员调用的函数集中起来形成一个集合,这就是API(Application Programming Interface)。Windows API编程是开发Windows应用程序最古老由最原始,同时又是试验一个程序员对windows操作系统及相关数据结构掌握程度的最好方法。

应该知道:所有其它类库以及后面要讲到的MFC,都是对这些最基本功能的函数进行封装来实现的。任何使用MFC能实现的功能,使用API同样能够实现,而且能够更加灵活。了解并学习API编程,可以看到使用MFC编程所看不到的东西,更深入了解Windows系统运行机制,同时帮助我们学习MFC编程。

三个动态连接库:Windows内核库(Kernel32.dll)、Windows用户界面管理库(User32.dll)、Windows图形设备界面库(Gdi32.dll),这些动态连接库共同构成了Win32 API函数。 Windows内核库(Kernel32.dll):所有底层的核心功能如任务管理、内存管理,进程线程文件管理等的函数都在这个动态连接库中;

Windows用户界面管理库(User32.dll):窗口管理,菜单管理以及通信等相关函数都在该动态连接库中;

Windows图形设备界面库(Gdi32.dll):集合了所有用于管理系统支持的所有图形设备函数。所有这三个动态连接库中的函数原型说明都在头文件windows.h中声明,所以在使用API进行编程序的时候别忘了包括该头文件。当然了,这只是主要的三个动态连接库,其他比较常用的还有网络服务(Winsock32.dll)、多媒体服务(Winmm.dll)等等。

两个例子程序分析:

1.文件拷贝

#include

#include

void main()

{

char SourceFileName[MAX_PATH];

char DestFileName[MAX_PATH];

BOOL Success;

cout

cin>>SourceFileName;

cout

cin>>DestFileName;

Success=CopyFile(SourceFileName,DestFileName,TRUE);

if(!Success)

cout

else

cout

}

2.网络相关

#include

#include

#include

void main()

{

// 定义数据结构存放计算机名称信息

DWORD MaxComputerlenth =MAX_COMPUTERNAME_LENGTH;

CHAR ComputerName[MAX_COMPUTERNAME_LENGTH];

// 调用API函数GetComputerName获取计算机名称存放到ComputerName中。 GetComputerName(ComputerName,&MaxComputerlenth);

cout

// 定义数据结构存放计算机系统信息

SYSTEM_INFO siSysInfo;

TCHAR tchBuffer[100];

// 调用API函数GetSystemInfo获取计算机名称存放到siSysInfo中

GetSystemInfo(&siSysInfo);

// 输出相关系统信息

sprintf(tchBuffer,"CPU的数量:%u\tCPU类型:%u",siSysInfo.dwNumberOfProcessors,siSysInfo.dwProcessorType);

cout

// 定义数据结构存放内存状态信息

MEMORYSTATUS stat;

// 调用API函数GetSystemInfo获取计算机名称存放到siSysInfo中

GlobalMemoryStatus(&stat);

// 进行输出

printf("%d%% 的内存在使用\n",stat.dwMemoryLoad);

printf("总共有%8ldk的物理内存空间. \n",stat.dwTotalPhys/1024);

printf("总共有%8ldk空闲的物理内存空间. \n",stat.dwAvailPhys/1024);

}

5. Windows 32 应用程序结构分析:

// Hello.cpp : Defines the entry point for the application.

//

#include "stdafx.h"

#include "resource.h"

#define MAX_LOADSTRING 100

// Global Variables:

HINSTANCE hInst; // current instance

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text

TCHAR szWindowClass[MAX_LOADSTRING];

// The title bar text

// Foward declarations of functions included in this code module:

ATOM

BOOL MyRegisterClass(HINSTANCE hInstance); InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_HELLO); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { } return FALSE; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_HELLO, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // TODO: Place code here. MSG msg; HACCEL hAccelTable;

}

// while (GetMessage(&msg, NULL, 0, 0)) { } if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { } TranslateMessage(&msg); DispatchMessage(&msg); return msg.wParam;

// FUNCTION: MyRegisterClass()

//

// PURPOSE: Registers the window class.

//

// COMMENTS:

//

// This function and its usage is only necessary if you want this code

// to be compatible with Win32 systems prior to the 'RegisterClassEx'

// function that was added to Windows 95. It is important to call this function

// so that the application will get 'well formed' small icons associated

// with it.

//

ATOM MyRegisterClass(HINSTANCE hInstance)

{

}

// wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra wcex.cbWndExtra wcex.hInstance wcex.hIcon = 0; = 0; = hInstance; = LoadIcon(hInstance, (LPCTSTR)IDI_HELLO); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); = (HBRUSH)(COLOR_WINDOW+1); = (LPCSTR)IDC_HELLO; = szWindowClass; wcex.hbrBackground wcex.lpszMenuName wcex.lpszClassName wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex);

// FUNCTION: InitInstance(HANDLE, int)

//

// PURPOSE: Saves instance handle and creates main window

//

// COMMENTS:

//

// In this function, we save the instance handle in a global variable and

// create and display the main program window.

//

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return FALSE;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

return TRUE;

}

//

// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)

//

// PURPOSE: Processes messages for the main window.

//

// WM_COMMAND - process the application menu

// WM_PAINT - Paint the main window

- post a quit message and return // WM_DESTROY

//

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

int wmId, wmEvent;

PAINTSTRUCT ps;

HDC hdc;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_ABOUT:

DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,

(DLGPROC)About);

break;

case IDM_EXIT:

DestroyWindow(hWnd);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code here...

RECT rt;

GetClientRect(hWnd, &rt);

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); hWnd,

EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

// Mesage handler for about box.

LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{

} case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { } break; EndDialog(hDlg, LOWORD(wParam)); return TRUE; switch (message) { case WM_INITDIALOG: return TRUE;

return FALSE;

}

Windows程序设计基本概念

1. Windows运行机制-----消息驱动

消息驱动又叫做事件驱动,是Windows编程采用的程序设计思想。在这种程序结构中,程序没有明显的开始、结束,程序流程的控制由各种随机发生、不确定、没有预先设定顺序的事件的发生来触发。是一个不断产生消息和处理消息的过程。

也就是说程序一运行开始处于等待消息状态,取得消息以后,就对其做出相应进行处理,处理完以后又进入等待消息状态。这种程序结构与windows操作系统结合非常紧密,最明显一点就是消息的管理是由操作系统完成的。应用程序从操作系统获得消息的两种方式:一种就是应用程序调用windows提供的消息获取函数;另外一种就是回调函数,由操作系统自己调用。

1窗口:是Windows操作系统最重要最基本的一个概念。它是一个正在运行的应用程序相对应的矩形区域,通过它用户可以和应用程序进行交互。

2客户区:是窗口中最大的一块空白的矩形区域,是用户和系统进行交互的主要区域,一般用于显示应用程序的输出。

3标题栏:位于窗口顶部,用于显示应用程序名称的。

4菜单栏:位于标题栏下方,菜单栏列出了应用程序支持的大部分功能。 5图标:适用于提醒用户的一个小图像,代表一个应用程序。

6光标:Windows光标显示在屏幕上的一个小位图。

7工具栏:一般位于菜单栏下方,上面有一些位图按钮,代表一些常用功能。 8状态栏:位于这个窗口底端,用于输出菜单提示信息和一些其他详细信息。 9对话框:一种特殊的窗口,用于接受用户的输入输出。

10控件:对话框上的许多小窗口都是控件。如按钮,编辑框等都是控件。

2. Windows应用程序设计相关基本术语

1窗口:是应用程序操作的基本单元,是用户可以通过它和应用程序进行交互的接口环境,也是系统管理应用程序的基本单位。从程序运行的内存组织结构看,窗口对应一个数据结构WNDCLASS。

2实例:实际上实例就是一个可执行程序在内存中的拷贝。一个可执行程序运行多次,在内存中就有多个内存拷贝。系统是通过实例句柄来识别一个可执行程序的拷贝。

3句柄:系统用来识别不同对象或者同类对象的不同实例的“编号”。它是一个无符号整数。

几乎所有对对象的引用都是通过句柄来进行的。如使用HWND、HCURSOR、HDC。 4资源:构成应用程序的元素称为资源:菜单、工具条、位图、字符串等。

5窗口函数:用户通过窗口和应用程序交互时产生的消息,送给一个函数进行处理。该函数体结构大致由一个Switch结构组成,是消息驱动机制的发动机。

6图形设备接口:GDI(Graphic Device Interface)时Windows系统的重要组成部分。负责系统和用户或者绘图程序之间的信息交换,并控制输出设备上图形和文字的输出。最大的优点就是设备无关性:将程序员和设备相隔离,程序员不必关心物理设备的细节,直接调用相关的API函数就可以在输出设备上显示图形或者文字。

7回调函数:写好了等系统进行调用的函数。只能由系统自动调用。前面所说的窗口函数就是一个典型的回调函数。

3. Win32应用程序结构和执行原理

例 Win32应用程序结构分析和执行原理解释

使用Visual C++ 6.0建立一个简单的Win32应用程序:选择File菜单的New,在出现的对话框中,选择Projects栏目(新建工程),并点取其下的Win32 Application项,表示使用Win32环境创建应用程序。先在Locatin(路径)中填入"D:\TEST\",然后在Project Name(项目名称)中填入"MyWin",其它按照缺省设置)。单击OK按钮。

添加MyWin.cpp文件到工程,文件内容如下:

编译,运行该程序。运行结果为弹出一个简单的Windows窗口,提示:你好,我是简单的Win!点击鼠标右键,会谈出提示框:你按下了鼠标右键!

按下Esc键,会提示:你按下了ESC键!这是一个最简单的Win32应用程序,其他较复杂的Windows应用程序都是在这样的程序框架上扩展得到的。

下面对框架里边比较重要的函数进行解释说明。

1. WinMain()函数

WinMain()函数是应用程序开始执行时的入口点,通常也是应用程序结束任务退出时的出口点。它与DOS程序的main()函数起同样的作用,有一点不同的是,WinMain()函数必须带有四个参数,它们是系统传递给它的。WinMain()函数的原型如下:

int PASCAL WinMain( HINSTANCE hInstance, //当前实例句柄

HINSTANCE hPrevInstance, //前一个实例句柄

LPSTR lpCmdLine, int nCmdShow) //命令行字符 //窗口显示方式 第一个参数hInstance,是标识该应用程序当前的实例的句柄。它是HINSTANCE类型,HINSTANCE是Handle of Instance的缩写,表示实例的句柄。hInstance是一个很关键的数据,它唯一的代表该应用程序,在后面初始化程序主窗口的过程中需要用到这个 参数。这里有两个概念,一个是实例,一个是句柄。实例代表的是应用程序执行的整个过程和方法,一个应用程序如果没有被执行,只是存在 于磁盘上,那么就说它是没有被实例化的;只要一执行,则说该程序的一个实例在运行。句柄,顾名思义,指的是一个对象的把柄。在Windows中,有各种各 样的句柄,它们都是32位的指针变量,用来指向该对象所占据的内存区。句柄的使用,可以极大的方便Windows管理其内存中的各种对象。

第二个参数是hPrevInstance,它是用来标识该应用程序的前一个实例句柄。对于基于Win32的应用程序来说,这个参数总是NULL。这是因为在Win95操作系统中, 应用程序的每个实例都有各自独立的地址空间,即使同一个应用程序被执行了两次,在内存中也会为它们的每一个实例分配新的内存空间,所以一个应用程序被执行 后,不会有前一个实例存在的可能。也就是说,hPrevInstance这个参数是完全没有必要的,只是为了提供与16位Windows的应用程序形式上 的兼容性,才保留了这个参数。在以前的16位Windows环境下(如Windows3.2),hPrevInstance用来标识与hInstance 相关的应用程序的前一个句柄。 第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。如在Win95的"开始"菜单中单击"运行",输入"Mywin hello",则此参数指向的字符串为"hello"。

最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOW、SW_HIDE、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED等。

2. 注册窗口类

上面的例程中,创建主窗口的函数是InitMyWindow()。通常要对填充一个窗口类结构WNDCLASS, 然后调用RegisterClass()对该窗口类进行注册。每个窗口都有一些基本的属性,如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色、 处理窗口消息函数的名称等等。注册的过程也就是将这些属性告诉系统,然后再调用CreateWindow()函数创建出窗口。这好比人们量体裁衣。

typedef struct _WNDCLASS {

UINT style; //窗口的风格

WNDPROC lpfnWndProc; //指定窗口的消息处理函数的远指针

int cbClsExtra; //指定分配给窗口类结构之后的额外字节数

int cbWndExtra; //指定分配给窗口实例之后的额外字节数

HANDLE hInstance; //指定窗口过程所对应的实例句柄

HICON hIcon; //指定窗口的图标

HCURSOR hCursor; //指定窗口的鼠标

HBRUSH hbrBackground; //指定窗口的背景画刷

LPCTSTR lpszMenuName; //窗口的菜单资源名称

LPCTSTR lpszClassName; //该窗口类的名称

} WNDCLASS;

在Win95和WinNT的具有新界面特性的系统中,为了支持新的窗口界面特性,还有一种扩展的窗口类型WNDCLASSEX,它的定义如下:

typedef struct _WNDCLASSEX { UINT cbSize; //指定WNDCLASSEX结构的大小 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; //窗口的小图标 } WNDCLASSEX; 结构中相关成员这里进行简单解释一下,实际应用过程中查阅MSND。填充完毕后,调用RegisterClass函数进行窗口注册。函数原型如下:

ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );

该函数如调用成功,则返回一个非0值,表明系统中已经注册了一个名为MyWin的窗口类。如果失败,则返回0。

3. 创建窗口

当窗口类注册完毕之后,并不会有窗口显示出来,因为注册的过程仅仅是为创建窗口所做的准备工作。实际创建一个窗口的是通过调用CreateWindow()函数完成的。窗口类中已经预先定义了窗口的一般属性,而CreateWindow()中的参数可以进一 步指定一个窗口的更具体的属性,在MyWin程序中,是如下调用CreateWindow()函数来创建窗口的:

hwnd = CreateWindow( "MyWin", //创建窗口所用的窗口类的名称 "一个简单的Win32程序", //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格,定义为普通型 200, //窗口位置的x坐标 200, //窗口位置的y坐标 500, //窗口的宽度 400, //窗口的高度 NULL, //父窗口句柄 NULL, //菜单句柄 hInstance, //应用程序实例句柄* NULL ); //一般都为NULL

如果窗口创建成功,返回值是新窗口的句柄,否则返回NULL。

显示和更新窗口

窗口创建后,并不会在屏幕上显示出来,要真正把窗口显示在屏幕上,还得使用ShowWindow()函数,其原型如下:

BOOL ShowWindow( HWND hWnd, int nCmdShow ); 参数hWnd指定要显示得窗口的句柄,nCmdShow表示窗口的显示方式,这里指定为从WinMain()函数的nCmdShow所传递而来的值。

由于ShowWindow()函数的执行优先级不高,所以当系统正忙着执行其它的任务时,窗口不会立即显示出来,此时,调用UpdateWindow()函数以可以立即显示窗口。其函数原型如下:

BOOL UpdateWindow( HWND hWnd );

4. 消息循环

在Win32编程中,消息循环是相当重要的一个概念,看似很难,但是使用起来却是非常简单。在WinMain()函数中,调用InitWindow()函数成功的创建了应用程序主窗口之后,就要启动消息循环,其代码如下:

while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

Windows应用程序可以接收以各种形式输入的信息,这包括键盘、鼠标动作 、记时器产生的消息,也可以是其它应用程序发来的消息等等。Windows系统自动监控所有的输入设备,并将其消息放入该应用程序的消息队列中。Windows消息结构及分类在下一章节进行讲解。

GetMessage()函数还可以过滤消息,它的第二个参数是用来指定从哪个窗口的消息队列中获取消息,其它窗口的消息将被过滤掉。如果该参数为NULL,则GetMessage()从该应用程序线程的所有窗口的消息队列中获取消息。

第三个和第四个参数是用来过滤MSG结构中主消息值的,主消息值在wMsgFilterMin和wMsgFilterMax之外的消息将被过滤掉。如果这两个参数为0,则表示接收所有消息。 当且仅当GetMessage()函数在获取到WM_QUIT消息后,将返回0值,于是程序退出消息循环。

TranslateMessage()函数的作用是把虚拟键消息转换到字符消息,以满足键盘输入的需要。DispatchMessage()函数所完成的工作是把当前的消息发送到对应的窗口过程中去。

5. 消息处理函数

消息处理函数又叫窗口过程,在这个函数中,不同的消息将用switch语句分配到不同的处理程序中 去。Windows的消息处理函数都有一个确定的样式,即这种函数的参数个数和类型以及其返回值的类型都有明确的规定。在VC的说明书中,消息处理函数的 原型是这样定义的:

LRESULT CALLBACK WindowProc(

HWND hwnd, //接收消息窗口的句柄 UINT uMsg, //主消息值 WPARAM wParam, //副消息值 LPARAM lParam //副消息值 ); 如果你的程序中还有其它的消息处理函数,也都必须按照上面的这个样式来定义,但函数名称可以随便取。MyWin中的WinProc()函数就是这样一个典型的消息处理函数。

消息处理函数的四个参数是由GetMessage()函数从消息队列中获得MSG结构,然后分解后得到的。第二个参数uMsg和MSG结构中的message值是一致的,代表了主消息值。程序中用switch语句来将不同类型的消息分配到不同的处理程序中去。

WinProc()函数明确的处理了4个消息,分别是WM_KEYDOWN(击键消息)、WM_RBUTTONDOWN(鼠标右键按下消息)、WM_PAINT(窗口重画消息)、WM_DESTROY(销毁窗口消息)。

值得注意的是,应用程序发送到窗口的消息远远不止以上这几条,象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等这样频 频使用的消息就有几十条。为了减轻编程的负担,Windows的API提供了DefWindowProc()函数来处理这些最常用的消息,调用了这个函数后,这些消息将按照系统默认的方式得到处理。

因此,在switch_case语句中,只须明确的处理那些有必要进行特别响应的消息,把其余的消息交给DefWindowProc()函数来处理,是一种明智的选择,也是你必须做的一件事。

6. 结束消息循环

当用户按Alt+F4或单击窗口右上角的退出按钮,系统就向应用程序发送一条WM_DESTROY的消息。在处理此消息时,调用了 PostQuitMessage()函数,该函数会给窗口的消息队列中发送一条WM_QUIT的消息。在消息循环中,GetMessage()函数一旦检 索到这条消息,就会返回FALSE,从而结束消息循环,随后,程序也结束。

4. Windows应用程序编程接口

Windows操作系统对外通过两种接口提供服务:普通用户操作接口服务和程序员接口服务。其中用户操作接口服务是通过用户操作来进行完成的,而程序员接口服务是提供一系列底层的实现操作系统最基本的函数(接口)共程序员调度来完成相关功能。比如一个文件的拷贝,

普通用户可以通过鼠标菜单选择操作或者命令来完成,程序员可以通过程序代码调用相关文件操作的函数(API)来完成相同的功能。

所有这些系统底层、实现最基本功能、供程序员调用的函数集中起来形成一个集合,这就是API(Application Programming Interface)。Windows API编程是开发Windows应用程序最古老由最原始,同时又是试验一个程序员对windows操作系统及相关数据结构掌握程度的最好方法。

应该知道:所有其它类库以及后面要讲到的MFC,都是对这些最基本功能的函数进行封装来实现的。任何使用MFC能实现的功能,使用API同样能够实现,而且能够更加灵活。了解并学习API编程,可以看到使用MFC编程所看不到的东西,更深入了解Windows系统运行机制,同时帮助我们学习MFC编程。

三个动态连接库:Windows内核库(Kernel32.dll)、Windows用户界面管理库(User32.dll)、Windows图形设备界面库(Gdi32.dll),这些动态连接库共同构成了Win32 API函数。 Windows内核库(Kernel32.dll):所有底层的核心功能如任务管理、内存管理,进程线程文件管理等的函数都在这个动态连接库中;

Windows用户界面管理库(User32.dll):窗口管理,菜单管理以及通信等相关函数都在该动态连接库中;

Windows图形设备界面库(Gdi32.dll):集合了所有用于管理系统支持的所有图形设备函数。所有这三个动态连接库中的函数原型说明都在头文件windows.h中声明,所以在使用API进行编程序的时候别忘了包括该头文件。当然了,这只是主要的三个动态连接库,其他比较常用的还有网络服务(Winsock32.dll)、多媒体服务(Winmm.dll)等等。

两个例子程序分析:

1.文件拷贝

#include

#include

void main()

{

char SourceFileName[MAX_PATH];

char DestFileName[MAX_PATH];

BOOL Success;

cout

cin>>SourceFileName;

cout

cin>>DestFileName;

Success=CopyFile(SourceFileName,DestFileName,TRUE);

if(!Success)

cout

else

cout

}

2.网络相关

#include

#include

#include

void main()

{

// 定义数据结构存放计算机名称信息

DWORD MaxComputerlenth =MAX_COMPUTERNAME_LENGTH;

CHAR ComputerName[MAX_COMPUTERNAME_LENGTH];

// 调用API函数GetComputerName获取计算机名称存放到ComputerName中。 GetComputerName(ComputerName,&MaxComputerlenth);

cout

// 定义数据结构存放计算机系统信息

SYSTEM_INFO siSysInfo;

TCHAR tchBuffer[100];

// 调用API函数GetSystemInfo获取计算机名称存放到siSysInfo中

GetSystemInfo(&siSysInfo);

// 输出相关系统信息

sprintf(tchBuffer,"CPU的数量:%u\tCPU类型:%u",siSysInfo.dwNumberOfProcessors,siSysInfo.dwProcessorType);

cout

// 定义数据结构存放内存状态信息

MEMORYSTATUS stat;

// 调用API函数GetSystemInfo获取计算机名称存放到siSysInfo中

GlobalMemoryStatus(&stat);

// 进行输出

printf("%d%% 的内存在使用\n",stat.dwMemoryLoad);

printf("总共有%8ldk的物理内存空间. \n",stat.dwTotalPhys/1024);

printf("总共有%8ldk空闲的物理内存空间. \n",stat.dwAvailPhys/1024);

}

5. Windows 32 应用程序结构分析:

// Hello.cpp : Defines the entry point for the application.

//

#include "stdafx.h"

#include "resource.h"

#define MAX_LOADSTRING 100

// Global Variables:

HINSTANCE hInst; // current instance

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text

TCHAR szWindowClass[MAX_LOADSTRING];

// The title bar text

// Foward declarations of functions included in this code module:

ATOM

BOOL MyRegisterClass(HINSTANCE hInstance); InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_HELLO); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { } return FALSE; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_HELLO, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // TODO: Place code here. MSG msg; HACCEL hAccelTable;

}

// while (GetMessage(&msg, NULL, 0, 0)) { } if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { } TranslateMessage(&msg); DispatchMessage(&msg); return msg.wParam;

// FUNCTION: MyRegisterClass()

//

// PURPOSE: Registers the window class.

//

// COMMENTS:

//

// This function and its usage is only necessary if you want this code

// to be compatible with Win32 systems prior to the 'RegisterClassEx'

// function that was added to Windows 95. It is important to call this function

// so that the application will get 'well formed' small icons associated

// with it.

//

ATOM MyRegisterClass(HINSTANCE hInstance)

{

}

// wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra wcex.cbWndExtra wcex.hInstance wcex.hIcon = 0; = 0; = hInstance; = LoadIcon(hInstance, (LPCTSTR)IDI_HELLO); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); = (HBRUSH)(COLOR_WINDOW+1); = (LPCSTR)IDC_HELLO; = szWindowClass; wcex.hbrBackground wcex.lpszMenuName wcex.lpszClassName wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex);

// FUNCTION: InitInstance(HANDLE, int)

//

// PURPOSE: Saves instance handle and creates main window

//

// COMMENTS:

//

// In this function, we save the instance handle in a global variable and

// create and display the main program window.

//

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return FALSE;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

return TRUE;

}

//

// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)

//

// PURPOSE: Processes messages for the main window.

//

// WM_COMMAND - process the application menu

// WM_PAINT - Paint the main window

- post a quit message and return // WM_DESTROY

//

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

int wmId, wmEvent;

PAINTSTRUCT ps;

HDC hdc;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_ABOUT:

DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,

(DLGPROC)About);

break;

case IDM_EXIT:

DestroyWindow(hWnd);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code here...

RECT rt;

GetClientRect(hWnd, &rt);

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); hWnd,

EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

// Mesage handler for about box.

LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{

} case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { } break; EndDialog(hDlg, LOWORD(wParam)); return TRUE; switch (message) { case WM_INITDIALOG: return TRUE;

return FALSE;

}


相关文章

  • 全国高校计算机等级考试一级考什么内容
  • 考试科目:一级MS Office.一级WPS Office和一级B ,一级共三个科目. (都是计算机基础知识.基本办公软件的使用.一级B 是入门级 我想应该是最简单的 它没有PPT 的内容.一级WPS OFFICE 考试和其余二者办公平台不 ...查看


  • 一个程序员应该具备的基础知识和概念
  • 一个程序员应该具备的基础知识和概念 1.计算机是有什么组成的,CPU是什么东西,其工作原理是什么.(对于这些以及下面将要提到的概念我不会告诉你什么答案,你可以看相应的教材,关于教材我会在下一部分详述,记住理解最重要!) 2.机器语言和微指令 ...查看


  • 信息化的基本概念
  • 第一章 信息化的基本概念 三大资源:信息资源.能量资源.物质资源: 现代信息技术:微电子技术.计算机技术.通信技术.网络技术: 集成电路简称IC.大规模集成电路简称LSI.超大规模集成电路VLSI.中央处理器CPU.微电子技术:集成电路+中 ...查看


  • [838]设计技术与方法-2016
  • 2015-2016年硕士研究生入学考试大纲 考试科目名称:设计技术与方法 考试科目代码:[838] (A卷:传播理论 B卷:传播技术 C卷:人机工程学及工业设计方法) 本科目分为A卷(传播理论).B卷(传播技术)和C卷(人机工程学及工业设计 ...查看


  • 计算机文化基础教学大纲
  • <计算机文化基础>教学大纲 课程总学时:48学时 周学时数:3学时 课程类型:通识必修课 开课(系)院:全校大一新生 执笔人:胡静瑶 审核人: 一.教学目的和要求: 本课程是为全校大一新生开设的通识必修课,是高等学校计算机基础教 ...查看


  • 计算机应用基础课程教学计划
  • <计算机应用基础>课程教学计划 一.课程性质和任务 <计算机应用基础>是由中国传媒大学出版社出版的的面向中职学生计算机学习的一本教材,21世纪是信息化的时代,计算机已广泛应用于各行各业,人们的工作和生活也越来越离不开 ...查看


  • 大学计算机基础教学大纲
  • <大学计算机基础>教学大纲 一. 课程性质 本课程是高职各专业必修的公共基础课.本课程既是学生掌握计算机知识及其应用的一门课程,又为学生后续的计算机相关课程的学习打好基础.<大学计算机基础>课程教学共需60学时,采用 ...查看


  • 计算机科学与技术专业 主要课程
  • 计算机科学与技术专业 03023001 高等数学 Higher Mathematics [192-11-1.2] 内容提要:作为本专业的重要基础课程,内容以微积分.中值定理.不定积分.定积分及其应用,多元 函数微分法及其应用.重积分.曲线积 ...查看


  • 山东省初中信息技术等级证书考试说明(试行)(2015印刷版)
  • 山东省中小学信息技术等级证书考试说明(试行) 初中信息技术 一.考试范围 山东省中小学信息技术等级证书考试范围主要依据教育部<中小学信息技术课程指导纲要(试行)>所确定的课程任务.教学目标以及课时安排,并结合我省的实际情况确定. ...查看


热门内容