WinMain函数 注册窗口类 消息循环

2024-03-25 22:38

本文主要是介绍WinMain函数 注册窗口类 消息循环,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#include <windows.h>
#pragma comment(lib,"winmm.lib")//为了要播放声音,必须导入这个库

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
/*
     HINSTANCE 类型的含义为实例句柄。
         hInstance 事实上就是当前应用程序自身的标识代号,代号通常都是一个32位整数。
         hPrevInstance 与过去的16位应用程序有关系,表示指向前一个实例的句柄。

     PSTR 类型的含义是指向以\0结尾的字符串指针。
         szCmdLine 前面的sz同样是表示指向以\0结尾的字符串指针,这个对象用于保存命令行。

     最后iCmdShow是一个整型数据,标记了程序最初的显示状态。
         为SW_SHOWNORAML的时候为一般大小显示方式。
         为SW_SHOWMAXIMIZED的时候为最大化显示方式。
         为SW_SHOWMINNOACTIVE的时候程序将显示在任务栏上。
*/
{

    static char szAppName[] = TEXT("HelloWin");//预先定义一个c风格字符串,稍后用于设置窗口类名称。
    WNDCLASS wndclass;//定义窗口类对象
/*
     在这里不得不说一下的是,窗口类事实上是struct结构体,内部有10个分量,他们是用来于初始化窗口类对象而用的。
     这个结构体在winuser.h头文件中定义,从方式上来说,分为ASCII版的WNDCLASSA和Unicode版的WNDCLASSW两个。
     typedef struct tagWNDCLASSA {
         UINT        style;
         WNDPROC     lpfnWndProc;
         int         cbClsExtra;
         int         cbWndExtra;
         HINSTANCE   hInstance;
         HICON       hIcon;
         HCURSOR     hCursor;
         HBRUSH      hbrBackground;
         LPCSTR      lpszMenuName;
         LPCSTR      lpszClassName;
     } WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
     typedef struct tagWNDCLASSW {
         UINT        style;
         WNDPROC     lpfnWndProc;
         int         cbClsExtra;
         int         cbWndExtra;
         HINSTANCE   hInstance;
         HICON       hIcon;
         HCURSOR     hCursor;
         HBRUSH      hbrBackground;
         LPCWSTR     lpszMenuName;
         LPCWSTR     lpszClassName;
     } WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
*/

//------------------------------- 窗口类对象初始化过程 ------------------------------------     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
     /*
         设置窗口类对象的样式风格,CS_HREDRAW | CS_VREDRAW这两个值是通过位运算的与运算结合起来的。
         表示了窗口在改变了水平和垂直大小的时候,窗口要强迫刷新。
         这些通过define定义的标识,可以在WinUser.h头文件中找到。
         #define CS_VREDRAW          0x0001
         #define CS_HREDRAW          0x0002
         #define CS_DBLCLKS          0x0008
         #define CS_OWNDC            0x0020
         #define CS_CLASSDC          0x0040
         #define CS_PARENTDC         0x0080
         #define CS_NOCLOSE          0x0200
         #define CS_SAVEBITS         0x0800
         #define CS_BYTEALIGNCLIENT  0x1000
         #define CS_BYTEALIGNWINDOW  0x2000
         #define CS_GLOBALCLASS      0x4000
         #define CS_IME              0x00010000
     */

    wndclass.lpfnWndProc   = WndProc ;//指定窗口的处理函数为WndProc,WndProc将处理windows消息。
    wndclass.cbClsExtra    = 0;//窗口类无扩展
    wndclass.cbWndExtra    = 0;//窗口实例无扩展
    wndclass.hInstance     = hInstance;//指定当前应用程序实例句柄,也就是程序当前的标识号。
    wndclass.hIcon         = LoadIcon (NULL,IDI_APPLICATION);
     /*
         通过LoadIcon函数设置应用程序窗口标题的icon图标。
         HICON LoadIcon(HINSTANCE hInstance,LPCTSTR lpIconName);
         函数返回HICON类型的图标句柄。
         第一个参数表示当前应用程序的窗口句柄,第二个参数表示图标。
         默认状态下,第一个参数为NULL,第二个为IDI_APPLICATION,表示使用系统默认提供的图标,可以在WinUser.h头文件中找到。
         #define IDI_APPLICATION     32512
     */
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     /*
         通过LoadCursor函数设置应用程序窗口光标样式。
         HCURSOR LoadCursor(HINSTANCE hInstance,LPCTSTR lpCursorName);
         函数返回HCURSOR类型的光标句柄。
         第一个参数表示当前应用程序的窗口句柄,第二个参数表示光标。
         默认状态下,第一个参数为NULL,第二个为IDC_ARROW,表示使用系统默认提供的光标,可以在WinUser.h头文件中找到。
         #define IDC_ARROW           MAKEINTRESOURCE(32512)
     */
     wndclass.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
     /*
         通过GetStockObject函数设置应用程序窗口的背景颜色。
         HGDIOBJ GetStockObject(int fnObject);
         函数返回HCURSOR类型的GDI对象句柄,为了程序能够正确执行,必须把HGDIOBJ类型强制转换成HBRUSH画刷句柄。
         参数表示当前使用的画刷颜色。
         这些常量的定义可以在WinGDI.h头文件中找到。
         #define WHITE_BRUSH         0
         #define LTGRAY_BRUSH        1
         #define GRAY_BRUSH          2
         #define DKGRAY_BRUSH        3
         #define BLACK_BRUSH         4
         #define NULL_BRUSH          5
         #define HOLLOW_BRUSH        NULL_BRUSH
     */
     wndclass.lpszMenuName  = NULL;
     wndclass.lpszClassName = szAppName;//窗口类对象的名称
//-----------------------------------------------------------------------------------------
     RegisterClass (&wndclass);
     /*
         注册窗口类,参数为窗口类对象的指针。
         函数原形为:
         ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
     */

//--------------------------  实例化过程  -------------------------------------------------
    HWND   hwnd ; //创建用于保存窗口句柄的对象,窗口句柄是系统识别不同窗口的依据,它只是个代号。
    hwnd = CreateWindow(
                                 szAppName,            // 窗口类名称
                                 "你好世界",           // 窗口标题
                                 WS_OVERLAPPEDWINDOW,  // 窗口样式
                                 CW_USEDEFAULT,        // 初始的窗口x轴位置
                                 CW_USEDEFAULT,        // 初始的窗口y轴位置
                                 CW_USEDEFAULT,        // 初始的窗口x轴大小
                                 CW_USEDEFAULT,        // 初始的窗口y轴大小
                                 NULL,                 // 父窗口句柄
                                 NULL,                 // 窗口功能表句柄
                                 hInstance,            // 应用程序实例句柄
                                 NULL                  // 建立参数,这个参数可以存取后面程序中可能引用到的资料。
                            );
     /*
         在窗口类对象的初始化过程中,我们定义了窗口的一些简单一般特征,比如背景颜色呀,光标呀,等等。
         但是在利用CreateWindow创建窗口的时候可以设置更多的细节,比如窗口标题这些。
         函数原形如下:
         HWND CreateWindow(  LPCTSTR lpClassName,
                                 LPCTSTR lpWindowName,
                                 DWORD dwStyle,
                                 int x,
                                 int y,
                                 int nWidth,
                                 int nHeight,
                                 HWND hWndParent,
                                 HMENU hMenu,
                                 HINSTANCE hInstance,
                                 LPVOID lpParam
                            );
         一旦窗口创建成功,那么CreateWindow将返回窗口句柄,也就是窗口代号,值保存在窗口句柄对象hwnd中。
     */
    ShowWindow(hwnd, iCmdShow);
     /*
         在执行过CreateWindow函数后,在系统的内部窗口已经创建成功了。
         但为了要把窗口显示在桌面上,我们还必须调用ShowWindow函数。
         其函数原形如下:
         BOOL ShowWindow(WND hWnd,int iCmdShow);
         参数1是需要显示的窗口句柄,第二个则是传递给WinMain的iCmdShow,用来确定最开始窗口的显示方式。
         在这里窗口的显示方式,主要是指最大化,最小化这些。
     */
    UpdateWindow (hwnd);
     /*
         UpdateWindow这个函数的作用是用于重绘显示区域。
         因为如果ShowWindow函数的iCmdShow从WinMain获得的参数是SW——SHOWNORMAL,那么窗口的显示区域就会被背景画刷覆盖,
         调用UpdateWindow函数会通过发送给窗口消息处理函数WndProc一个WM_PAINT消息,通过这个消息完成重绘显示区域的工作。
     */
//-----------------------------------------------------------------------------------------
//----------------------------  消息循环  -------------------------------------------------
     /*
         当调用过UpdateWindow函数后,窗口已经显示在了桌面屏幕上,接下来要做的工作是处理消息。
         windows应用程序可以接受各种消息包括键盘,鼠标,等等。
         windows是通过监视各种输入设备,把发生的事件转化为消息的,并将消息保存在消息队列中。
         最后当前的应用程序从自己的消息队列中按顺序检索消息,并把每一个消息发送到所对应的窗口消息处理函数总去,这里是指WndProc
     */
    MSG    msg ;//建立消息对象。
     /*
         MSG是个结构体类型,在WinUser.h头文件中可以找到。
         typedef struct tagMSG{
         HWND        hwnd;//窗口句柄
         UINT        message;//消息识别字,在WinUser.h头文件中可以找到,以WM开头,这里就不全部举出来了。
         WPARAM      wParam;//32位的消息参数,其含义和值根据消息的不同而不同。
         LPARAM      lParam;//32位的消息参数,其值和消息无关。
         DWORD       time;//消息进入消息队列的时间。
         POINT       pt;//消息进入消息队列时候的鼠标坐标。
         #ifdef _MAC
              DWORD       lPrivate;
         #endif
         } MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
         其中POINT也是个结构体类型,在WinDef.h头文件中可以找到

         typedef struct tagPOINT
         {
              LONG  x;
              LONG  y;
         } POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
     */
    while (GetMessage (&msg, NULL, 0, 0))
    {
         /*
              我们通过这个循环代码来维护消息循环,循环的执行条件是通过GetMessage函数获得的。
              函数原型如下:
              BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);
              参数一是一个指向msg对象的指针,剩余的参数为NULL或0表示程序接受它自己建立的所有窗口的消息。
              windows从消息队列取出的下一个消息将填充MSG结构中的各成员分量。
         */
              TranslateMessage (&msg);//把虚拟键盘消息转换到字符消息,满足键盘输入的需要,参数为msg消息对象的指针。
              DispatchMessage (&msg);
              /*
                   把当前的消息发送到窗口消息处理函数中去处理,在这里为WndProc
                   当DispatchMessage调用结束后,循环再次重复,重新回到GetMessage处,接着获取消息。
                   如果消息循环接收到WM_QUIT消息则跳出消息循环。
              */
    }
//----------------------------------------------------------------------------------------
    return msg.wParam;//返回消息结构中的wParam成员信息。
     /*
         MSG结构的wParam成员的值是传递给PostQuitMessage函数参数,通常是0。
         因为PostQuitMessage函数是在结束消息循环必须调用的函数。
         系统其实是执行了return 0;结束了WinMain函数退出了程序,很想控制台应用程序main结束的时候的return 0;,所以直接写return 0;也不会导致程序错误。
     */
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//窗口消息处理函数
/*
     函数返回类型为LRESULT,是一个长整数,修饰CALLBACK表示此函数为回调函数,函数的返回类型,和参数顺序都必须按照系统的规定设置。
     参数一为窗口句柄,第二个参数是无符号整型数据,用于标识接受的消息,最后两个参数为32位的消息参数,提供了更多关于消息的信息。
     WPARAM和LPARAM都表示的是长整数,该函数的四个参数与MSG结构的前四个成员相同。
     消息处理函数,通常是windows自己调用的,当然程序作者也可以通过调用SendMessage函数直接呼叫自己的窗口消息处理函数,只是在这里暂时不讨论。
*/
{
    HDC hdc;//创建设备描述句柄对象
    PAINTSTRUCT ps;//创建绘制结构对象
     /*
         PAINTSTRUCT结构包含了一些窗口消息处理程序,可以用来更新窗口显示区域中的信息。
         结构如下:
         typedef struct tagPAINTSTRUCT { 
         HDC  hdc; 
         BOOL fErase; 
         RECT rcPaint; 
         BOOL fRestore; 
         BOOL fIncUpdate; 
         BYTE rgbReserved[32]; 
         } PAINTSTRUCT, *PPAINTSTRUCT; 
     */
    RECT rect;//创建矩形结构对象
     /*
         此结构的定义如下:
         typedef struct _RECT { 
         LONG left; 
         LONG top; 
         LONG right; 
         LONG bottom; 
         } RECT, *PRECT; 
     */
    switch (message)//通过switch和case结构来确定处理什么样的消息,如果不想处理某些消息则把消息传递给DefWindowProc函数处理。
    {
         case WM_CREATE://当窗口创建的时候获得WM_CREATE消息
              PlaySound (TEXT("C:\\online.wav"),NULL,SND_FILENAME|SND_ASYNC);//播放声音
              return 0;//窗口消息处理函数如果正在处理消息必须返回0
         case WM_PAINT://通知窗口更新显示区域的信息
              /*
                   当窗口刚开始建立的时候,整个显示区域都是无效的,因为程序还没有在窗口上绘制任何东西。
                   第一条WM_PAINT消息通常发生在调用UpdateWindows函数的时候,告诉窗口消息处理函数在显示区域绘制一些东西。
                   事实上当用户把wndclass.style设置成CS_HREDRAW | CS_VREDRAW后,一旦用户改变窗口大小,就会把显示区域当作无效,这时候就会收到WM_PAINT消息。
              */
              /*
                   通常在处理WM_PAINT消息的时候,总是以BeginPaint开头和EndPaint结尾的。
              */
              hdc = BeginPaint (hwnd, &ps);
              /*
                   调用BeginPaint函数可以传回设备句柄,这里指的是显示器的代号和显示器的驱动程序。
                   因为在窗口显示区域要显示文字或者图形都需要用到设备句柄。
                   它的函数原形为:
                   HDC BeginPaint(
                   HWND hwnd,            // handle to window
                   LPPAINTSTRUCT lpPaint // paint information
                   );
                   它实际的功能是:当发现窗口显示区域的背景还没有被清除的时候,则由windows来删除它。
                   我们前面在wndclass结构中设置了画刷为白色,这么以来系统就用白色来遮盖桌面的颜色,这样窗口显示区域就变成白色了。
              */
              GetClientRect (hwnd,&rect);//设置窗口显示区域的尺寸,同时它也负责获得窗口改变后的窗口显示区域的尺寸信息。
              DrawText (hdc,TEXT("中国软件开发实验室,http://www.cndev-lab.com"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);//绘制文字在窗口显示区域中
              /*
                   DT_SINGLELINE|DT_CENTER|DT_VCENTER 表示的是文字显示的方式,这些在WinUser.h头文件中定义。
              */
              EndPaint (hwnd,&ps);//结束指定窗口的绘图
              return 0;
         case WM_DESTROY://当窗口销毁的时候会返回此信息,比如ALT+F4或关闭窗口的时候,系统默认调用DestroyWindow()函数撤消窗口。
              PostQuitMessage (0);
              /*
                   处理WM_DESTROY消息必须调用PostQuitMessage函数,该函数向消息队列中发送WM_QUIT消息,让程序退出消息循环。
                   应用程序可以在响应这个消息的同时做一些其它结束的工作。
              */
              return 0;
    }
  return DefWindowProc (hwnd, message, wParam, lParam);//处理不于处理的消息
}

 

总结:VC++6.0编程真是难啊,比C#等语言难学多了,我也是硬着头皮把这个程序看完并读懂,真是不容易啊。
1、WinMain函数
⑴函数说明
⑵初始化
①窗口类定义
②注册窗口类
③创建窗口
④显示窗口
⑶消息循环
2、窗口函数

这篇关于WinMain函数 注册窗口类 消息循环的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/846466

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

使用JS/Jquery获得父窗口的几个方法(笔记)

<pre name="code" class="javascript">取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document);如题: $(selector, window.top.document);//获得顶级窗口里面的元素 $(

ActiveMQ—消息特性(延迟和定时消息投递)

ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message Delivery) 转自:http://blog.csdn.net/kimmking/article/details/8443872 有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。 类似

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据