首页 > 代码库 > Windows API 编程学习记录<三>

Windows API 编程学习记录<三>

恩,开始写API编程的第三节,其实马上要考试了,但是不把这节写完,心里总感觉不舒服啊。写完赶紧去复习啊
      在前两节中,我们介绍了Windows API 编程的一些基本概念和一个最基本API函数 MessageBox的使用,在这节中,我们就来正式编写一个Windows的窗口程序。

在具体编写代码之前,我们必须先要了解一下API 编写窗口程序具体的三个基本步骤:

            1. 注册窗口类;

            2.创建窗口;

            3.显示窗口;


恩,我们
现在开始一个一个介绍。
1. 在Windows 编程中,如果你要显示一个窗口,你必须先要向系统注册一个窗口类(WNDCLASSEX),不过在注册这个窗口类之前,还有一个小工作让你去完成,就是这个窗口类需要你自己来实现,不过Windows已经在系统中定义了这个类,这个窗口类的本质就是一个结构体,这个结构体里面包含了描述你这个窗口需要的一些数据结构,比如你这个窗口的背景色,图标样式等等,只需要你去向这类(结构体)里面填写你需要的样式就可以了。下面就是窗口类具体的定义及结构体中每项所代表的意义。

typedef struct WNDCLASSEX {
UINT cbSize;          //WNDCLASSEX 的大小。我们可以用sizeof(WNDCLASSEX)来获得准确的值。
UINT style;           //从这个窗口类派生的窗口具有的风格。您可以用“or”操作符来把几个风格或到一起。 (关于这个参数可以自己上网查询,最好自己试着用用或者查询本节附录) 
WNDPROC lpfnWndProc;  //窗口处理函数的指针。
int cbClsExtra;       //指定紧跟在窗口类结构后的附加字节数。
int cbWndExtra;       //指定紧跟在窗口实例的附加字节数。
HINSTANCE hInstance;  //本模块的实例句柄。
HICON hIcon;          //图标的句柄。
HCURSOR hCursor;      //光标的句柄。
HBRUSH hbrBackground; //背景画刷的句柄。
LPCTSTR lpszMenuName; //指向菜单的指针。
LPCTSTR lpszClassName;//指向类名称的指针。
HICON hIconSm;        //和窗口类关联的小图标。如果该值为NULL。则把hIcon中的图标转换成大小合适的小图标。
} WNDCLASSEX, *PWNDCLASSEX;

将这个窗口类实现后,就可以用RegisterClassEx函数向系统注册窗口类了,其中函数参数是指向WNDCLASSEX结构体的一个指针。

ATOM RegisterClassEx(CONST WNDCLASSEX *Ipwcx);

注册窗口类其实可以这样理解,就是你去汽车店买了一个各方面都符合你需要的新车(类似向WNDCLASSEX结构体填充数据),但是你在使用这个汽车之前必须要向国家有关部门申请一个牌照,这个过程其实就是类似RegisterClassEx函数。

2.介绍完了注册窗口类,让我们来看看如何创建窗口,其实创建窗口就是使用Createwindow函数来创建,这个函数确定了窗口显示的风格,另外在创建完窗口后,会返回窗口的句柄,关于句柄,我们在第二节中有过描述,现在就再来讲下吧,其实句柄就是系统用来标示系统中每一个资源的,就像我们这个窗口,系统就是通过它的句柄来操作窗口的,在第三步显示窗口时,就用到了窗口句柄;

HWND CreateWindow(
LPCTSTR lpClassName,   //窗口类的名字。
LPCTSTR lpWindowName,  //指向一个指定窗口名的空结束的字符串指针。其实就是窗口的名字。
DWORD dwStyle,        //指定创建窗口的风格。该参数可以是窗口风格的组合。 (关于这个参数可以自己上网,最好自己试着用用或者查询本节附录)
int x,                 //窗口的横坐标。
int y,                 //窗口的竖坐标。
int nWidth,             //窗口的宽度。
int nHeight,            //窗口的高度。
HWND hWndParent,       //指向被创建窗口的父窗口或所有者窗口的句柄。
HMENU hMenu,            //菜单句柄,或依据窗口风格指明一个子窗口标识。
HANDLE hlnstance,      //与窗口相关联的模块事例的句柄。
LPVOID lpParam         //指向一个值的指针,该值传递给窗口 WM_CREATE消息
);

  3.最后就剩下显示窗口了。显示窗口需要用到两个函数ShowWindow(),和UpdateWindow();关于这两个函数的作用,ShowWindow指定了窗口显示的状态,而UpdateWindow()函数的作用是,如果窗口更新的区域不为空,则函数通过发送一个WM_PAINT消息来更新指定窗口的客户区。函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。这两个函数的原型如下:

BOOL ShowWindow(      
            HWND hWnd,//当前的窗口句柄
              int nCmdShow //可见状态可见状态的取值可查询本节附录
            );
BOOL UpdateWindow(
           HWND hWnd // 窗口的句柄
            );

现在我们就把我们的思路整合成一个可以显示窗口的代码,我们在阅读这个代码中可以验证下创建窗口是不是需要我们之前所说的那三步,注册窗口类,创建窗口,显示窗口。 在这个代码中包含了窗口对消息的循环处理,在这节中我们先避开这个问题,我们先理解窗口创建的流程,下节我们会具体讲什么是消息,如何处理消息。在这里还是大致提下消息吧,其实Windows程序设计都是基于消息机制的,我们可以这样简单的理解一下什么是消息,当我们在窗口上点击关闭按钮时,为什么窗口就会消失呢,其实就是我们在点击关闭按钮时,会向窗口发送一个关闭的消息,窗口接收到这个消息以后,就会去执行相应的操作。恩,下面就是显示窗口的代码。

#include <windows.h>

//回调函数,这个函数里的消息及消息处理我们下节再讲,这节大家先理解窗口创建显示的流程
LRESULT WINAPI WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)            //处理消息过程
    {
    case WM_DESTROY:        //响应鼠标单击关闭按钮事件
        PostQuitMessage(0); //退出消息队列
        return 0;           //退出函数
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

//主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    char *cName = "CWindowName";  //窗口类的名字
     WNDCLASSEX wc;
    HWND hWnd;
    MSG Msg;

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//通过函数来设置一个白色的背景.
    wc.hCursor = NULL;         //不设置
    wc.hIcon = NULL;           //不设置
    wc.hIconSm = NULL;         //不设置
    wc.hInstance = hInstance;  //当前程序的句柄,hInstance是有系统给传递的
    wc.lpfnWndProc = WinProc;  //窗口处理过程的回调函数,有关回调函数,下节再讲
    wc.lpszClassName = cName;  //窗口类的名字。
    wc.lpszMenuName = NULL;    //目录名,不设置
    

    RegisterClassEx(&wc);//在系统中注册

    //创建窗口,注意返回值是一个句柄。
    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, cName, "我的窗口", WS_OVERLAPPEDWINDOW,
        200, 100, 600, 400, NULL, NULL, hInstance, NULL);  //创建窗口,窗口标题为"我的窗口"
    //创建窗口的容错处理
    if (hWnd == NULL)
    {          
        MessageBox(NULL, "There‘s an Error", "Error Title", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    //显示窗口
     ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);

    //下面是对消息的循环处理,关于消息及消息的处理我们下节在讲。
    while (GetMessage(&Msg, NULL, 0, 0))
    {
        TranslateMessage(&Msg); //翻译消息
         DispatchMessage(&Msg);  //分派消息
    }
    return Msg.message;
}

恩,这节就暂时讲到这里吧,其实楼主也只是一个在校的大二学生,在这里写Windows API 编程其实有两个出发点,第一是让自己加强对API 编程的理解,提高自己,第二点就是希望为那些学完C语言,又想去学点其他编程知识的同学们提供点参考,其实学完C语言之后可以学习很多种编程知识,API编程也只是一个小小的方向,大家可以看看自己到底对哪方面感兴趣,然后好好钻研钻研。

 

 

 

附录:

1. WNDCLASSEX结构体中style的取值意义:

CS_BYTEALIGNCLIENT: 在字节边界上(在x方向上)定位窗口的用户区域的位置

CS_BYTEALIGNWINDOW: 在字节边界上(在x方向上)定位窗口的位置

CS_CLASSDC: 该窗口类的所有窗口实例都共享一个窗口类DC

CS_DBLCLKS: 允许向窗口发送双击鼠标键的消息

CS_GLOBALCLASS: 当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个 hInstance 必须相同。

CS_HREDRAW: 当水平长度改变或移动窗口时,重画整个窗口

CS_NOCLOSE: 禁止系统菜单的关闭选项

CS_OWNDC: 给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。

CS_PARENTDC: 将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。

CS_SAVEBITS: 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。

CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口。

 

2. CreateWindow中dwStyle的取值意义:

WS_BORDER:创建一个带边框的窗口。

WS_CAPTION:创建一个有标题框的窗口(包括WS_BODER风格)。

WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。

WS_CHILDWINDOW:与WS_CHILD相同。

WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。

WS_CLIPSIBLINGS:排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。

WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。

WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。

WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。

WS_HSCROLL:创建一个有水平滚动条的窗口。

WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。

WS_MAXIMIZE:创建一个初始状态为最大化状态的窗口。

WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。

WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。

WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。

WS_POPUP:创建一个弹出式窗口。该风格不能与WS_CHILD风格同时使用。

WS_POPUPWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。

WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。

WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。

WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。

WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。

WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。

WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU, WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。

WS_VISIBLE:创建一个初始状态为可见的窗口。

WS_VSCROLL:创建一个有垂直滚动条的窗口。

 

3.ShowWindow中的nCmdShow取值意义:

SW_FORCEMINIMIZE:在WindowNT5.0中最小化窗口,即使拥有窗口的线程被挂起也会最小化。在从其他线程最小化窗口时才使用这个参数。

SW_HIDE:隐藏窗口并激活其他窗口。

SW_MAXIMIZE:最大化指定的窗口。

SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。

SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。

SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。

SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。

SW_SHOWMAXIMIZED:激活窗口并将其最大化。

SW_SHOWMINIMIZED:激活窗口并将其最小化。

SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。

SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。

SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。

SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。