zoukankan      html  css  js  c++  java
  • win32应用程序创建流程

    窗口创建过程


    创建一个完整的窗口,需要经过下面几个操作步骤:

    1.编写WinMain函数(可以查看MSDN)。

    2.设计窗口类(WNDCLASS)。

    3.注册窗口类。

    4.创建窗口。

    5.显示并更新窗口。

    6.编写消息循环。

    7.编程窗口过程函数。


    编写WinMain函数


    WinMain是Windows程序的入口点函数,当操作系统启动一个程序时,它就调用该程序的WinMain函数。它和DOS程序的入口点函数main是一样的作用。

    WinMain函数的原型声明如下:

    int WINAPI WinMain(HINSTANCE hInstance,   
                       HINSTANCE hPrevInstance, 
                       LPWSTR lpCmdLine,   
                       int nShowCmd
                       ); 
    参数说明:
    • hInstance 表示该程序当前运行的实例句柄,这是一个数值,操作系统会为每个运行中的实例分配句柄值。
    • hPrevInstance 当前实例的前一个句柄的实例。
    • lpCmdLine 指定给应用程序的命令行参数。
    • nShowCmd 指定程序的窗口应该如何显示。


    设计窗口类


    一个完整的窗口类具有许多特征,包括光标(鼠标进入该窗口时的形状)、图标、背景颜色等,在创建一个窗口前,需要对一个窗口进行设计,在windows中,窗口的特征有WNDCLASS结构体来定义,WNDCLASS结构体的定义如下:

    typedef struct 
    {
        UINT style;             //这一类型窗口的样式
        WNDPROC lpfnWndProc;    //指向窗口过程的函数指针
        int cbClsExtra;         //类附加内存
        int cbWndExtra;         //窗口附加内存
        HINSTANCE hInstance;    //实例句柄
        HICON hIcon;            //窗口类的图标句柄
        HCURSOR hCursor;        //窗口类的光标句柄
        HBRUSH hbrBackground;   //窗口类的背景    
        LPCTSTR lpszMenuName;   //菜单名字
        LPCTSTR lpszClassName;  //窗口类名字
    } WNDCLASS;
    


    注册窗口


    设计完窗口类后,需要调用RegisterClass函数对其注册,注册成功后,才可以创建该类型的窗口。函数声明如下:

    ATOM RegisterClass(const WNDCLASS* lpWndClass); 


    创建窗口


    设计好窗口类并进行注册成功之后,就可以利用CreateWindow函数产生这种类型的窗口了,其函数声明如下:

    HWND CreateWindow(LPCTSTR lpClassName,  //指定窗口类的名称,需要和WNDCLASS的className一样。
                      LPCTSTR lpWindowName, //窗口的名字
                      DWORD dwStyle,   		//创建的窗口样式
                      int x,   				//窗口左上角的x坐标
                      int y,   				//窗口左上角的y坐标
                      int nWidth,   		//窗口宽度
                      int nHeight, 			//窗口高度
                      HWND hWndParent,   	//父窗口句柄
                      HMENU hMenu,   		//窗口菜单的句柄
                      HANDLE hInstance,   	//应用程序句柄
                      PVOID lpParam ); 		//附件参数,多文档窗口为CLIENTCREATESTRUCT结构体,其余多是NULL

    显示窗口


    窗口创建成功之后,我们要让它显示出来,调用函数ShowWindow来显示窗口,函数原型如下:

    BOOL ShowWindow(HWND hWnd,   int nCmdShow);
    nCmdShow指定了窗口显示的状态,具体窗口状态可以查看MSDN


    更新窗口


    被调用ShowWindow函数之后,我们需要紧接调用UpdateWindow来刷新窗口。UpdateWindow函数声明如下:

    BOOL UpdateWindow(HWND hWnd// handle to window);
    其参数是创建成功后的窗口句柄,UpdateWindow函数通过发送一个WM_PAINT消息来刷新窗口,UpdateWindow将WM_PAINT消息直接发送给了窗口过程函数进行消息处理,而没有放到消息队列中去。


    消息循环


    在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。获取消息可以调用GetMessage()函数,消息循环常见代码如下:

        MSG msgInfo;
        while (GetMessage(&msgInfo, NULL, 0, 0))
        {
            TranslateMessage(&msgInfo);
            DispatchMessage(&msgInfo);
        }

    更多内容见“windows消息处理机制”。


    编程窗口过程函数


    在完成上述步骤后,剩下的工作主要是编写一个窗口过程函数,用于处理发送给窗口的消息。一个Windows应用程序的主要代码部分就隐藏在窗口过程,其函数声明如下:

    LRESULT CALLBACK WindowProc(HWND hwnd,
                                UINT uMsg,
                                WPARAM wParam,
                                LPARAM lParam
                                );

    窗口过程函数的名字是可随便命名的,但函数定义的形式必须和上述声明保持一致。WindowProc函数的4个参数分别对应消息的窗口句柄。消息代码、消息代码的两个附加参数。

    一个程序可以有多个窗口,窗口过程函数的hwnd就标识了接收消息的特定窗口。在窗口过程函数内部使用switch/case语句来确定窗口过程接收消息类型以及消息的处理。例如:

    //编写窗口过程函数
    LRESULT CALLBACK WindProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_CHAR:
            {
                char szMsg[20] = {0};
                sprintf_s(szMsg,"char code is %d", wParam);
                MessageBox(hWnd,szMsg, "char", 0);
                break;
            }
        case WM_PAINT:
    			...
    	case WM_CLOSE:
    			...
    	case WM_DESTROY:
    			...
        default:    
            return DefWindowProc(hWnd,uMsg,wParam,lParam);
        }
    }

    完整代码

    #include <Windows.h>
    #include <stdio.h>
    
    //窗口过程函数声明
    LRESULT CALLBACK WndProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    
    /****************************************************************
    *函数名称:WinMain
    *功    能:winddow应用程序入口
    *作    者:Jin
    *日    期:2016年8月10日
    ****************************************************************/
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow
                       )
    {
    
        //设计窗口类
        WNDCLASS wndcls;
        wndcls.cbClsExtra       = 0;
        wndcls.cbWndExtra       = 0;
        wndcls.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wndcls.hCursor          = LoadCursor(NULL, IDC_ARROW);
        wndcls.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
        wndcls.hInstance        = hInstance;
        wndcls.lpfnWndProc      = WndProcess;
        wndcls.lpszClassName    = "Jin";
        wndcls.lpszMenuName     = NULL;
        //垂直和横轴大小发生变化,窗口重绘
        wndcls.style            = CS_HREDRAW | CS_VREDRAW; 
        
        //注册窗口
        RegisterClass(&wndcls);
        HWND hWnd = NULL;
    
        //创建窗口
        hWnd = CreateWindow("Jin", "Jin Win32", WS_OVERLAPPEDWINDOW, 0, 0,
                            600, 400, NULL, NULL, hInstance, NULL);
    
        //显示&刷新
        ShowWindow(hWnd,SW_SHOWNORMAL);
        UpdateWindow(hWnd);
    
        //定义消息循环
        MSG msgInfo;
        while (GetMessage(&msgInfo, NULL/*所有窗口*/, 0, 0))
        {
            TranslateMessage(&msgInfo); //换字符消息
            DispatchMessage(&msgInfo);  //分发消息
        }
        
        return msgInfo.wParam;
    }
    
    /****************************************************************
    *函数名称:WndProcess
    *功    能:窗口过程消对应的消息处理
    *作    者:Jin
    *日    期:2016年8月21日
    ****************************************************************/
    LRESULT CALLBACK WndProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_CHAR:
            {
                char szChar[20] = {0};
                sprintf_s(szChar,"char code is %d", wParam);
                MessageBox(hWnd,szChar, "char", MB_OK);
                break;
            }
        case  WM_LBUTTONDOWN:
            {
                MessageBox(hWnd, "mouse clicked", "mouse", MB_OK);
                HDC hDc;
                hDc = GetDC(hWnd);
                TextOut(hDc, 0, 50, "hello world", strlen("hello world"));
                ReleaseDC(hWnd,hDc);
                break;
            }
        case WM_PAINT:
            {
                HDC hDC;
                PAINTSTRUCT ps;
                hDC = BeginPaint(hWnd, &ps);
                TextOut(hDC,0,0,"CSDN", strlen("CSDN"));
                EndPaint(hWnd, &ps);
                break;
            }
        case  WM_CLOSE:
            {
                if (IDYES == MessageBox(hWnd, "are you sure to exit?", "message", MB_YESNO))
                {
                    DestroyWindow(hWnd);//窗口消失,产生WM_DESTROY新消息
                }
                break;
            }
        case  WM_DESTROY:
            {
                PostQuitMessage(0);//产生WM_QUIT消息,然后程序退出
                break;
            }
        default:    
            return DefWindowProc(hWnd,uMsg,wParam,lParam);
        }
    
        return 0;
    }
    

    运行初始结果



  • 相关阅读:
    CMD命令行netsh添加防火墙规则
    C# 编写windows服务及服务的安装、启动、删除、定时执行任务
    C#释放资源文件dll或exe
    .net core 2.1 Razor 超快速入门
    正则表达式的先行断言(lookahead)和后行断言(lookbehind)
    C#从IE缓存读取图片
    实现ppt幻灯片播放倒计时
    C#自动化操作IE浏览器系列之一打开新的浏览器并导航到百度进行搜索
    MT【188】一个正切余切有关的恒等式
    MT【187】余弦的线性组合
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468390.html
Copyright © 2011-2022 走看看