• Win32编程


     

     

    Win32编程

    此资料为ITjob软件开发教程网提供,特此分享,互相学习!

    C/C++/VC/MFC技术交流群:95453496

    一、Win32编程基本概念

    1、消息驱动

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

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

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

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

     

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

     

     

    3、窗口元素

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

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

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

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

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

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

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

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

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

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

     

    4、编程术语

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

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

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

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

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

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

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

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

    nCmdShow:是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOWSW_HIDESW_SHOWMAXIMIZEDSW_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结构中主消息值的,主消息值在wMsgFilterMinwMsgFilterMax之外的消息将被过滤掉。如果这两个参数为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语句来将不同类型的消息分配到不同的处理程序中去。

    wParamlParam附加的消息参数。其含义随主消息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_SIZEWM_MINIMIZEWM_CREATEWM_MOVE等这样频频使用的消息就有几十条。为了减轻编程的负担,WindowsAPI提供了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[] = "当前时间是:20101231日 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相关资料即可。

     

    作业:

    1、使用VC创建典型的“Hello World!”工程,编译并对程序进行单步跟踪,进一步理解Win32程序框架,熟悉相关函数。

     

     

    2、创建一个Win32应用程序,其中包含一个主窗口和一个子窗口,要求子窗口可以关闭,子窗口关闭后在主窗口中点击鼠标右键重新打开子窗口。

     

    此资料为ITjob软件开发培训基地老师研发撰写的课程,如有转载请注明出处!

  • 相关阅读:
    2019-2020-2 20175227张雪莹《网络对抗技术》 Exp3 免杀原理与实践
    2019-2020-2 20175227张雪莹《网络对抗技术》 Exp2 后门原理与实践
    2019-2020-2 20175227张雪莹《网络对抗技术》 Exp1 PC平台逆向破解
    USCOSII
    office word excel等图标显示异常
    Mysql事务
    Mysql 主备配置
    查看mysql已有用户并删除
    在linux下面安装mysql 确认 配置文件路径 my.cnf
    yum提示Another app is currently holding the yum lock; waiting for it to exit...
  • 原文地址:https://www.cnblogs.com/qintangtao/p/2799222.html
Copyright © 2020-2023  润新知