• (转)1.win32编程一


    一、Win32编程基本概念

    1、消息驱动

    在介绍Windows消息驱动概念之前,我们首先来回顾面向过程的程序结构:main()程序有明显的开始、中间过程和结束点,程序是围绕这个过程编写好相关的子过程,再把这些子过程串联在一起。程序编好以后,该过程也就确定了,程序必须按照规定好的顺序执行:是否需要用户的输入、输入什么、程序取得用户输入以后做什么处理,处理完毕将结果显示给用户。该过程一旦确定,程序的执行过程也是固定的,用户不能干预。

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

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

    这种消息驱动机制,有点像银行的柜台业务:早上八点,银行开门(Windows应用程序开始运行),每个营业员(Windwows线程)回到自己的柜台开始办公。如果有顾客来办理相关业务(相当于Windows消息),那么对应的业务员就进行处理。顾客来办理业务的时间以及业务类型都是随机的,如果某一时刻没有顾客办理业务并且没有到下班时间(Windows应用程序退出)的话,那么相关的业务员进入等待状态。所有的业务员不断重复该过程,直到下班(Windows应用程序退出)。

    2、应用程序、操作系统、IO设备之间的相互关系

    3、窗口元素

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

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

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

    菜单栏:位于标题栏下方,菜单栏列出了应用程序支持的大部分功能。

    图标: 适用于提醒用户的一个小图像,代表一个应用程序。

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

    工具栏:一般位于菜单栏下方,上面有一些位图按钮,代表一些常用功能。

    状态栏:位于这个窗口底端,用于输出菜单提示信息和一些其他详细信息。

    对话框:一种特殊的窗口,用于接受用户的输入输出。

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

    4、编程术语

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

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

    句柄:系统用来识别不同对象或者同类对象的不同实例的"编号"。它是一个无符号整数。几乎所有对对象的引用都是通过句柄来进行的。如使用HINSTANCE、HWND、HCURSOR、HICON、HDC、HBRUSH、HPEN等。

    资源:构成应用程序的元素称为资源:菜单、工具条、位图、字符串等。

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

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

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

    二、第一个Win32程序

    Win32程序的入口为WinMain`函数,是由操作系统调用的。和main()函数不同,WinMain有严格的原型定义,不能改变。其原型如下:

    int WINAPI WinMain(

    HINSTANCE  hInstance,              //当前实例句柄

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

    LPSTR           lpCmdLine,           //命令行参数

    int                 nCmdShow            //窗口显示方式,如SW_ SHOWNORMAL等

    );

    这里我们看到了一些不认识的大写字符,在此后的学习中,我们还会大量遇到这种情况。稍后我们会专门讲解。

    Windows编程和DOS编程最大的不同之一就在于DOS是字符界面的,而Windows是图形界面的,因此Win32编程第一个重要的工作就是创建窗口。

    创建一个Win32程序的典型步骤如下:

    l  注册窗口类:RegisterClass()。定义窗口类,以指明窗口的外观和窗口回调函数等

    l  创建窗口:CreateWindow()。创建一个窗口实例

    l  显示窗口:ShowWindow()。显示刚刚创建的窗口

    l  更新窗口:UpdateWindow()。更新窗口

    l  消息循环:while (GetMessage(&msg, NULL, 0, 0))。进行消息循环,不断的处理消息。

    l  实现回调函数:由系统调用,程序员负责代码实现,告诉系统如何响应消息。

    例1、       创建一个简单的Win32应用程序MyWin

    打开VS6.0,选择File菜单的New,在出现的对话框中,选择Projects栏目(新建工程),并点取其下的Win32 Application项,表示使用Win32环境创建应用程序。先在Locatin(路径)中选择要保存项目文件的路径,然后在Project Name(项目名称)中填入"MyWin",其它按照缺省设置)。单击OK按钮。代码如下:

    #include <windows.h>

    #include <stdio.h>

    //声明窗口回调函数

    LRESULT CALLBACK WinProc(

           HWND hwnd,        // 窗口句柄

           UINT uMsg,          // 消息ID

           WPARAM wParam,      // 第1个消息参数

           LPARAM lParam   // 第2个消息参数

    );

    //程序入口

    int WINAPI WinMain(

      HINSTANCE hInstance,           // 当前实例句柄

      HINSTANCE hPrevInstance,    // 前一实例句柄

      LPSTR lpCmdLine,                  // 命令行参数

      int nCmdShow                        // 窗口显示方式

    )

    {

           //1. 注册窗口

           WNDCLASS wndcls;    //定义并填充窗口类

           wndcls.cbClsExtra = 0;

           wndcls.cbWndExtra = 0;

           wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

           wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);

           wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);

           wndcls.hInstance = hInstance;

           wndcls.lpfnWndProc = WinProc;  //重点:指定回调函数

           wndcls.lpszClassName = "Itjob2010";

           wndcls.lpszMenuName = NULL;

           wndcls.style = CS_HREDRAW | CS_VREDRAW;

           RegisterClass(&wndcls);              //注册窗口

           //2. 创建窗口

           HWND hwnd;

           hwnd = CreateWindow(

                  wndcls.lpszClassName,  //窗口类名称

                  "一个简单的Win32程序",   //窗口标题

                  WS_OVERLAPPEDWINDOW,   //窗口风格,定义为普通型

                  0,                                       //窗口位置的x坐标

                  0,                                       //窗口位置的y坐标

                  600,                             //窗口的宽度

                  400,                             //窗口的高度

                  NULL,                                //父窗口句柄

                  NULL,                                //菜单句柄

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

                  NULL);                               //窗口创建数据指针

           //3. 显示窗口

           ShowWindow(hwnd, SW_SHOWNORMAL);

           //4. 更新窗口

           UpdateWindow(hwnd);

           //5. 消息循环

           MSG msg;

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

           {

                  TranslateMessage(&msg);             //把虚键消息翻译成字符消息(WM_CHAR),

                                                                   //再把它放回到应用程序的消息队列中去

                  DispatchMessage(&msg);             //指示操作系统把这条消息发送到窗口

                                                                   //过程WinProc进行处理

           }

           return 0;

    }

    //窗口回调函数,由操作系统调用,程序员

    //不要调用,但程序员需要编写其实现代码

    LRESULT CALLBACK WinProc(

           HWND hwnd,        // 窗口句柄

           UINT uMsg,          // 消息ID

           WPARAM wParam,      // 第1个消息参数

           LPARAM lParam   // 第2个消息参数

    )

    {

           switch (uMsg)

           {

           case WM_CHAR:

                  sprintf(szChar, "你按下了%c键", (char)wParam);

                  MessageBox(hwnd, szChar, "WM_CHAR", 0);

                  break;

           case WM_LBUTTONDOWN:

                  HDC hdc;

                  hdc = GetDC(hwnd);

                  TextOut(hdc, 0, 50, "计算机编程语言培训", strlen("计算机编程语言培训"));

                  ReleaseDC(hwnd, hdc);

                  break;

           case WM_PAINT:

                  HDC hDC;

                  PAINTSTRUCT ps;

                  hDC = BeginPaint(hwnd, &ps);

                  TextOut(hDC, 0, 0, "Hello, World!", strlen("Hello, World!"));

                  EndPaint(hwnd, &ps);

                  break;

           case WM_DESTROY:

                  PostQuitMessage(0);

                  break;

           default:

                  return DefWindowProc(hwnd, uMsg, wParam, lParam);

           }

           return 0;

    }

    编译,运行该程序。运行结果为出现一个简单的Windows窗口。在窗口空白区点击鼠标左键,会在屏幕上出现:计算机编程语言培训;按下a键,会提示:你按下了a键!

    这是一个最简单的Win32应用程序,其他较复杂的Windows应用程序都是在这样的程序框架上扩展得到的。

    下面对上述程序进行解释说明。

    l  WinMain()函数

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

    int WINAPI WinMain(

    HINSTANCE  hInstance,              //当前实例句柄

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

    LPSTR           lpCmdLine,           //命令行参数

    int                 nCmdShow            //窗口显示方式,如SW_ SHOWNORMAL等

    );

    参数说明如下:

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

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

    lpCmdLine:是指向应用程序命令行参数字符串的指针。如在"开始"菜单中单击"运行",输入"WinMain.exe hello",则此参数指向的字符串为"hello"。

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

    l  注册窗口类

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

    typedef struct _WNDCLASS {

    UINT             style;                    //窗口风格,通常取值CS_HREDRAW|CS_VREDRAW

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

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

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

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

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

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

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

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

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

    } WNDCLASS;

    在这里提一下匈牙利表示法:其中的lpfn字首代表“指向函数的长指针”。cb字首代表“字节数”而且通常作为一个常数来表示一个字节的大小。h字首是一个句柄,而hbr字首代表“一个画刷的句柄”。lpsz字首代表“指向以0结尾字符串的指针”。

    参数含义如下:

    style:一般取值CS_VREDRAW|CS_HREDRAW,表示当窗口的水平方向或垂直方向的大小改变之后,窗口要全部重画。style窗口类型定义如下:

    #define      CS_VREDRAW            0x0001

    #define      CS_HREDRAW                 0x0002

    #define      CS_KEYCVTWINDOW      0x0004

    #define      CS_DBLCLKS             0x0008

    #define      CS_OWNDC              0x0020

    由于每个识别字都可以在一个复合值中设置一个位的值,所以按这种方式定义的识别字通常称为“位标识”。

    lpfnWndProc:设定这个窗口类的窗口消息处理程序,即设定消息过程处理函数。该函数将处理根据这个窗口类所建立的所有窗口的全部消息。在C语言中,像这样在结构中使用函数名时,真正提供的是指向函数的指针。

    cbClsExtra:指定分配给窗口类结构之后的额外字节数,一般设为0

    cbWndExtra:指定分配给窗口实例之后的额外字节数,一般设为0

    hInstance:程序的执行实体句柄(它也是WinMain的参数之一)

    hIcon:LoadIcon (NULL, IDI_APPLICATION) ;为窗口设置一个图标。图标是一个小的点阵图图像,它对使用者代表程序,将出现在Windows工作列中和窗口的标题列的左端。在本书的后面,您将学习如何为您的Windows程序自定义图标。现在,为了方便起见,我们将使用预先定义的图标。要取得预先定义图标的句柄,可以将第一个参数设定为NULL来调用LoadIcon。在载入程序写作者自定义的图标时(图标应该存放在磁片上的.EXE程序文件中),这个参数应该被设定为程序的执行实体句柄hInstance。第二个参数代表图标。对于预先定义图标,此参数是以IDI开始的识别字(「ID代表图标」),识别字在WINUSER.H中定义。IDI_APPLICATION图标是一个简单的窗口小图形。LoadIcon函数传回该图标的句柄。我们并不关心这个句柄的实际值,它只用于设置hIcon栏位的值。该栏位在WNDCLASS结构中定义为HICON型态,此型态名的含义为「handle to an icon(图标句柄)」。

    hCursor:LoadCursor (NULL, IDC_ARROW) ;与hIcon非常相似。LoadCursor函数载入一个预先定义的鼠标游标(命名为IDC_ARROW),并传回该游标的句柄。该句柄被设定给WNDCLASS结构的hCursor栏位。当鼠标游标在依据这个类别建立的窗口的显示区域上出现时,它变成一个小箭头。

    hbrBackground:指定窗口背景颜色。hbrBackground栏位名称中的hbr字首代表「handle to a brush(画刷句柄)」。画刷是个绘图词汇,指用来填充一个区域的着色样式。Windows有几个标准画刷,也称为「备用(stock)」画刷。这里所示的GetStockObject调用将传回一个白色画刷的句柄:GetStockObject (WHITE_BRUSH) ;这意味著窗口显示区域的背景完全为白色,这是一种极其普遍的做法。

    lpszMenuName:指定菜单。这里没有菜单,可以设定为NULL。

    lpszClassName:给出一个类别名称。对于小程序,类别名称可以与程序名相同。

    对WNDCLASS填充完毕后,调用RegisterClass函数进行窗口注册。函数原型如下:

    ATOM RegisterClass( CONST WNDCLASS *lpWndClass );

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

    l  创建窗口

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

    HWND CreateWindow(

    LPCTSTR       lpClassName,         //窗口类名称

    LPCTSTR       lpWindowName,    //窗口标题

    DWORD        dwStyle,                //窗口风格,定义为普通型

    int                 x,                         //窗口位置的x坐标

    int                 y,                          //窗口位置的y坐标

    int                 nWidth,                 //窗口的宽度

    int                 nHeight,                //窗口的高度

    HWND          hWndParent,          //父窗口句柄

    HMENU        hMenu,                 //菜单句柄

    HANDLE       hInstance,              //应用程序实例句柄

    LPVOID        lpParam                //窗口创建数据指针,一般为NULL

    );

    部分参数的含义如下:

    lpszClassName:创建该窗口所使用的窗口类的名称,该名称应与前面所注册的窗口类的名称一致。

    lpWindowName:窗口标题栏的文字。

    dwStyle:窗口的风格,下面列出了常用的窗口风格:

    WS_OVERLAPPEDWINDOW:创建一个层叠式窗口,有边框、标题栏、系统菜单、最大化和最小化按钮,本质是以下几种风格的与或:

    WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX

    WS_POPUPWINDOW:创建一个弹出式窗口,是以下几种风格的与或:

    WS_BORDER,WS_POPUP,WS_SYSMENU。

    WS_OVERLAPPED:创建一个层叠式窗口,它有标题栏和边框,同WS_TILED

    WS_POPUP:该窗口为弹出式窗口,不能与WS_CHILD同时使用

    WS_BORDER:窗口有单线边框

    WS_CAPTION:窗口有标题栏

    WS_CHILD:该窗口为子窗口,不能与WS_POPUP同时使用

    WS_DISABLED:该窗口为无效,即对用户操作不产生任何反应

    WS_VISIBLE:窗口为可见

    WS_HSCROLL:窗口有水平滚动条

    WS_VSCROLL:窗口有垂直滚动条

    WS_MAXIMIZE:窗口初始化为最大化

    WS_MINIMIZE:窗口初始化为最小化

    WS_MAXIMIZEBOX:窗口有最大化按钮

    WS_MINIMIZEBOX:窗口有最小化按钮

    WS_SIZEBOX:边框可进行大小控制的窗口

    WS_SYSMENU:创建一个有系统菜单的窗口,必须与WS_CAPTION风格同时使用

    WS_THICKFRAME:创建一个大小可控制的窗口,与WS_SIZEBOX 风格一样.

    WS_TILED:创建一个层叠式窗口,有标题栏

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

           特别注意:CreateWindow函数在返回之前,会发送一条WM_CREATE消息到窗口的消息队列,对于Overlapped、Pop-up和Child窗口,CreateWindow函数还会发送WM_GETMINMAXINFO、WM_NCCREATE消息。这就给我们在ShowWindow显示窗口之前提供了一个入口点OnCreate(),在这里可以做一些初始化的工作。

    l  显示窗口

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

    BOOL ShowWindow( HWND hWnd, int nCmdShow );

    hWnd:         指定要显示的窗口的句柄,

    nCmdShow: 表示窗口的显示方式,如SW_SHOWNORMAL,详见MSDN。

    也会触发WM_SIZE消息

    l  更新窗口

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

    BOOL UpdateWindow( HWND hWnd );

    特别注意:UpdateWindow函数会发送一条WM_PAINT消息到窗口的消息队列,以重绘窗口。

    l  消息循环

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

    MSG msg;

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

    {

           TranslateMessage(&msg);

           DispatchMessage(&msg);

    }

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

    GetMessage()函数主要用来从消息队列中取出一条消息。其原型为:

    BOOL GetMessage(

    LPMSG   lpMsg,                  //消息指针,用于接收消息

    HWND   hWnd,                   //窗口句柄

    UINT      wMsgFilterMin,     //first message

    UINT      wMsgFilterMax      //last message

    );

    lpMsg:表示Windows消息的结构,用于保存接收到的消息。

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

    wMsgFilterMin和wMsgFilterMax:用来过滤MSG结构中主消息值的,主消息值在wMsgFilterMin和wMsgFilterMax之外的消息将被过滤掉。如果这两个参数为0,则表示接收所有消息。

    当且仅当GetMessage()函数在获取到WM_QUIT消息后,将返回FALSE(0)值,于是程序退出消息循环。调用PostQuitMessage()函数可以发送WM_QUIT消息。

    TranslateMessage()函数的作用是把虚拟键消息转换到字符消息,以满足键盘输入的需要。如果虚拟键码确实可以转换成字符,就会发送一条WM_CHAR消息到消息队列。

    DispatchMessage()函数所完成的工作是把当前的消息发送到对应的窗口过程中去。

    l  消息处理函数

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

    LRESULT CALLBACK WindowProc(

    HWND          hwnd,            //接收消息窗口的句柄 

    UINT             uMsg,            //主消息值

    WPARAM      wParam,         //副消息值

    LPARAM       lParam           //副消息值

    );

    如果你的程序中还有其它的消息处理函数,也都必须按照上面的这个样式来定义,但函数名称可以随便取。消息处理函数的四个参数是由GetMessage()函数从消息队列中获得MSG结构,然后分解得到的。

    hwnd:接收消息窗口的句柄。

    uMsg:和MSG结构中的message值是一致的,代表了主消息值。程序中用switch语句来将不同类型的消息分配到不同的处理程序中去。

    wParam和lParam:附加的消息参数。其含义随主消息uMsg的不同而不同,查阅MSDN。如,对于WM_KEYDOWN主消息,查阅MSDN,有如下说明:

    chCharCode = (TCHAR) wParam;              //character code

    lKeyData = lParam;                            //key data

    而对于WM_LBUTTONDOWN,查阅MSDN,有如下说明:

    fwKeys = wParam;        // key flags

    xPos = LOWORD(lParam);   // horizontal position of cursor

    yPos = HIWORD(lParam);    // vertical position of cursor

    在上例中,WinProc()函数明确的处理了4个消息,分别是WM_CHAR(按键消息)、WM_RBUTTONDOWN(鼠标左键按下消息)、WM_PAINT(窗口重画消息)、WM_DESTROY(销毁窗口消息)。值得注意的是,应用程序发送到窗口的消息远远不止以上这几条,象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等这样频频使用的消息就有几十条。为了减轻编程的负担,Windows的API提供了DefWindowProc()函数来处理这些最常用的消息,调用了这个函数后,这些消息将按照系统默认的方式得到处理。

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

    l  结束消息循环

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

    三、Windows应用程序编程接口------Windows API

           在上例中,我们接触了许多以前没见过的函数,如MessageBox, TextOut,CreateWindow, PostQuitMessage等等,这些就是所谓的Windows API函数。

    Windows操作系统通过两种接口对外提供服务:普通用户操作接口服务和程序员接口服务。其中用户操作接口服务是通过最终用户的操作来完成的,而程序员接口服务是提供一系列底层的实现操作系统最基本的函数(接口)供程序员调用来完成相关功能的。比如一个文件的拷贝,普通用户可以通过鼠标菜单选择操作或者命令来完成,程序员可以通过程序代码调用文件操作的相关函数(API)来完成相同的功能。

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

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

    API函数集是由操作系统或开发环境提供的,以DLL的形式出现。其中有三个最主要的动态连接库: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)等等。

    例2、使用Windows API实现一些简单的系统功能

    建立一个控制台空工程,加入文件API.cpp,文件内容如下:

    // API.cpp : 定义控制台应用程序的入口点。

    #include <iostream>

    #include <Windows.h>

    #include <stdio.h>

    #include <stdlib.h>

    using namespace std;

    //获取计算机名称,CPU数量,CPU类型,已用内存百分比,物理内存总数,空闲物理内存

    void GetSysInfo()

    {

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

        DWORD MaxComputerlenth = MAX_COMPUTERNAME_LENGTH;

           CHAR ComputerName[MAX_COMPUTERNAME_LENGTH];

          

        // 调用API函数GetComputerName获取计算机名称存放到ComputerName中。

        GetComputerName(ComputerName, &MaxComputerlenth);

           cout << "本台计算机的名称为:" << ComputerName << endl;

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

        SYSTEM_INFO siSysInfo;

           TCHAR tchBuffer[100];

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

           GetSystemInfo(&siSysInfo);

          

        // 输出相关系统信息

           sprintf(tchBuffer,"CPU的数量: %u\tCPU类型: %u",

                  siSysInfo.dwNumberOfProcessors, siSysInfo.dwProcessorType);

           cout << tchBuffer << endl;

          

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

           MEMORYSTATUS stat;

        GlobalMemoryStatus(&stat);

           // 进行输出

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

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

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

    }

    void CopyCppFile()

    {

           WIN32_FIND_DATA FileData;

           HANDLE hSearch;

           DWORD dwAttrs;

           TCHAR szDirPath[] = TEXT("c:\\CppFiles\\");

           TCHAR szNewPath[MAX_PATH];

          

           BOOL fFinished = FALSE;

          

           // Create a new directory.

           if (!CreateDirectory(szDirPath, NULL))

           {

                  printf("Could not create new directory.\n");

                  //return;

           }

          

           // Start searching for text files in the current directory.

           hSearch = FindFirstFile(TEXT("*.cpp"), &FileData);

           if (hSearch == INVALID_HANDLE_VALUE)

           {

                  printf("No *.cpp files found.\n");

                  return;

           }

          

           // Copy each .TXT file to the new directory

           // and change it to read only, if not already.

           while (!fFinished)

           {

                  if (CopyFile(FileData.cFileName, szNewPath, FALSE))

                  {

                         dwAttrs = GetFileAttributes(FileData.cFileName);

                         //if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;

                        

                         if (!(dwAttrs & FILE_ATTRIBUTE_READONLY))

                         {

                                SetFileAttributes(szNewPath,

                                       dwAttrs | FILE_ATTRIBUTE_READONLY);

                         }

                  }

                  else

                  {

                         printf("Could not copy file.\n");

                         //return;

                  }

                 

                  if (!FindNextFile(hSearch, &FileData))

                  {

                         if (GetLastError() == ERROR_NO_MORE_FILES)

                         {

                                printf("Copied all cpp files.\n");

                                fFinished = TRUE;

                         }

                         else

                         {

                                printf("Could not find next file.\n");

                                return;

                         }

                  }

           }

          

           // Close the search handle.

           FindClose(hSearch);

    }

    void main()

    {

           SYSTEMTIME tm;

           ::GetLocalTime(&tm);

           char szBuf[] = "当前时间是:2010年12月31日 23:59:59";

           sprintf(szBuf, "当前时间是:%4d年%.2d月%.2d日 %.2d:%.2d:%.2d",

                  tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);

           cout << szBuf <<endl;

          

           tm.wYear--;

           BOOL bDone = SetLocalTime(&tm);

           tm.wYear++;

           bDone = SetLocalTime(&tm);

           cout << endl;

           CopyCppFile();

           cout << endl;

           GetSysInfo();

           cout << endl;

    }

    编译执行,结果会显示当前的系统时间和相关的系统信息。

    由于API接口太多,这里就不一一举例说明了。我们就把它们理解为系统已经提供的这么一些函数,使用的时候在程序中调用就可以。如果参数及函数功能不了解的话,可以查阅MSDN相关资料即可。

  • 相关阅读:
    461. Hamming Distance
    342. Power of Four
    326. Power of Three
    368. Largest Divisible Subset java solutions
    95. Unique Binary Search Trees II java solutions
    303. Range Sum Query
    160. Intersection of Two Linked Lists java solutions
    88. Merge Sorted Array java solutions
    67. Add Binary java solutions
    14. Longest Common Prefix java solutions
  • 原文地址:https://www.cnblogs.com/kalo1111/p/2933561.html
Copyright © 2020-2023  润新知