界面编程总结(2)

WIN32 SDK界面编程

在介绍win32 sdk界面编程,先需要了解win32 编程。熟悉win32编程之后,就可以轻松进行win32 界面编程。

一、什么是win32 编程

Win32编程,指的是用Window提供的APIApplication Programming Interface)为Window编写应用程序。 之所以称之为Win32,是因为现在的Window都是32位的(现在已经有64位的吧!但是最普遍是32位).win32 是指Window都是32位的操作系统,例如98XP20002003等操作系统, win32编程就是在这些系统下的编程 ,运用Window提供的APIApplication Programming Interface)为Window编写应用程序。
win32
编程可以用C来完成,主要是通过windowsAPI来工作.但是API上千个,想全部掌握很难,建议安装一个MSDN随时查看.书籍方面又PetzeldWindows程序设计,上下两册,讲的比较全面,但是内容很多. 建议你先学C++,估计你是对控制台那个黑屏厌烦的,但是进入windows后你会发现,它比DOS的还烦!Win32编程,指的是用Window提供的APIApplication Programming Interface)为Window编写应用程序。 之所以称之为Win32,是因为现在的Window都是32位的(现在已经有64位的吧!但是最普遍是32位)。大家都知道,Window是由GDI.DLLUSER.DLLKERNEL.DLL三大主要部分组成的。那么学习Win32编程的大部分(特别是应用程序界面部分的编程)是用这三个DLLDynatic Linked Library)动态链接库子程序形式提供的API函数。

首先:你必须有编程的经验。这里的经验不是指传统的DOS下的字符模式下的编程。大家都知道,Window是图形操作系统、同时也多任务抢占式(理解它很重要),它是在图形模式下工作。当然你编程得服从于它。但是正 是因为这个,Window的编程模式就和DOS不一样。所有你得有DOS下编程的经验,但是还得转变为WINDOW下的编程方式。因为两个系统的编程一个是过程化的。即程序从上到下,顺序执行。而另一个是,事件驱动的。要明白这个,才会体验到Window的博大精深。

事件驱动:我们知道DOS下程序是顺序执行的。至少它是按着你指定的路径或条件执行的。尽管可能会在某些条件下跳转,但是基本上是在你(程序的掌握之中),但是在事件驱动中,你只需考虑到可能出现的情况,并对这些情况做相应的处理。当Window执行你的程序时,它会检测是否发生了你考虑的那些事情是否发生,如果发生了某件事情(比如你用鼠标单击),它会给你的程序发送相应的消息(所以叫做消息驱动,这里对就鼠标的消息是WM_MOUSELDOWN等)。
windows操作系统是靠消息的驱动的,所有的事件都被封装为各种各样的消息,系统和其他程序通过接受消息,分析消息附带的参数,再分别进行相关的处理,然后完成相关的任务。不管用什么语言,或者什么开发工具,只要是在windows下可以运行的程序,在他的本质上都有一个接受消息、处理消息的循环。这就是win32程序乃至整个windows操作系统本身的运做本质。

学习WIN32需要看那些资料,这里推荐《windows程序设计》、《windows api参考大全》、《windows核心编程》、MSDN

二、怎样使用APIWindows程序

1、先来看个简单实例:

#include"windows.h"
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,PSTRszCmdLine,intiCmdShow)

{
  MessageBox(NULL,TEXT("你好,欢迎来到VC之路"),TEXT("欢迎"),0);
  return0;

}

第一个参数:应用程序的当前实例句柄。

第二个参数:应用程序的前一个实例句柄,别管它,对于Win32位而言,它一般是NULL.

第三个参数:指向任何传给程序的命令行参数。PSTR代表"指向字符串的指针"

第四个参数:它告诉应用程序如何初始化窗口,如最大化,最小化等状态。

WinMain()所起的作用:初始化,展示,销毁应用程序等。
2、消息机制

#include"stdafx.h"//注意,这个向导产生的头文件不能去掉
#include<windows.h>
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,
intiCmdShow)
{
staticTCHARszAppName[]=TEXT("HelloWin");

HWNDhwnd;
MSGmsg;

WNDCLASSwc;
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=(HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName=NULL;
wc.lpszClassName=szAppName;
if
(!RegisterClass(&wc))
{
MessageBox(NULL,TEXT("ThisprogramrequiresWindowsNT!"),szAppName,MB_ICONERROR);
return0;

}
hwnd=CreateWindow(szAppName,
//windowclassname
TEXT("
欢迎你的到来!"),//windowcaption
WS_OVERLAPPEDWINDOW,
//windowstyle
CW_USEDEFAULT,
//initialxposition
CW_USEDEFAULT,//initialyposition

CW_USEDEFAULT,
//initialxsize
CW_USEDEFAULT,
//initialysize
NULL,
//parentwindowhandle
NULL,
//windowmenuhandle
hInstance,
//programinstancehandle
NULL);
//creationparameters
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while
(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;

}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
HDChdc;
PAINTSTRUCTps;
RECTrect;
switch
(message)
{
case
WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,TEXT("
你好,欢迎你来到VC之路!"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(hwnd,&ps);
return
0;
case
WM_DESTROY:
PostQuitMessage(0);
return
0;
}
return
DefWindowProc(hwnd,message,wParam,lParam);
}

3Windows编程的特点

C语言编程至少有一个主程序,其名字是main()Windows程序则至少两个主程序,一个是WinMain(),

int WINAPI WinMain(

          HINSTANCE hInstance,   // handle to current instance

          HINSTANCE hPrevInstance,  // handle to previous instance

          LPSTR lpCmdLine,     // command line

          int nCmdShow     // show state

         );

另一个是窗口过程函数WndProc,它的函数原型为:

long FAR PASCAL WndProc(HWND hWnd,WORD message,WORD wParam,LONG lParam);

Windows应用程序的编程就围绕这两个部份进行的。其中WinMain函数为应用程序的入口点,它的名字一定要是WinMain

Windows中,应用程序通过要求Windows完成指定操作,而承担这项通信任务的API函数就是Windows的相应窗口函数WndProc。在dos里,程序能直接控制事件的发生顺序,结果等。而在Windows里,应用程序不直接调用任何窗口函数,而是等待Windows调用窗口函数,请求完成任务或返回信息。为保证Windows调用这个窗口函数,这个函数必须先向Windows登记,然后在Windows实施相应操作时回调,所以窗口函数又称为回调函数WndProc是一个主回调函数,Windows至少有一个回调函数。

回调函数WndProc在哪里定义的呢,请看这个语句:wc.lpfnWndProc = WndProc .

我把这个程序支解为四块:
(
)建立注册窗口类.

()创建窗口.
()显示和更新窗口.
()创建消息循环.
()终止应用程序.
()窗口过程.
()处理消息.

()注册窗口类:

(1)建立窗口类

WinMain()是程序的入口,它相当于一个中介人的角色,把应用程序(指小窗口)介绍给windows.首要的一步是登记应用程序的窗口类.

窗口种类是定义窗口属性的模板,这些属性包括窗口式样,鼠标形状,菜单等等,窗口种类也指定处理该类中所有窗口消息的窗口函数.只有先建立窗口种类,才能根据窗口种类来创建Windows应用程序的一个或多个窗口.创建窗口时,还可以指定窗口独有的附加特性.窗口种类简称窗口类,窗口类不能重名.在建立窗口类后,必须向Windows登记.

建立窗口类就是用WNDCLASS结构定义一个结构变量,在这个程序中就是指WNDCLASS wc ;然后用自己设计的窗口属性的信息填充结构变量wc的域.

WinMain登记窗口类,首先要填写一个WNDCLASS结构,其定义如下所示:

   typedef struct _WNDCLASSA

   {

     UINT style ;         //窗口类风格

     WNDPROC lpfnWndProc ;    //指向窗口过程函数的指针

     int cbClsExtra ;       //窗口类附加数据

     int cbWndExtra ;       //窗口附加数据

     HINSTANCE hInstance ;    //拥有窗口类的实例句柄

     HICON hIcon ;        //最小窗口图标

     HCURSOR hCursor ;      //窗口内使用的光标

     HBRUSH hbrBackground ;   //用来着色窗口背景的刷子

     LPCSTR lpszMenuName ;    //指向菜单资源名的指针

     LPCSTR lpszClassName ;   // 指向窗口类名的指针

   }

VC6.0里面,把光标定位在WNDCLASS上,按F1,即可启动MSDN,在MSDN里你可看到这个结构原形.在下节讲解这些参数在本程序中的具体用法.

(2)注册窗口类

(1)第一个参数:成员style控制窗口的某些重要特性,在WINDOWS.H中定义了一些前缀为CS的常量,在程序中可组合使用这些常量.也可把sytle设为0.本程序中为wc.style = CS_HREDRAW | CS_VREDRAW它表示当窗口的纵横坐标发生变化时要重画整个窗口。你看:无论你怎样拉动窗口的大小,那行字都会停留在窗口的正中部,而假如把这个参数设为0的话,当改动窗口的大小时,那行字则不一定处于中部了。

(2)第二个参数:lpfnWndProc包括一个指向该窗口类的消息处理函数的指针,此函数称为窗口过程函数。它将接收Windows发送给窗口的消息,并执行相应的任务。其原型为:

long FAR PASCAL WndProc(HWND ,unsigned,WORD,LONG);并且必须在模快定义中回调它。WndProc是一个回调函数(见第五节),如果暂时无法理解这个模糊的概念意味着什么,可先放过,等到讲消息循环时再详谈。

(3)第三,四个参数:cbWndExtra域指定用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。这般来讲,你只要把它们设为0就行了,不必过多考虑。

(4)第五个参数:hInstance域标识应用程序的实例hInstance,当然,实例名是可以改变的。wc.hInstance = hInstance ;这一成员可使Windows连接到正确的程序。

(5)第六个参数:成员hIcon被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用以表示程序仍驻留在内存中。Windows提供了一些默认图标,我们也可定义自己的图标,VC里面专有一个制作图标的工具。

(6)第七个参数: hCursor域定义该窗口产生的光标形状。LoadCursor可返回固有光标句柄或者应用程序定义的光标句柄。IDC_ARROW表示箭头光标.

(7)第八个参数:wc.hbrBackground域决定Windows用于着色窗口背景的刷子颜色,函数GetStockObject返回窗口的颜色,本程序中返回的是白色,你也可以把它改变为红色等其他颜色.试试看

(8)第九个参数:lpszMenuName用来指定菜单名,本程序中没有定义菜单,所以为NULL

(9)第十个参数:lpszClassName指定了本窗口的类名。

当对WNDCLASS结构域一一赋值后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的API函数是RegisterClass,注册失败的话,就会出现一个对话框如程序所示,函数RegisterClass返回0,也只能返回0值,因为注册不成功,程序已经不能再进行下去了。

在本程序中注册窗口类如下:

if (!RegisterClass (&wc)) {

       MessageBox (NULL, TEXT ("This program requires Windows NT!"),

               szAppName,MB_ICONERROR) ;

       return 0 ;

             }

()创建窗口

注册窗口类后,就可以创建窗口了,本程序中创建窗口的有关语句如下:

 hwnd = CreateWindow (szAppName, // window class name

TEXT ("欢迎你的到来!"),    // window caption

WS_OVERLAPPEDWINDOW, // window style

CW_USEDEFAULT, // initial x position

CW_USEDEFAULT, // initial y position

CW_USEDEFAULT, // initial x size

CW_USEDEFAULT, // initial y size

NULL, // parent window handle

NULL, // window menu handle

hInstance, // program instance handle

NULL) ; // creation parameters

参数1:登记的窗口类名,这个类名刚才咱们在注册窗口时已经定义过了。

参数2用来表明窗口的标题。

参数3: 用来表明窗口的风格,如有无最大化,最小化按纽啊什么的。

参数4,5: 用来表明程序运行后窗口在屏幕中的坐标值。

参数6,7: 用来表明窗口初始化时(即程序初运行时)窗口的大小,即长度与宽度。

参数8: 在创建窗口时可以指定其父窗口,这里没有父窗口则参数值为0

参数9: 用以指明窗口的菜单,菜单以后会讲,这里暂时为0

最后一个参数是附加数据,一般都是0

CreateWindow()的返回值是已经创建的窗口的句柄,应用程序使用这个句柄来引用该窗口。如果返回值为0,就应该终止该程序,因为可能某个地方出错了。如果一个程序创建了多个窗口,则每个窗口都有各自不同的句柄.

()显示和更新窗口

API函数CreateWindow创建完窗口后,要想把它显示出现,还必须调用另一个API函数ShowWindows.形式为:

ShowWindow (hwnd, iCmdShow);

其第一个参数是窗口句柄,告诉ShowWindow()显示哪一个窗口,而第二个参数则告诉它如何显示这个窗口:最小化(SW_MINIMIZE),普通(SW_SHOWNORMAL),还是最大化(SW_SHOWMAXIMIZED)WinMain在创建完窗口后就调用ShowWindow函数,并把iCmdShow参数传送给这个窗口。你可把iCmdShow改变为这些参数试试。

WinMain()调用完ShowWindow后,还需要调用函数UpdateWindow,最终把窗口显示了出来。调用函数UpdateWindow将产生一个WM_PAINT消息,这个消息将使窗口重画,即使窗口得到更新.

()创建消息循环

主窗口显示出来了,WinMain就开始处理消息了,怎么做的呢?

Windows为每个正在运行的应用程序都保持一个消息队列。当你按下鼠标或者键盘时,Windows并不是把这个输入事件直接送给应用程序,而是将输入的事件先翻译成一个消息,然后把这个消息放入到这个应用程序的消息队列中去。应用程序又是怎么来接收这个消息呢?这就讲讲消息循环了。

应用程序的WinMain函数通过执行一段代码从她的队列中来检索Windows送往她的消息。然后WinMain就把这些消息分配给相应的窗口函数以便处理它们,这段代码是一段循环代码,故称为"消息循环"。这段循环代码是什么呢?好,往下看:

在咱们的第二只小板凳中,这段代码就是:

......

MSG msg; //定义消息名

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

{

TranslateMessage (&msg) ; //翻译消息

DispatchMessage (&msg) ; //撤去消息

}

return msg.wParam ;

MSG结构在头文件中定义如下:

typedef struct tagMSG

{

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

} MSG, *PMSG;

MSG数据成员意义如下:

参数1hwnd是消息要发送到的那个窗口的句柄,这个窗口就是咱们用CreateWindows函数创建的那一个。如果是在一个有多个窗口的应用程序中,用这个参数就可决定让哪个窗口接收消息。

参数2:message是一个数字,它唯一标识了一种消息类型。每种消息类型都在Windows文件中定义了,这些常量都以WM_开始后面带一些描述了消息特性的名称。比如说当应用程序退出时,Windows就向应用程序发送一条WM_QUIT消息。

参数3:一个32位的消息参数,这个值的确切意义取决于消息本身。

参数4:同上。

参数5:消息放入消息队列中的时间,在这个域中写入的并不是日期,而是从Windows启动后所测量的时间值。Windows用这个域来使用消息保持正确的顺序。

参数6:消息放入消息队列时的鼠标坐标.

消息循环以GetMessage调用开始,它从消息队列中取出一个消息:

GetMessage(&msg,NULL,0,0),第一个参数是要接收消息的MSG结构的地址,第二个参数表示窗口句柄,NULL则表示要获取该应用程序创建的所有窗口的消息;第三,四参数指定消息范围。后面三个参数被设置为默认值,这就是说你打算接收发送到属于这个应用程序的任何一个窗口的所有消息。在接收到除WM_QUIT之外的任何一个消息后,GetMessage()都返回TRUE。如果GetMessage收到一个WM_QUIT消息,则返回FALSE,如收到其他消息,则返回TRUE。因此,在接收到WM_QUIT之前,带有GetMessage()的消息循环可以一直循环下去。只有当收到的消息是WM_QUIT时,GetMessage才返回FALSE,结束消息循环,从而终止应用程序。 均为NULL时就表示获取所有消息。

消息用GetMessage读入后(注意这个消息可不是WM_QUIT消息),它首先要经过函数TranslateMessage()进行翻译,这个函数会转换成一些键盘消息,它检索匹配的WM_KEYDOWNWM_KEYUP消息,并为窗口产生相应的ASCII字符消息(WM_CHAR),它包含指定键的ANSI字符.但对大多数消息来说它并不起什么作用,所以现在没有必要考虑它。

下一个函数调用DispatchMessage()要求Windows将消息传送给在MSG结构中为窗口所指定的窗口过程。我们在讲到登记窗口类时曾提到过,登记窗口类时,我们曾指定Windows把函数WindosProc作为咱们这个窗口的窗口过程(就是指处理这个消息的东东)。就是说,Windows会调用函数WindowsProc()来处理这个消息。在WindowProc()处理完消息后,代码又循环到开始去接收另一个消息,这样就完成了一个消息循环。


()终止应用程序:

Windows是一种非剥夺式多任务操作系统。只有的应用程序交出CPU控制权后,Windows才能把控制权交给其他应用程序。当GetMessage函数找不到等待应用程序处理的消息时,自动交出控制权,WindowsCPU的控制权交给其他等待控制权的应用程序。由于每个应用程序都有一个消息循环,这种隐式交出控制权的方式保证合并各个应用程序共享控制权。一旦发往该应用程序的消息到达应用程序队列,即开始执行GetMessage语句的下一条语句。

WinMain函数把控制返回到Windows时,应用程序就终止了。应用程序的启动消息循环前要检查引导出消息循环的每一步,以确保每个窗口已注册,每个窗口都已创建。如存在一个错误,应用程序应返回控制权,并显示一条消息。

但是,一旦WinMain函数进入消息循环,终止应用程序的唯一办法就是使用PostQuit

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值