自定义窗口

来源:互联网 发布:蒋南翔 知乎 编辑:程序博客网 时间:2024/04/29 05:12

最近在弄一个测试程序,希望可以创建一个自定义的窗口来画图,由于在console工程中,所以想自己创建一个窗口,在路上........

 

http://hi.baidu.com/xiuyuan132/blog/item/12bb3826c9e6653f8644f90a.html

该函数用来创建一个窗体

认识 CreateWindow 函数:


CreateWindow(  lpClassName: PChar;     {窗口类的名字}  lpWindowName: PChar;    {窗口标题}  dwStyle: DWORD;         {窗口样式, 参加下表}  X,Y: Integer;           {位置; 默认的X,Y可以指定为: Integer(CW_USEDEFAULT)}  nWidth,nHeight: Integer;{大小; 默认的宽度、高度可以指定为: Integer(CW_USEDEFAULT)}}  hWndParent: HWND;       {父窗口句柄}  hMenu: HMENU;           {主菜单句柄}  hInstance: HINST;       {模块实例句柄, 也就是当前 exe 的句柄}  lpParam: Pointer        {附加参数, 创建多文档界面时才用到, 一般设为 nil}): HWND;                  {返回所创建的窗口的句柄}//dwStyle 窗口样式参数可选值:WS_OVERLAPPED       = 0;                {重叠式窗口, 应带标题栏和边框}WS_POPUP            = DWORD($80000000); {弹出式窗口, 不能与 WS_CHILD 一起使用}WS_CHILD            = $40000000;        {子窗口, 不能与 WS_POPUP 一起使用}WS_MINIMIZE         = $20000000;        {最小化窗口}WS_VISIBLE          = $10000000;        {初始时可见}WS_DISABLED         = $8000000;         {禁止输入}WS_CLIPSIBLINGS     = $4000000;         {裁剪子窗口, 也就是子窗口重绘不影响重叠的其他子窗口, 应与 WS_CHILD 一起使用}WS_CLIPCHILDREN     = $2000000;         {在父窗口中绘图时绕开子窗口区域, 创建父窗口是使用}WS_MAXIMIZE         = $1000000;         {最大化窗口}WS_CAPTION          = $C00000;          {有标题栏}WS_BORDER           = $800000;          {有细线边框}WS_DLGFRAME         = $400000;          {对话框窗口}WS_VSCROLL          = $200000;          {有垂直滚动条}WS_HSCROLL          = $100000;          {有水平滚动条}WS_SYSMENU          = $80000;           {带系统标题栏, 须同时指定 WS_CAPTION}WS_THICKFRAME       = $40000;           {带宽边框, 宽边框用于改变窗口大小}WS_GROUP            = $20000;           {能用方向键转移焦点}WS_TABSTOP          = $10000;           {能用 TAB 转移焦点}WS_MINIMIZEBOX      = $20000;           {有最小化按钮}WS_MAXIMIZEBOX      = $10000;           {有最大化按钮}WS_TILED            = WS_OVERLAPPED;WS_ICONIC           = WS_MINIMIZE;WS_SIZEBOX          = WS_THICKFRAME;WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX);WS_TILEDWINDOW      = WS_OVERLAPPEDWINDOW;WS_POPUPWINDOW      = (WS_POPUP or WS_BORDER or WS_SYSMENU);WS_CHILDWINDOW      = (WS_CHILD);//另外还有一些扩展样式:WS_EX_DLGMODALFRAME    = 1;      {指定双边界窗口; 藉此指定 WS_CAPTION 创建标题栏}WS_EX_NOPARENTNOTIFY   = 4;      {在窗口创建或取消时不向父窗口发送 WM_PARENTNOTIFY 消息}WS_EX_TOPMOST          = 8;      {在所有非最顶层窗口的上面}WS_EX_ACCEPTFILES      = $10;    {可接受拖放文件}WS_EX_TRANSPARENT      = $20;    {透明样式, 在同属窗口已重画时该窗口才可重画}WS_EX_MDICHILD         = $40;    {创建一个 MDI 子窗口}WS_EX_TOOLWINDOW       = $80;    {工具窗口}WS_EX_WINDOWEDGE       = $100;   {带立体的边框}WS_EX_CLIENTEDGE       = $200;   {带阴影的边界}WS_EX_CONTEXTHELP      = $400;   {标题包含一个问号标志, 不能与 WS_MAXIMIZEBOX 和 WS_MINIMIZEBOX 同时使用}WS_EX_RIGHT            = $1000;  {窗口具有右对齐属性}WS_EX_LEFT             = 0;      {窗口具有左对齐属性, WS_EX_LEFT 是缺省设置}WS_EX_RTLREADING       = $2000;  {窗口文本从右到左}WS_EX_LTRREADING       = 0;      {窗口文本从左到右, WS_EX_LTRREADING 是缺省设置}WS_EX_LEFTSCROLLBAR    = $4000;  {垂直滚动条在左边界, 只用于特殊语言环境}WS_EX_RIGHTSCROLLBAR   = 0;      {垂直滚动条在右边界, WS_EX_RIGHTSCROLLBAR 是缺省设置}WS_EX_CONTROLPARENT    = $10000; {允许用户使用 Tab 键在窗口的子窗口间搜索}WS_EX_STATICEDGE       = $20000; {窗口不可用时创建一个三维边界}WS_EX_APPWINDOW        = $40000; {当窗口可见时, 将一个顶层窗口放置到任务条上}WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE or WS_EX_CLIENTEDGE); {立体边框并带阴影}WS_EX_PALETTEWINDOW    = (WS_EX_WINDOWEDGE or WS_EX_TOOLWINDOW or WS_EX_TOPMOST); {立体边框、工具条窗口样式、在顶层}WS_EX_LAYERED          = $00080000; {分层或透明窗口, 该样式可使用混合特效}WS_EX_NOINHERITLAYOUT  = $00100000; {子窗口不继承父窗口的布局}WS_EX_LAYOUTRTL        = $00400000; {从右到左的布局}WS_EX_COMPOSITED       = $02000000; {用双缓冲从下到上绘制窗口的所有子孙}WS_EX_NOACTIVATE       = $08000000; {处于顶层但不激活}

分析:

首先要用 CreateWindow 创建窗口, 才能用 ShowWindow 显示窗口; 因为 ShowWindow 需要 CreateWindow 返回的句柄.

在 CreateWindow 的参数中, 位置与大小与窗口标题无须多说;
父窗口与菜单, 暂时都不需要, 先可置为 0;
程序实例的句柄, Delphi 已经为我们准备好了: HInstance; (参见原来的说明)
窗口样式在前面的例子中我们使用了: WS_OVERLAPPEDWINDOW, 它代表几种特点的组合, 表示了常规窗口.

CreateWindow 还有一个重要参数(第一个参数 lpClassName): 窗口类的名字.
Windows 要求我们要登记并注册一个窗口类以后, 才可以用 CreateWindow 建立窗口!

http://blog.csdn.net/OneOnce/archive/2010/03/05/5349719.aspx

// 包含头文件windows.h
#include <windows.h>
#include "tchar.h"

// 预先声明Message Handler,可以叫做任何名字,这里是MyWindowProcedure
LRESULT CALLBACK MyWindowProcedure(HWND, UINT, WPARAM, LPARAM);

// 以下是所有Windows程序都需要的WinMain函数
// WinMain主要用来实现三个功能:
// 1. 注册Window Class;
// 2. 在内存中创建Window并初始化Window的属性;
// 3. 创建一个Message Loop来检查Message Queue中有没有该Window的Message。

//nCmdShow:指明窗口如何显示
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)
{
 wchar_t *szAppName = _T("WinHello"); // 定义一个字符串
 HWND hwnd; // 定义一个Window Handle变量
 MSG msg; // 定义一个Message结构的变量,用来储存Message的信息

 WNDCLASS wc; // 定义一个Window Class数据结构,用来储存Window Class的属性

 //下面这段代码用来定义Window的属性,例如Message Handler的地址、窗口背景、光标和图标等
 wc.style=CS_HREDRAW|CS_VREDRAW; // 设置style: 当窗口改变大小时就重新绘制窗口
 wc.lpfnWndProc=(WNDPROC)MyWindowProcedure; // 设定Window Procedure
 wc.cbClsExtra=0; // 用来储存Class Structure后的额外的数据,这里不需要
 wc.cbWndExtra=0; // 用来储存Window Instance后的额外的数据,这里不需要
 wc.hInstance=hInstance; // Window Procedure所在的Instance
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); // class的图标
 wc.hCursor=LoadCursor(NULL,IDC_ARROW); // class的光标
 wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); // 背景刷
 wc.lpszMenuName=NULL; // 菜单资源的名字,这里没有
 wc.lpszClassName=szAppName; // 应用程序的名字

 // 注册Window,通过调用API函数RegisterClass来实现
 // 注册Window Class的一个目的就是将Window和Window Procedure关联起来
 RegisterClass(&wc);

 // 注册Window Class后,WinMain就调用CreateWindow函数来创建应用程序的Window
 hwnd = CreateWindow(szAppName, // 已注册的Class名字
      L"Hello, World – Windows_98 Style", // Window名字(标题)
      WS_OVERLAPPEDWINDOW, // Window风格
      CW_USEDEFAULT, // Window起点的X坐标
      CW_USEDEFAULT, // Window起点的Y坐标
      CW_USEDEFAULT, // Window的宽度
      CW_USEDEFAULT, // Window的高度
      HWND_DESKTOP, // 父窗口的handle
      NULL, // 菜单的handle
      hInstance, // 应用程序instance的handle
      NULL // window-creation数据的指针
      );

 // 以下两条语句用来显示Window
 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);

 // 用while循环语句来检索并发送Messages
 // 从Message Queue中检索Message,并将它放到变量msg中。
 // 当收到"WM_QUIT"这个Message时,GetMessage函数就返回0,循环结束。而且WinMain函数也结束,程序终止。
 while(GetMessage(&msg, NULL, 0, 0))
 {
  //函数功能:该函数将虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。
  TranslateMessage(&msg); // 将Virtual-Key Messages转化为Character Messages

  //该函数调度一个消息给窗口程序。通常调度从GetMessage取得的消息。
  DispatchMessage(&msg); // 将Message发送到Window Procedure
 }

 return (int)msg.wParam;
}

/* 操作系统向应用程序发送一系列消息,如左键按下和左键抬起,应用程序将通过GetMessage等方法最终将消息提交到窗口过程 */
// MyWindowProcedure函数处理WM_PAINT和WM_DESTROY这两个Message,然后必须调用DefWindowProc去处理其他Message
LRESULT CALLBACK MyWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 PAINTSTRUCT ps; // 定义一个PAINTSTRUCT结构的变量,用来储存绘制Window的Client Area的信息
 HDC hdc; // 定义一个HDC变量
 LPCTSTR text=L"Welcome to windows!"; // 定义一个LPCTSTR类型的字符串指针

 // 用switch语句来处理WM_PAINT和WM_DESTROY这两个Message
 switch(message)
 {
 case WM_PAINT:
  // 下面5条语句是用来在屏幕上输出文字的,我们在后面的章节会详细讨论这个问题的,这里就不多说了

  /*
    BeginPaint函数准备指定的窗口来重绘并将绘画相关的信息放到一个PAINTSTRUCT结构中。
    HDC BeginPaint(HWND hwnd, // 窗口的HANDLE
              LPPAINTSTRUCT lpPaint // 绘画信息
             );
  */
  hdc = BeginPaint(hwnd, &ps);
  RECT rect;
  GetClientRect(hwnd, &rect);
  TextOut(hdc, (rect.right-rect.left)/2, (rect.bottom-rect.top)/2, text, lstrlen(text));//该函数用当前选择字符、背景颜色和正文颜色将一个字符串写到指定位置。
  EndPaint(hwnd, &ps);

  return 0;

  // 处理退出消息
 case WM_DESTROY:
  /*
     函数功能:该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息。
     函数原型:VOID PostQuitMessage(int nExitCode);
     参数: pExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数
  */
  PostQuitMessage(0);

  return 0;
 }

 // 调用默认的Window Procedure,使所有Message都可以被处理
 return DefWindowProc(hwnd, message, wParam, lParam);
}

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/OneOnce/archive/2010/03/05/5349719.aspx

 

4.  WinMain函数的定义

WinMainWindows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain函数结束或返回时,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
);
WinMain函数接收4个参数,这些参数都是在系统调用WinMain函数时,传递给应用程序的。
第一个参数hInstance表示该程序当前运行的实例的句柄,这是一个数值。
当程序在Windows下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例,才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。
 
第二个参数hPrevInstance表示当前实例的前一个实例的句柄。
在Win32环境下,这个参数总是NULL,即在Win32环境下,这个参数不再起作用。
 
第三个参数lpCmdLine是一个以空终止的字符串,指定传递给应用程序的命令行参数。
例如:一个d:/test.txt文件,当用鼠标双击它时将启动记事本(notepad.exe),此时系统会将d:/test.txt作为命令行参数传递给记事本程序的WinMain函数,记事本程序在得到这个文件的全路径名后,就在窗口中显示该文件的内容。要在VC++开发环境中向应用程序传递参数,可以单击菜单Project --> Settings,选择“Debug选项卡,在“Program arguments”编辑框中输入你想传递给应用程序的参数。
 
第四个参数nCmdShow指定程序的窗口应该如何显示,
例如最大化、最小化、隐藏等。这个参数的值由该程序的调用者所指定,应用程序通常不需要去理会这个参数的值。
 
关于WinMain函数前的修饰符WINAPI。者可以利用goto definition功能查看WINAPI的定义,可以看到WINAPI其实就是__stdcall。

 

5.  窗口的创建

一个完整的窗口具有许多特征,包括光标(鼠标进入该窗口时的形状)、图标、背景色等。在创建一个窗口前,也必须对该类型的窗口进行设计,指定窗口的特征。窗口的特征就是由WNDCLASS结构体来定义的。WNDCLASS结构体的定义如下
typedef struct _WNDCLASS {
     UINT
           style
;
     WNDPROC
       lpfnWndProc
;
     int
           cbClsExtra
;
     int
           cbWndExtra
;
     HANDLE
        hInstance
;
    HICON
          hIcon
;
    HCURSOR
        hCursor
;
    HBRUSH
         hbrBackground
;
    LPCTSTR
        lpszMenuName
;
    LPCTSTR
        lpszClassName
;
} WNDCLASS;

第一个成员变量style指定这一类型窗口的样式,常用的样式如下:
CS_HREDRAW --当窗口水平方向上的宽度发生变化时,将重新绘制整个窗口。
CS_VREDRAW --当窗口垂直方向上的高度发生变化时,将重新绘制整个窗口。
CS_NOCLOSE --禁用系统菜单的Close命令,这将导致窗口没有关闭按钮。
CS_DBLCLKS --当用户在窗口中双击鼠标时,向窗口过程发送鼠标双击消息。
 

[知识点] Windows.h中,以CS_开头的类样式(Class Style)标识符被定义为16位的常量,这些常量都只有某1位为1。在VC++开发环境中,用goto definition,可以看到CS_VREDRAW=0x0001CS_HREDRAW=0x0002CS_DBLCLKS =0x0008CS_NOCLOSE=0x0200,可将这些16进制数转换为2进制数,就发现它们都只有1位为1,并且为1的位各不相同。用这种方式定义的标识符称为“位标志”,可以用位运算操作符来组合使用这些样式。

例如,要让窗口在水平和垂直尺寸发生变化时发生重绘,可以使用位或(|)style=CS_HREDRAW | CS_VREDRAW

例如,要去掉先前的style变量所具有的CS_VREDRAW样式,可以使用取反(~符进行操作,再和这个变量进行与(&)操作即可实现。如style=style & ~ CS_VREDRAW

 

 

 

 

第二个成员变量lpfnWndProc是一个函数指针,指向窗口过程函数,窗口过程函数是一个回调函数,一个Windows程序可以包含多个窗口过程函数,一个窗口过程总是与某一个特定的窗口类相关联(通过WNDCLASS结构体中的lpfnWndProc成员变量指定),基于该窗口过程。

 

lpfnWndProc成员变量的类型是WNDPROC,我们在VC++开发环境中使用goto definition功能,可以看到WNDPROC的定义:
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

 

在这里又出现了两个新的数据类型LRESULT和CALLBACK,再次使用goto definition,可以看到它们实际上是long和__stdcall。
 
[知识点]  在函数调用过程中,会使用栈。__stdcall__cdecl是两种不同的函数调用约定,定义了函数参数入栈的顺序,由调用函数还是被调用函数将参数弹出栈,以及产生函数修饰名的方法。Win32API函数都遵循__stdcall调用约定。在VC++开发环境中,默认的编译选项是__cdecl,对于那些需要__stdcall调用约定的函数,在声明时必须显式地加上__stdcall。在Windows程序中,回调函数必须遵循__stdcall调用约定,所以我们在声明回调函数时要使用CALLBACK。使用CALLBACK而不是__stdcall的原因是为了告诉我们这是一个回调函数。
 
 
第三个成员变量cbClsExtra:Windows为系统中的每一个窗口类管理一个WNDCLASS结构。在应用程序注册一个窗口类时,它可以让Windows系统为WNDCLASS结构分配和追加一定字节数的附加内存空间,这部分内存空间称为类附加内存,由属于这种窗口类的所有窗口所共享,类附加内存空间用于存储类的附加信息。Windows系统把这部分内存初始化为0。一般我们将这个参数设置为0。
 
第四个成员变量cbWndExtra:Windows系统为每一个窗口管理一个内部数据结构,在注册一个窗口类时,应用程序能够指定一定字节数的附加内存空间,称为窗口附加内存。在创建这类窗口时,Windows系统就为窗口的结构分配和追加指定数目的窗口附加内存空间,应用程序可用这部分内存存储窗口特有的数据。Windows系统把这部分内存初始化为0。如果应用程序用WNDCLASS结构注册对话框(用资源文件中的CLASS伪指令创建),必须给DLGWINDOWEXTRA设置这个成员。一般我们将这个参数设置为0。
 
第五个成员变量hInstance指定包含窗口过程的程序的实例句柄。
 
第六个成员变量hIcon指定窗口类的图标句柄。这个成员变量必须是一个图标资源的句柄,如果这个成员为NULL,那么系统将提供一个默认的图标。
在为hIcon变量赋值时,可以调用LoadIcon函数来加载一个图标资源,返回系统分配给该图标的句柄。该函数的原型声明如下所示:
HICON LoadIcon( HINSTANCE hInstance, LPCTSTR lpIconName)
LoadIcon函数不仅可以加载Windows系统提供的标准图标到内存中,还可以加载由用户自己制作的图标资源到内存中,并返回系统分配给该图标的句柄。但要注意的是,如果加载的是系统的标准图标,那么第一个参数必须为NULL
LoadIcon的第二个参数是LPCTSTR类型,利用goto definition命令将会发现它实际被定义成CONST CHAR*,即指向字符常量的指针,而图标的ID是一个整数。对于这种情况我们需要用MAKEINTRESOURCE宏把资源ID标识符转换为需要的LPCTSTR类型。
 
[知识点]  VC++中,对于自定义的菜单、图标、光标、对话框等资源,都保存在资源脚本*.rc文件中。资源是通过标识符(ID)来标识的,同一个ID可以标识多个不同的资源。资源的ID实质上是一个整数,在“resource.h”中定义为一个宏。在为资源指定ID时,应该养成一个良好的习惯,即在“ID”后附加特定资源英文名称的首字母,例如,菜单资源为IDM_XXXM表示Menu),图标资源为IDI_XXXI表示Icon),按钮资源为IDB_ XXXB表示Button)。
 
第七个成员变量hCursor指定窗口类的光标句柄。这个成员变量必须是一个光标资源的句柄,如果这个成员为NULL,那么无论何时鼠标进入到应用程序窗口中,应用程序都必须明确地设置光标的形状。
在为hCursor变量赋值时,可以调用LoadCursor函数来加载一个光标资源,返回系统分配给该光标的句柄。该函数的原型声明如下所示:
HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);
LoadCursor函数除了加载的是光标外,其使用方法与LoadIcon函数一样。
 
第八个成员变量hbrBackground指定窗口类的背景画刷句柄。当窗口发生重绘时,系统使用这里指定的画刷来擦除窗口的背景。既可以为hbrBackground成员指定一个画刷的句柄,也可以为其指定一个标准的系统颜色值。
可以调用GetStockObject函数来得到系统的标准画刷。GetStockObject函数的原型声明如下所示:
HGDIOBJ GetStockObject( int fnObject);
参数fnObject指定要获取的对象的类型。GetStockObject函数不仅可以用于获取画刷的句柄,还可以用于获取画笔、字体和调色板的句柄。由于GetStockObject函数可以返回多种资源对象的句柄,在实际调用该函数前无法确定它返回哪一种资源对象的句柄,因此它的返回值的类型定义为HGDIOBJ,在实际使用时,需要进行类型转换。例如,我们要为hbrBackground成员指定一个黑色画刷的句柄,可以调用如下:
wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
当窗口发生重绘时,系统会使用这里指定的黑色画刷擦除窗口的背景。
 
第九个成员变量lpszMenuName是一个以空终止的字符串,指定菜单资源的名字。如果你使用菜单资源的ID号,那么需要用MAKEINTRESOURCE宏来进行转换。如果将lpszMenuName成员设置为NULL,那么基于这个窗口类创建的窗口将没有默认的菜单。要注意,菜单并不是一个窗口,很多初学者都误以为菜单是一个窗口。
 
第十个成员变量lpszClassName是一个以空终止的字符串,指定窗口类的名字。设计了一种新类型的窗口,要为该类型的窗口取个名字。这里我们将这种类型窗口的命名为“HelloWindow”,后面将看到如何使用这个名称。
 
 
6.  窗口的创建
设计完窗口类(WNDCLASS)后,需要调用RegisterClass函数对其进行注册,注册成功后,才可以创建该类型的窗口。注册函数的原型声明如下:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
该函数只有一个参数,即上一步骤中所设计的窗口类对象的指针。
设计好窗口类并且将其成功注册之后,就可以用CreateWindow函数产生这种类型的窗口了。CreateWindow函数的原型声明如下:
HWND CreateWindow(
     LPCTSTR lpClassName,    // pointer to registered class name
     LPCTSTR lpWindowName,   // pointer to window name
     DWORD dwStyle,          // window style
     int x,                   // horizontal position of window
     int y,                   // vertical position of window
     int nWidth,              // window width
     int nHeight,             // window height
     HWND hWndParent,        // handle to parent or owner window
     HMENU hMenu,             // handle to menu or child-window identifier
     HANDLE hInstance,       // handle to application instance
     LPVOID lpParam          // pointer to window-creation data
);
lpClassName指定窗口类的名称,即我们在上一步骤设计一个窗口类中为WNDCLASS的lpszClassName成员指定的名称,在这里应该设置为“HelloWindow”,表示要产生“HelloWindow”这一类型的窗口。
参数lpWindowName指定窗口的名字。如果窗口样式指定了标题栏,那么这里指定的窗口名字将显示在标题栏上。
参数dwStyle指定创建的窗口的样式。要注意区分WNDCLASS中的style成员与CreateWindow函数的dwStyle参数,前者是指定窗口类的样式,基于该窗口类创建的窗口都具有这些样式,后者是指定某个具体的窗口的样式。
在这里,我们可以给创建的窗口指定WS_OVERLAPPEDWINDOW这一类型,该类型的定义为:
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED  |  WS_CAPTION    |    
                                                                     WS_SYSMENU   |   WS_THICKFRAME  |
                                                                     WS_MINIMIZEBOX     |    WS_MAXIMIZEBOX)
可以看到,WS_OVERLAPPEDWINDOW是多种窗口类型的组合。下面是这几种常用窗口类型的说明。
 WS_OVERLAPPED:产生一个层叠的窗口,一个层叠的窗口有一个标题栏和一个边框。
WS_CAPTION:创建一个有标题栏的窗口。
WS_SYSMENU:创建一个在标题栏上带有系统菜单的窗口,要和WS_CAPTION类型一起使用。
WS_THICKFRAME:创建一个具有可调边框的窗口。
WS_MINIMIZEBOX:创建一个具有最小化按钮的窗口,必须同时设定WS_ SYSMENU类型。
WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口,必须同时设定WS_ SYSMENU类型。
使用WS_OVERLAPPEDWINDOW类型的窗口如图1.1所示。
CreateWindow函数的参数xy,nWidth,nHeight分别指定窗口左上角的xy坐标,窗口的宽度,高度。如果参数x被设为CW_USEDEFAULT,那么系统为窗口选择默认的左上角坐标并忽略y参数。如果参数nWidth被设为CW_USEDEFAULT,那么系统为窗口选择默认的宽度和高度,参数nHeight被忽略。
参数hWndParent指定被创建窗口的父窗口句柄。窗口之间可以有父子关系,子窗口必须具有WS_CHILD样式。对父窗口的操作同时也会影响到子窗口,表1.1列出了对父窗口的操作如何影响子窗口。
表1.1  对父窗口的操作对子窗口的影响
  
  
销毁
在父窗口被销毁之前销毁
隐藏
在父窗口被隐藏之前隐藏,子窗口只有在父窗口可见时可见
移动
跟随父窗口客户区一起移动
显示
在父窗口显示之后显示
参数hMenu指定窗口菜单的句柄。
参数hInstance指定窗口所属的应用程序实例的句柄。
参数lpParam:作为WM_CREATE消息的附加参数lParam传入的数据指针。在创建多文档界面的客户窗口时,lpParam必须指向CLIENTCREATESTRUCT结构体。多数窗口将这个参数设置为NULL。
如果窗口创建成功,CreateWindow函数将返回系统为该窗口分配的句柄,否则,返回NULL。注意,在创建窗口之前应先定义一个窗口句柄变量来接收创建窗口之后返回的句柄值。
7.显示及更新窗口
(1)显示窗口
窗口创建之后,我们要让它显示出来。调用函数ShowWindow来显示窗口,该函数的原型声明如下所示:
BOOL ShowWindow(
  HWND hWnd,     // handle to window
  int nCmdShow   // show state
);
ShowWindow函数有两个参数,第一个参数hWnd就是在上一步骤中成功创建窗口后返回的那个窗口句柄;第二个参数nCmdShow指定了窗口显示的状态,常用的有以下几种。
SW_HIDE:隐藏窗口并激活其他窗口。
SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。
SW_SHOWMAXIMIZED:激活窗口并将其最大化显示。
SW_SHOWMINIMIZED:激活窗口并将其最小化显示。
SW_SHOWNORMAL:激活并显示窗口。如果窗口是最小化或最大化的状态,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。
(2)更新窗口
在调用ShowWindow函数之后,我们紧接着调用UpdateWindow来刷新窗口,就好像我们买了新房子,需要装修一下。UpdateWindow函数的原型声明如下:
BOOL UpdateWindow(
  HWND hWnd   // handle to window
);
其参数hWnd指的是创建成功后的窗口的句柄。UpdateWindow函数通过发送一个WM_PAINT消息来刷新窗口,UpdateWindow将WM_PAINT消息直接发送给了窗口过程函数进行处理,而没有放到我们前面所说的消息队列里,注意这一点。到此,一个窗口就算创建完成了。

原创粉丝点击