鱼C论坛

 找回密码
 立即注册
查看: 3687|回复: 0

[学习笔记] win32编程(001)——初识窗口程序的创建

[复制链接]
发表于 2017-6-14 18:44:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
这两天出去浪了 ,就没更新,本来想了半天开头怎么写,算了,直接进入正题吧

窗口程序的创建步骤:
1 定义WinMain入口函数
2 定义并赋值窗口类的数据
3 注册窗口类  RegisterClass
4 创建窗口  CreateWindow
5 显示窗口
    ShowWindow/UpdateWindow
6 消息循环
    GetMessage
    TranslateMessage
    DisptachMessage
7 定义窗口处理函数 WindowProc


创建窗口的基本步骤就是上面7条,这七条基本要讲好几期,下面我会先发一个窗口创建的完整源代码,并附上相关注释,之后再一条条详细解释

  1. #include "stdafx.h"

  2. //自定义(窗口处理函数)处理消息
  3. LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
  4. {
  5.         switch (msgID)
  6.         {
  7.         case WM_DESTROY:
  8.                 PostQuitMessage(0);
  9.                 break;
  10.         default:
  11.                 return DefWindowProc(hWnd, msgID, wParam, lParam);
  12.         }
  13.         return 0;
  14. }

  15. //WinMain入口函数
  16. int WINAPI WinMain(HINSTANCE hInstance, //当前程序实例句柄
  17.                                 HINSTANCE hPrevInstance, //当前程序前一个实例句柄
  18.                                 PSTR szCmdLince, ,//命令行参数字符串
  19.                                 int iCmdShow)//窗口的显示方式
  20. {
  21.         //注册窗口类
  22.         WNDCLASS wc = { 0 };//定义并初始化窗口类的结构体数据
  23.         wc.cbClsExtra = 0;//窗口类附加数据buff的大小
  24.         wc.cbWndExtra = 0;//窗口附加数据buff的大小
  25.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//绘制窗口背景的画刷句柄
  26.         wc.hCursor = NULL;//鼠标的句柄
  27.         wc.hIcon = NULL;//窗口图标句柄
  28.         wc.hInstance = hInstance;//当前模块的实例句柄
  29.         wc.lpfnWndProc = WndProc;//窗口处理函数的名称
  30.         wc.lpszClassName = _T("fishc");//窗口类的名称
  31.         wc.lpszMenuName = NULL;//窗口菜单的资源ID字符串
  32.         wc.style = CS_HREDRAW | CS_VREDRAW;//窗口类的风格
  33.         RegisterClass(&wc);//将以上所有赋值全部写入操作系统
  34.         HWND hWnd = CreateWindow(_T("fishc"), _T("fishc"),WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hInstance,NULL);

  35.         //显示窗口
  36.         ShowWindow(hWnd,SW_SHOW);
  37.         UpdateWindow(hWnd);//刷新窗口

  38.         //消息循环
  39.         MSG nMsg= { 0 };
  40.         while (GetMessage(&nMsg, NULL, 0, 0))
  41.         {
  42.                 TranslateMessage(&nMsg);
  43.                 DispatchMessage(&nMsg);
  44.         }
  45.         return 0;
  46. }
复制代码


我们看到上面有很多我们不认识的英文,实际上都是给基本数据类型起的别名,下面附上常见的一些
  1. 大部分包含在basetsd.h,minwindef.h这两个头文件中

  2. typedef unsigned long ULONG;
  3. typedef unsigned short USHORT;
  4. typedef unsigned char UCHAR;

  5. #define CALLBACK    __stdcall
  6. #define WINAPI      __stdcall
  7. #define WINAPIV     __cdecl
  8. #define APIENTRY    WINAPI
  9. #define APIPRIVATE  __stdcall
  10. #define PASCAL      __stdcall

  11. typedef unsigned long       DWORD;
  12. typedef int                 BOOL;
  13. typedef unsigned char       BYTE;
  14. typedef unsigned short      WORD;
  15. typedef float               FLOAT;
  16. typedef int                 INT;
  17. typedef unsigned int        UINT;

  18. typedef UINT_PTR            WPARAM;
  19. typedef LONG_PTR            LPARAM;
  20. typedef LONG_PTR            LRESULT;
复制代码


1.窗口的注册

1.1窗口类
窗口类包含了窗口的各种参数信息的数据结构。每个窗口都具有窗口类,基于窗口类创建窗口。每个窗口类都具有一个名称,使用前必须注册到系统。

1.2窗口类的分类
1.2.1-系统窗口类
系统已经定义好的窗口类,不需要注册,直接使用窗口类即可,所有应用程序都可以直接使用。
例如按钮   - BUTTON窗口和编辑框 - EDIT窗口
  1. #include "stdafx.h"

  2. int APIENTRY WinMain(HINSTANCE hInstance,
  3.                      HINSTANCE hPrevInstance,
  4.                      LPSTR     lpCmdLine,
  5.                      int       nCmdShow)
  6. {
  7.         //不需要注册类
  8.         HWND hButton = CreateWindow( "EDIT", "OK",
  9.                                         WS_OVERLAPPEDWINDOW,
  10.                                         100, 100, 500, 500, NULL, NULL,
  11.                                         hInstance, NULL );
  12.         ShowWindow( hButton, SW_SHOW );
  13.         UpdateWindow( hButton );
  14.         MSG nMsg = { 0 };
  15.         while( GetMessage( &nMsg, NULL, 0, 0 ) )
  16.         {
  17.                 TranslateMessage( &nMsg );
  18.                 DispatchMessage( &nMsg );//将消息交给窗口处理函数
  19.         }
  20.         return 0;
  21. }
复制代码

没有消息处理函数的窗口关闭后,进程并不会结束,需要自行到任务管理器中结束

1.2.2-应用程序全局窗口类
由用户自己定义,当前应用程序所有模块都可以使用。
1.2.3-应用程序局部窗口类
由用户自己定义,当前应用程序中本模块可以使用

既然说到了win32,还有以后可能会说的mfc,就不能不提最好的老师,msdn帮助手册,关于msdn手册哪里找,怎么下,我就不在赘述,但是我会提供官方的在线版,具体msdn有什么用,就先从一个实例讲起
  1. #include<windows.h>

  2. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLince, int iCmdShow)
  3. {
  4.        MessageBox(NULL,TEXT("这是我在鱼C学习的第一个程序"),TEXT("打招呼"),MB_OK);
  5.        return 0;
  6. }
复制代码

这是小甲鱼课程中的代码,其中最关键的就是messagebox函数,这个函数有几个参数,参数具体是什么,有什么返回值,msdn中说的是非常详细了,在线地址

介绍完msdn,那么继续说窗口创建
一般应用程序窗口类的注册,常用函数是RegisterClass/RegisterClassEx,分别对应WNDCLASS/WNDCLASSEX两种结构体,EX只比普通多了两个参数,其他参数相同,所以以EX介绍为主RegisterClassEx函数
  1. ATOM WINAPI RegisterClassEx(
  2.   _In_ const WNDCLASSEX *lpwcx//窗口类的数据
  3. );注册成功后,返回一个数字标识typedef WORD                ATOM
复制代码


WNDCLASSEX函数
  1. typedef struct _WNDCLASSEX {
  2.     UINT       cbSize; //结构体的大小
  3.     UINT       style;  //窗口类的风格
  4.     WNDPROC    lpfnWndProc; //窗口处理函数
  5.     int        cbClsExtra; //窗口类附加数据buff的大小
  6.     int        cbWndExtra; //窗口附加数据buff的大小
  7.     HINSTANCE  hInstance; //当前模块的实例句柄
  8.     HICON      hIcon; //窗口图标句柄
  9.     HCURSOR    hCursor; //鼠标的句柄
  10.     HBRUSH     hbrBackground; //绘制窗口背景的画刷句柄
  11.     LPCTSTR    lpszMenuName; //窗口菜单的资源ID字符串
  12.     LPCTSTR    lpszClassName; //窗口类的名称
  13.     HICON      hIconSm; //窗口的小图标句柄
  14. } WNDCLASSEX, *PWNDCLASSEX;
复制代码


应用程序全局窗口类的注册,需要在窗口类的风格中增加 CS_GLOBALCLASS,例如:
  1. WNDCLASSEX wce = {0};
  2. wce.style = CS_GLOBALCLASS;
复制代码


应用程序局部窗口类
在注册窗口类时,不添加CS_GLOBALCLASS风格创建,创建的就是局部窗口类。

1.3窗口类的风格
  1. CS_GLOBALCLASS - 应用程序全局窗口类
  2. CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
  3. CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
  4. CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
  5. CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
  6. CS_DBLCLKS - 允许窗口接收鼠标左键双击
  7. CS_NOCLOSE - 窗口没有关闭按钮
复制代码

  1. #include "stdafx.h"
  2. HINSTANCE g_hInstance = 0;//全局句柄接收当前程序实例句柄
  3. void AppReg( )
  4. {
  5.         WNDCLASSEX wce = { 0 };
  6.         wce.cbSize = sizeof(wce);
  7.         wce.cbClsExtra = 0;
  8.         wce.cbWndExtra = 0;
  9.         wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  10.         wce.hCursor = NULL;
  11.         wce.hIcon = NULL;
  12.         wce.hIconSm = NULL;
  13.         wce.hInstance = g_hInstance;
  14.         wce.lpfnWndProc = DefWindowProc;
  15.         wce.lpszClassName = "Main";
  16.         wce.lpszMenuName = NULL;
  17.         wce.style = CS_HREDRAW | CS_VREDRAW;
  18.         RegisterClassEx( &wce );//将以上所有赋值全部写入操作系统
  19.         HWND hWnd = CreateWindow( "Main", "window",
  20.                                 WS_OVERLAPPEDWINDOW,
  21.                                 100, 100, 500, 500, NULL, NULL, g_hInstance,
  22.                                 NULL );
  23.         ShowWindow( hWnd, SW_SHOW );
  24.         UpdateWindow( hWnd );
  25.         MSG nMsg = { 0 };
  26.         while( GetMessage( &nMsg, NULL, 0, 0 ) )
  27.         {
  28.                 TranslateMessage( &nMsg );
  29.                 DispatchMessage( &nMsg );
  30.         }
  31. }
  32. int APIENTRY WinMain(HINSTANCE hInstance,
  33.                      HINSTANCE hPrevInstance,
  34.                      LPSTR     lpCmdLine,
  35.                      int       nCmdShow)
  36. {
  37.         g_hInstance = hInstance;//接收当前程序实例句柄
  38.         AppReg( );
  39.         return 0;
  40. }
复制代码


2.窗口的创建
2.1窗口类的查找过程
2.1.1系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。
2.1.2比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3。
2.1.3在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。
2.1.4使用找到的窗口类的信息,创建窗口返回。
2.1.5在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。

当窗口注册完毕并将数据写入系统后,就可以开始窗口的创建了,窗口注册函数CreateWindow/CreateWindowEx
CreateWindowEx函数
  1. HWND CreateWindowEx(
  2.         DWORD dwExStyle, //窗口的扩展风格
  3.         LPCTSTR lpClassName,  //已经注册的窗口类名称
  4.         LPCTSTR lpWindowName, //窗口标题栏的名字
  5.         DWORD dwStyle, //窗口的基本风格,[url=https://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx]Window Styles[/url]
  6.         int x, //窗口左上角水平坐标位置
  7.         int y, //窗口左上角垂直坐标位置
  8.         int nWidth, //窗口的宽度
  9.         int nHeight,//窗口的高度
  10.         HWND hWndParent,//窗口的父窗口句柄
  11.         HMENU hMenu,//窗口菜单句柄
  12.         HINSTANCE hInstance, //应用程序实例句柄
  13.         LPVOID lpParam //窗口创建时附加参数   
  14. ); 创建成功返回窗口句柄
复制代码


2.2创建子窗口
如果你上面每句话都细心琢磨的话,会发现好多参数都有前或者父这种说法,所以在一个窗口下还能创建一个子窗口,要点主要有两个
2.2.1创建时要设置父窗口句柄
2.2.2创建风格要增加 WS_CHILD|WS_VISIBLE
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. HINSTANCE g_hInstance = 0;//接收当前程序实例句柄
  4. //自定义(窗口处理函数) 处理消息
  5. LRESULT CALLBACK WndProc( HWND hWnd, UINT msgID,
  6.                                                 WPARAM wParam, LPARAM lParam )
  7. {
  8.         switch( msgID )
  9.         {
  10.         case WM_DESTROY:
  11.                 PostQuitMessage( 0 );//使GetMessage函数返回0???
  12.                 break;
  13.         }
  14.         return DefWindowProc( hWnd, msgID, wParam, lParam );
  15. }
  16. //注册窗口类
  17. void Register( LPCTSTR lpClassName, WNDPROC wndproc )
  18. {
  19.         WNDCLASSEX wce = { 0 };
  20.         wce.cbSize = sizeof( wce );
  21.         wce.cbClsExtra = 0;
  22.         wce.cbWndExtra = 0;
  23.         wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  24.         wce.hCursor = NULL;
  25.         wce.hIcon = NULL;
  26.         wce.hIconSm = NULL;
  27.         wce.hInstance = g_hInstance;
  28.         wce.lpfnWndProc = wndproc;/***************/
  29.         wce.lpszClassName = lpClassName;
  30.         wce.lpszMenuName = NULL;
  31.         wce.style = CS_HREDRAW | CS_VREDRAW;
  32.         RegisterClassEx( &wce );
  33. }
  34. //创建主窗口
  35. HWND CreateMain( LPCTSTR lpClassName, LPCTSTR lpWndName )
  36. {
  37.         HWND hWnd = CreateWindowEx( 0, lpClassName, lpWndName,
  38.                                         WS_OVERLAPPEDWINDOW, 100, 100, 700, 500,
  39.                                         NULL, NULL, g_hInstance, NULL );
  40.         return hWnd;
  41. }
  42. //创建子窗口
  43. HWND CreateChild( LPCTSTR lpClassName, LPCTSTR lpWndName,
  44.                                         HWND hParent )
  45. {
  46.         HWND hChild = CreateWindowEx( 0, lpClassName, lpWndName,
  47.                                 WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,
  48.                                 100, 100, 200, 200, hParent, NULL,
  49.                                 g_hInstance, NULL );
  50.         return hChild;
  51. }
  52. //显示窗口
  53. void Display( HWND hWnd )
  54. {
  55.         ShowWindow( hWnd, SW_SHOW );
  56.         UpdateWindow( hWnd );
  57. }
  58. //消息循环
  59. void Message( )
  60. {
  61.         MSG nMsg = { 0 };
  62.         while( GetMessage(&nMsg, NULL, 0, 0) )
  63.         {
  64.                 TranslateMessage( &nMsg );
  65.                 DispatchMessage( &nMsg );//将消息交给窗口处理函数。
  66.         }
  67. }

  68. int APIENTRY WinMain(HINSTANCE hInstance,
  69.                      HINSTANCE hPrevInstance,
  70.                      LPSTR     lpCmdLine,
  71.                      int       nCmdShow)
  72. {
  73.         g_hInstance = hInstance;
  74.         Register( "Main", WndProc );
  75.         HWND hWnd = CreateMain( "Main", "window" );
  76.         Register( "Child", DefWindowProc );
  77.         HWND hChild1 = CreateChild( "Child", "c1", hWnd );
  78.         HWND hChild2 = CreateChild( "Child", "c2", hWnd );
  79.         Display( hWnd );
  80.         MoveWindow( hChild1, 100, 100, 200, 200, TRUE );//移动窗口位置和大小,(窗口句柄,水平坐标,垂直坐标,宽度,高度,是否擦除原来位置上的窗口图像)
  81.         MoveWindow( hChild2, 400, 100, 200, 200, TRUE );//[url=https://msdn.microsoft.com/EN-US/library/windows/desktop/ms633534(v=vs.85).aspx]MoveWindow函数[/url]
  82.         Message( );
  83.         return 0;
  84. }
复制代码


2.3窗口类和窗口的附加数据
注册窗口时,可以设置这两个数据内存空间的大小。
  1. int cbClsExtra; //窗口类附加数据buff的大小
  2. int cbWndExtra; //窗口附加数据buff的大小
复制代码

可以提供窗口类和窗口存放自己的数据的空间。

2.3.1窗口类附加数据的使用
2.3.1.1定义数据空间的大小
  1. int cbClsExtra - 一般定义为4字节倍数
复制代码

2.3.1.2存入数据(SetClassLong

  1. DWORD SetClassLong(
  2.         HWND hWnd,//窗口句柄
  3.         int nIndex,//字节索引号(从哪个字节开始存)
  4.         LONG dwNewLong //存入的数据
  5.         );返回旧数据
复制代码

2.3.1.3读取数据(GetClassLong

  1. DWORD GetClassLong(
  2.         HWND hWnd,  //窗口句柄
  3.         nt nIndex  //字节索引号(从哪个字节开始读)
  4.         ); 返回获取值
复制代码


2.3.2窗口附加数据的使用
2.3.2.1定义数据空间的大小
  1. int cbWndExtra;
复制代码

2.3.2.2存入数据(SetWindowLong

  1. LONG SetWindowLong(
  2.         HWND hWnd,       // 窗口句柄
  3.         int nIndex,      // 字节索引号(从哪个字节开始存)
  4.         LONG dwNewLong   // 存入的数据
  5.         );
复制代码

2.3.2.3读取数据(GetWindowLong

  1. LONG GetWindowLong(
  2.         HWND hWnd,  // 窗口句柄
  3.         int nIndex  // 字节索引号(从哪个开始读)
  4.         );//返回值获取读到的数据
复制代码


  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. HINSTANCE g_hInstance = 0;//接收当前程序实例句柄
  4. //自定义(窗口处理函数) 处理消息
  5. LRESULT CALLBACK WndProc( HWND hWnd, UINT msgID,
  6.                                                 WPARAM wParam, LPARAM lParam )
  7. {
  8.         switch( msgID )
  9.         {
  10.         case WM_DESTROY:
  11.                 PostQuitMessage( 0 );//使GetMessage函数返回0???
  12.                 break;
  13.         }
  14.         return DefWindowProc( hWnd, msgID, wParam, lParam );
  15. }
  16. //注册窗口类
  17. void Register( LPCTSTR lpClassName, WNDPROC wndproc )
  18. {
  19.         WNDCLASSEX wce = { 0 };
  20.         wce.cbSize = sizeof( wce );
  21.         wce.cbClsExtra = 200;
  22.         wce.cbWndExtra = 200;
  23.         wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  24.         wce.hCursor = NULL;
  25.         wce.hIcon = NULL;
  26.         wce.hIconSm = NULL;
  27.         wce.hInstance = g_hInstance;
  28.         wce.lpfnWndProc = wndproc;/***************/
  29.         wce.lpszClassName = lpClassName;
  30.         wce.lpszMenuName = NULL;
  31.         wce.style = CS_HREDRAW | CS_VREDRAW;
  32.         RegisterClassEx( &wce );
  33. }
  34. //创建主窗口
  35. HWND CreateMain( LPCTSTR lpClassName, LPCTSTR lpWndName )
  36. {
  37.         HWND hWnd = CreateWindowEx( 0, lpClassName, lpWndName,
  38.                                         WS_OVERLAPPEDWINDOW, 100, 100, 700, 500,
  39.                                         NULL, NULL, g_hInstance, NULL );
  40.         return hWnd;
  41. }
  42. //创建子窗口
  43. HWND CreateChild( LPCTSTR lpClassName, LPCTSTR lpWndName,
  44.                                         HWND hParent )
  45. {
  46.         HWND hChild = CreateWindowEx( 0, lpClassName, lpWndName,
  47.                                 WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,
  48.                                 100, 100, 200, 200, hParent, NULL,
  49.                                 g_hInstance, NULL );
  50.         return hChild;
  51. }
  52. //显示窗口
  53. void Display( HWND hWnd )
  54. {
  55.         ShowWindow( hWnd, SW_SHOW );
  56.         UpdateWindow( hWnd );
  57. }
  58. //消息循环
  59. void Message( )
  60. {
  61.         MSG nMsg = { 0 };
  62.         while( GetMessage(&nMsg, NULL, 0, 0) )
  63.         {
  64.                 TranslateMessage( &nMsg );
  65.                 DispatchMessage( &nMsg );//将消息交给窗口处理函数。
  66.         }
  67. }
  68. //存入数据

  69. void SetExtra( HWND hWnd )
  70. {
  71.         SetClassLong( hWnd, 0, 100);
  72.         SetWindowLong( hWnd, 0, 100 );
  73. }
  74. //读取数据
  75. void GetExtra( HWND hWnd )
  76. {
  77.         DWORD nClass = GetClassLong( hWnd, 0 );
  78.         DWORD nWnd = GetWindowLong( hWnd, 0 );
  79.         char szText[256] = { 0 };
  80.         sprintf( szText, "窗口类附加数据缓冲区:%d,窗口附加数据缓冲区:%d", nClass, nWnd );
  81.         MessageBox( hWnd, szText, "Infor", MB_OK );
  82. }

  83. int APIENTRY WinMain(HINSTANCE hInstance,
  84.                      HINSTANCE hPrevInstance,
  85.                      LPSTR     lpCmdLine,
  86.                      int       nCmdShow)
  87. {
  88.         g_hInstance = hInstance;
  89.         Register( "Main", WndProc );
  90.         HWND hWnd = CreateMain( "Main", "window" );
  91.         Register( "Child", DefWindowProc );
  92.         HWND hChild1 = CreateChild( "Child", "c1", hWnd );
  93.         HWND hChild2 = CreateChild( "Child", "c2", hWnd );
  94.         Display( hWnd );
  95.         MoveWindow( hChild1, 100, 100, 200, 200, TRUE );
  96.         MoveWindow( hChild2, 400, 100, 200, 200, TRUE );
  97.         SetExtra( hChild1 );
  98.         GetExtra( hChild2 );
  99.         Message( );
  100.         return 0;
  101. }
复制代码


2.4使用两种附加数据的不同
2.4.1窗口类附加数据缓冲区:是基于同一个窗口类创建出来的所有窗口共享的缓冲区。
2.4.2窗口附加数据缓冲区:是窗口自己私有的缓冲区,即便是基于同一个窗口类创建出来的窗口相互之间也不共享。

下期预告:windows消息机制

评分

参与人数 1鱼币 +5 收起 理由
小甲鱼 + 5 支持楼主!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-25 14:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表