Windows应用程序

 

Windows应用程序是由一系列的消息处理

代码来实现的。这和传统的过程式编程方法很不一样,编程者只能够

预测用户所利用应用程序用户界面对象所进行的操作以及为这些操作

编写处理代码,却不可以这些操作在什么时候发生或者是以什么顺序

来发生,也就是说,我们不可能知道什么消息会在什么时候以什么顺

序来临。

Windows应用程序基本流程:

 

Windows API:(windowsAppliacation Programming Interface. Windows 应用程序编程接口),

API就是一系列的例程,应用程序通过调用这些例程来请求操作系统完成一些低级服务。在Windows这样的图形用户界面中,应用程序的窗口、图标、菜单和对话框等就是由API来管理和维护的。

 

Windows应用程序中,main()函数被、WinMain()函数取代,WinMain()函数原型如下:

Int WINAPIWinMain( HINSTANCE hInstance //当前实例句柄

                  HINSTANCE hPrevInstance //前一实例句柄

                  LPSTR lpCmdLine //指向命令行参数的指针

                  Int  nCmdShow)//窗口的显示状态

“句柄”(handle),所谓的句柄是一个标识

对象的变量,或者是一个对操作系统资源的间接引用。

WinMain()函数中一般需要完成以下操作:

1 注册窗口类

2 创建应用程序主窗口

3 进入应用程序消息循环

 

在注册窗口类前,我们先创建一个类型为

WNDCLASS的结构,然后在该结构对象中填入窗口类的信息,最后将它

传递给函数RegisterClass,整个过程如下面的代码所示:

WNDCLASS wc;

// 填充窗口类信息

wc.style=CS_HREDRAW|CS_VREDRAW;//

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=GetStockObject(WHITE_BRUSH);

wc.lpszMenuName=NULL;

wc.lpszClassName="SdkDemo1";

// 注册窗口类

RegisterClass(&wc);

在使用RegisterClass注册窗口类成功之后,即可以使用该窗口类创

建并显示应用程序的窗口。这个过程如下面的代码所示:

// 创建应用程序主窗口

hWnd=CreateWindow("SdkDemo1", // 窗口类名

"第一个Win32 SDK应用程序",// 窗口标题

WS_OVERLAPPEDWINDOW,// 窗口样式

CW_USEDEFAULT,// 初始化 x 坐标

CW_USEDEFAULT,// 初始化 y 坐标

CW_USEDEFAULT,// 初始化窗口宽度

CW_USEDEFAULT,// 初始化窗口高度

NULL, // 父窗口句柄

NULL, // 窗口菜单句柄

hInstance,// 程序实例句柄

NULL); // 创建参数

// 显示窗口

ShowWindow(hWnd,SW_SHOW);

// 更新主窗口客户区

UpdateWindow(hWnd);

创建窗口完成之后,ShowWindows显示该窗口,第二个参数SW_SHOW表

示在当前位置以当前大小激活并显示由第一个参数标识的窗口。然

后,函数UpdateWindows向窗口发送一条WM_PAINT消息,以通知窗口

更新其客户区。

////////////////////////////////////////////////////////////////////////////////////////////

CreateWindow()原型:

HWNDCreateWindow(LPCTSTR lpClassName, // 指向已注册的类名

LPCTSTR lpWindowName,// 指向窗口名称

DWORDdwStyle, // 窗口样式

int x, // 窗口的水平位置

int y, // 窗口的垂直位置

int nWidth,// 窗口宽度

int nHeight,// 窗口高度

HWNDhWndParent, // 父窗口或所有者窗口句柄

HMENU hMenu,// 菜单句柄或子窗口标识符

HANDLEhInstance, // 应用程序实例句柄

LPVOIDlpParam, // 指向窗口创建数据的指针

);

////////////////////////////////////////////////////////////////////////////////////////////

 

在完成上面的步骤之后,进入应用程序的主消息循环。一般情况下,

主消息循环具有下面的格式:

while(GetMessage(&msg,NULL,0,0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

下面我们来看一下程序主窗口的窗口过程WndProc。窗口过程名是可

以由用户自行定义,然后在注册窗口类时在WNDCLASS结构中指定。但

是,一般来说,程序都把窗口过程命令为WndProc来类似的名称,如

MainWndProc等,并不是一定要这样做,但是这样明显的有利于阅

读,因此也是我们推荐的做法。窗口过程具有如下的原型:

LRESULTWINAPI WndProc(HWND,UINT,WPARAM,LPARAM);

LRESULTCALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

对于编译器而言,两种书写形式都是一样的,它们都等价于 long __stdcall WndProc(void *,unsigned int,unsigned int,long)

窗口过程使用了四个参数,在它被调用时(再强调一点,一般情况

下,窗口过程是由操作系统调用,而不是由应用程序调用的,这就是

我们为什么将它们称为回调函数的道理),这四个参数对应于所发送

消息结构的前四个成员。下面给出了一个窗口过程的例子:

// WndProc 主窗口过程

LRESULTWINAPI WndProc (HWND hWnd,

UINT msg,

WPARAMwParam,

LPARAMlParam)

{

HDC hdc;

RECT rc;

HPENhPen,hPenOld;

HBRUSHhBrush,hBrushOld;

switch (msg)

{

caseWM_PAINT:

hdc=GetDC(hWnd);

GetClientRect(hWnd,&rc);

hPen=CreatePen(PS_SOLID,0,RGB(0,0,0));

hBrush=CreateHatchBrush(HS_DIAGCROSS,RGB(0,0,0));

hPenOld=SelectObject(hdc,hPen);

hBrushOld=SelectObject(hdc,hBrush);

Ellipse(hdc,rc.left,rc.top,rc.right,rc.bottom);

SelectObject(hdc,hPenOld);

SelectObject(hdc,hBrushOld);ReleaseDC(hWnd,hdc);

break;

caseWM_DESTROY:

PostQuitMessage(0);

break;

default:

break;

}

returnDefWindowProc(hWnd,msg,wParam,lParam);

}

在该窗口过程中,我们处理了最基本两条消息。

第一条消息是WM_PAINT,当窗口客户区的全部或一部分需要重绘时,

系统向该窗口发送该消息。在前面的过程中我们已经提到过,在使用

ShowWindow函数显示窗口之后,通常随即调用函数UpdateWindow,该

函数直接向窗口过程发送一个WM_PAINT消息,以通知窗口绘制其客户

区。在该消息的处理函数中,我们先使用GetDC获得窗口的设备句

柄,关于设备句柄本书后面将要专门涉及,这里我们只需知道它是用

来调用各种绘图方法的。然后调用GetClientRect获得当前窗口的客

户区矩形。接着调用CreatePen创建一个黑色画笔,调用

CreateHatchBrush创建一个45度交叉线的填充画刷,并且

SelectObject函数将它们选入设备描述表中,原有的画笔和画刷被保

存到hPenOld和hBrushOld中,以便以后恢复。完成以上步骤之后,调

用Ellipse函数以当前客户区大小绘制一个椭圆。最后,再一次调用

SelectObject函数恢复原有的画笔和画刷,并调用ReleaseDC释放设

备描述表句柄。在这个消息的处理代码中,我们涉及到了一些新的概

念、数据类型和API函数,然而本章并不着意于讲述这些内容,读者

也不必深究它们,这些代码只是为了完整该示例程序才使用的。对于

窗口来说,除了客户区以外的其它内容将由系统进行重绘,这些内容

包括窗口标题条、边框、菜单条、工具条以及其它控件,如果包含了

它们的话。这种重绘往往发生在覆盖于窗口上方的其它窗口被移走,

或者是窗口被移动或改变大小时。因此,对于大多数窗口过程来说,

WM_PAINT消息是必须处理的。

另一个对于绝大多数窗口过程都必须处理的消息是WM_DESTROY,当窗口被撤消时(比如用户从窗口的系统菜单中选择了“关闭”,或者单

击了右边的小叉,对于这些事件,Windows的默认处理是调用

DestroyWindow函数撤销相应的窗口),将会接收到该消息。由于本程

序仅在一个窗口,因此在这种情况下应该终止应用程序的执行,因此

我们调用了PostQuitMessage函数,该函数向线程的消息队列中放入

一个WM_QUIT消息,传递给PostQuitMessage函数的参数将成为

WM_QUIT消息的wParam参数,在上面的例子中,该值为0。

对于其它情况,在上面的示例程序中我们没有必要进行处理,

Windows专门为此提供了一个默认的窗口过程,称为DefWindowProc,

我们只需要以WndProc的参数原封不动的调用默认窗口过程

DefWindowProc,并将其返回值作为WndProc的返回值即可。

 

这个程序的完整代码给出如下:

#include<windows.h>

// 函数原型

int WINAPIWinMain(HINSTANCE,HINSTANCE,LPSTR,int);

LRESULTWINAPI WndProc(HWND,UINT,WPARAM,LPARAM);

// WinMain 函数

int WINAPIWinMain (HINSTANCE hInstance,

HINSTANCEhPrevInstance,

LPSTRlpCmdLine,

intnCmdShow) HWND hWnd; // 主窗口句柄

MSG msg; // 窗口消息

WNDCLASS wc;// 窗口类

if(!hPrevInstance)

{

// 填充窗口类信息

wc.style=CS_HREDRAW|CS_VREDRAW;

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=GetStockObject(WHITE_BRUSH);

wc.lpszMenuName=NULL;

wc.lpszClassName="SdkDemo1";

// 注册窗口类

RegisterClass(&wc);

}

// 创建应用程序主窗口

hWnd=CreateWindow("SdkDemo1", // 窗口类名

"第一个Win32 SDK应用程序",// 窗口标题

WS_OVERLAPPEDWINDOW,// 窗口样式

CW_USEDEFAULT,// 初始化 x 坐标

CW_USEDEFAULT,// 初始化 y 坐标

CW_USEDEFAULT,// 初始化窗口宽度 CW_USEDEFAULT, // 初始化窗口高度

NULL, // 父窗口句柄

NULL, // 窗口菜单句柄

hInstance,// 程序实例句柄

NULL); // 创建参数

// 显示窗口

ShowWindow(hWnd,SW_SHOW);

// 更新主窗口客户区

UpdateWindow(hWnd);

// 开始消息循环

while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

returnmsg.wParam;

}

// WndProc 主窗口过程

LRESULTWINAPI WndProc (HWND hWnd,

UINT msg,

WPARAMwParam,

LPARAMlParam)

{

HDC hdc;

RECT rc;

HPENhPen,hPenOld; HBRUSH hBrush,hBrushOld;

switch (msg)

{

caseWM_PAINT:

hdc=GetDC(hWnd);

GetClientRect(hWnd,&rc);

hPen=CreatePen(PS_SOLID,0,RGB(0,0,0));

hBrush=CreateHatchBrush(HS_DIAGCROSS,RGB(0,0,0));

hPenOld=SelectObject(hdc,hPen);

hBrushOld=SelectObject(hdc,hBrush);

Ellipse(hdc,rc.left,rc.top,rc.right,rc.bottom);

SelectObject(hdc,hPenOld);

SelectObject(hdc,hBrushOld);

ReleaseDC(hWnd,hdc);

break;

caseWM_DESTROY:

PostQuitMessage(0);

break;

default:

break;

}

returnDefWindowProc(hWnd,msg,wParam,lParam);

}

 

Windows中

所用的数

据类型

对应的基本数据

类型

说明

BOOL  int  布尔值

BSTR  unsigned short *  32位字符指针

BYTE  unsigned char 8位无符号整数

COLORREF  unsigned long 用作颜色值的32位值

DWORD  unsigned long 32位无符号整数,段地址和相关的偏移地

 

LONG  long 32位带符号整数

LPARAM  long  作为参数传递给窗口过程或回调函数的32

位值

LPCSTR  const char * 指向字符串常量的32位指针

LPSTR  char * 指向字符串的32位指针

LPCTSTR  const char  *

(注1)

指向可移植的Unicode和DBCS字符串常量

的32位指针

LPTSTR  char *(注1)  指向可移植为Unicode和DBCS字符串的32

位指针

LPVOID  void * 指向未定义类型的32位指针

LRESULT  long  来自窗口过程或回调函数的32位返回值

UINT  unsigned int 32位无符号整数

WNDPROC  long

(__stdcall  *)

(void

*,unsigned

int,unsigned

int,long)(注2)

指向窗口过程的32位指针

WORD  unsigned short  16位无符号整数

WPARAM  unsigned int 当作参数传递给窗口过程或回调函数的32

位值

 

注1:  这是在DBCS版本下的情况,在Unicode版本下LPCTSTR和LPTSTR将代表

其它的数据类型。

注2:  事实上,WNDPROC被定义为LRESULT  (CALLBACK*)(HWND,  UINT,

WPARAM,LPARAM),这个定义最终被编译器解释为long (__stdcall *)(void

*,unsignedint,unsigned int,long)。

 

表3. 3 Windows公用句柄类型  (void*)

句柄类型  说明

HBITMAP  保存位图信息的内存域的句柄

HBRUSH  画刷句柄

HCTR  子窗口控件句柄

HCURSOR  鼠标光标句柄 HDC  设备描述表句柄

HDLG  对话框句柄

HFONT  字体句柄

HICON  图标句柄

HINSTANCE  应用程序的实例句柄

HMENU  菜单句柄

HMODULE  模块句柄

HPALETTE  颜色调色板句柄

HPEN  在设备上画图时用于指明线型

的笔的句柄

HRGN  剪贴区域句柄

HTASK  独立于已执行任务的句柄

HWND  窗口句柄

时间: 2024-12-18 13:19:20

Windows应用程序的相关文章

C#windows应用程序打包(VS2010+SQLServer2008)

C#windows应用程序打包(VS2010+SQLServer2008) 开发环境:VS2010+SQL Server 2008 操作系统:win7_32bit 旗舰版 开发语言:C# 项目名称:学生寄宿管理系统 下面开始介绍:如何给windows应用程序打包? 第一步: 打开VS2010,打开你要打包的项目,然后右击"解决方案",”添加“,"新建项目",弹出如下图所示界面: 点击”安装和部署“左边的三角形,选择下面的”Visual studio Installe

Windows应用程序文件格式转换控件LEADTOOLS ePrint Professional

LEADTOOLS ePrint Professional控件是一个多功能一体化文件转换解决方案,它可帮助您将任何Windows应用程序中的文件或图像转换为150种类型的文件,其中包括:PDF, DOC, HTML, TXT, TIFF, JPG, GIF, PNG等等. ePrint Professional包含了两种转换模式 - ePrint printer和ePrint Workstation printer,为您提供不同水平的文件转换控制,您可以更加灵活的进行生产.ePrint prin

Windows应用程序的消息处理机制

(1)操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中. (2)应用程序在消息循环中调用GetMessage函数从消息队列中取出一条一条的消息. 取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用TranslateMessage产生新的消息. (3)应用程序调用DispatchMessage,将消息回传给操作系统. 消息是由MSG结构体对象来表示的,其中就包含了接收消息的窗口的句柄.因此,DispatchMessage函数总能进行正确的传递.

Windows应用程序高级控件之ListView控件

ListView控件---列表视图控件 用途:显示带图标的项列表,其中可以显示大图标.小图标和数据 ListView控件的常用属性: View属性:设置项在控件中的显示方式,View属性的值有以下几种 Details       每个项显示在不同的行上 LargeIcon     每个项都显示为一个最大的图标,下面有标签,是默认的视图模式 List          每个项显示为一个小图标,右边带标签,各项排列在列中,没有列表头 SmallIcon     每个项显示为小图标,右边带标签 Tit

Windows应用程序高级控件之TreeView

TreeView控件--树控件 为用户显示节点层次结构,每个节点又可以包含子节点. 添加和删除树节点 添加--TreeView的Nodes属性的Add方法:public virtual int Add(TreeNode node) 删除--TreeView的Nodes属性的Remove方法:public void Remove(TreeNode node) 添加-实例代码: private void Form1_Load(object sender, EventArgs e) { //为树控件建

Windows控制台程序“选定模式”的问题

最近用Nodejs写了个代理程序,一直用的好好的,木有问题,今天突然发现不能用了,使用telnet去连代理的端口也能连通,可是服务就是不能正常使用,提示连接超时. 当时猜测是Nodejs的某个地方阻塞了,分析了下代码,怎么也想不明白不能有阻塞的地方啊. 又是各种倒腾,后来发现一个奇怪的问题,我把鼠标放到Nodejs的控制台上,默认进入了编辑模式,而且整个应用的标题变成了"选定 XXXX"这种形式,我想退出程序,需要按两次Ctrl+C,难道是这的问题? 又来有测试了下,果真还是这的问题,

基本的Windows应用程序 窗体创建

基本的Windows应用程序 转载:http://shiba.hpe.sh.cn/jiaoyanzu/WULI/Article1506 下面是一个完全可以运行的Windows程序,代码很简单,读者通过代码中的注释了解它们的含义.我们将在下一节详细讲解些代码.做为一个练习,我们建议读者在你的开发工具中创建一个工程,手工输入些代码,然后编译运行这个程序.注意,如果你使用的是Visual C++,那么在选择工程类型时必须是“Win32 application project”,而不能是“Win32 c

Windows窗口程序运行过程

现在,简单介绍下windows应用程序的大概运行过程,让刚开始接触Windows开发或者MFC开发的同学有一个大致的了解. 1.创建一个窗口首先要注册一个窗口类,初始化wndclass中的各个域,设置窗口过程函数. 2.调用RigisterClass来注册这个窗口类. 3.创建窗口.CreateWindow 4.显示窗口.ShowWindow 5.刷新窗口.UpdateWindow 5.消息循环. 这里主要讲解消息循环. 消息循环中的循环是由程序中 while(GetMessage(&msg,N

Unity3D部署windows store程序到Surface进行调试

Unity3D如果开发Windows Store的游戏,一般需要真机或者模拟器来调试,本文主要讲解下如何把程序发布到Surface真机上进行调试. 首先第一步肯定是要在Unity3D中将项目build出来: 那么接下来就要依靠Visual Studio 2013来帮助我们调试Windows Store的程序了. Visual Studio 2013虽然集成了一个Windows 8.1的模拟器,但是很多应用需要用到真机,甚至是Surface这种移动设备(比如指南针.加速器等的需要) 笔者刚遇到本问