• 【MFC】第一个窗口程序(2)


    Windows C窗口程序

    也称“SDK编程”,即调用 Windows 提供的API接口(C),完成窗口程序的设计,API接口可以理解为一些C的函数和数据类型(结构体、枚举)。

    难点1:

    突然冒出很多“新”的数据类型,DWORD 、LPSTR 、LRESULT等等

    难点2:

    句柄的概念,应用程序实例句柄、窗口句柄、画刷光标句柄、文件句柄等等

    难点3:

    消息队列、消息处理与程序流程。

    先写一个最简单的SDK窗口程序(VS2012平台):

    步骤1:

    创建工程,选择《Win32项目》(不是控制台项目)

     步骤2:

    一步一步点下去,在《应用程序设置》页面,把 空项目 勾上,空白项目压力最小。

    步骤3:

    添加一个CPP文件,编写代码:

    代码如下:

    1. #include <Windows.h>
    2. LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
    3. {
    4. switch(message)
    5. {
    6. case WM_DESTROY:
    7. case WM_CLOSE:
    8. ::PostQuitMessage(0);
    9. break;
    10. default:
    11. return ::DefWindowProc(hwnd,message,wParam,lParam);
    12. }
    13. return 0;
    14. }
    15. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
    16. {
    17. WNDCLASS wc;
    18. wc.cbClsExtra=0;
    19. wc.cbWndExtra=0;
    20. // wc.hbrBackground=NULL;
    21. wc.hbrBackground=(HBRUSH)::GetStockObject(GRAY_BRUSH);
    22. // wc.hCursor=NULL;
    23. wc.hCursor=::LoadCursor(NULL,IDC_CROSS);
    24. wc.hIcon=NULL;
    25. wc.hInstance=hInstance;
    26. wc.lpfnWndProc=WndProc;
    27. wc.lpszClassName="Test";
    28. wc.lpszMenuName=NULL;
    29. wc.style=CS_VREDRAW | CS_HREDRAW;
    30. ::RegisterClass(&wc);
    31. HWND hwnd = ::CreateWindow("Test","First Windows Appliation",WS_OVERLAPPEDWINDOW,0,0,800,600,NULL,NULL,hInstance,NULL);
    32. ::ShowWindow(hwnd,nCmdShow);
    33. ::UpdateWindow(hwnd);
    34. MSG msg;
    35. while(::GetMessage(&msg,NULL,NULL,NULL))
    36. {
    37. ::TranslateMessage(&msg);
    38. ::DispatchMessage(&msg);
    39. }
    40. return 0;
    41. }

     1、WinMain 是程序的入口,由操作系统调用,返回 int 值供操作系统了解程序运行的结果(是否异常),这与控制台的main 函数类似;

    2、函数调用的规则:函数调用的时候,需要把参数入栈,调用完毕也需要回收栈的空间,多个参数则有从右到左或者相反的方向。__stdcall 和 __cdec 都是从右到左,其中__cdec是C和C++程序的缺省调用方式,特点是 调用函数 负责栈的管理。__stdcall 则是由被调函数完成栈的管理(回收)。

    3、WINAPI 、CALLBACK 都是__stdcall

     其实这点区别不重要,关键是 回调函数 ,普通的函数调用方默认等待被调函数的返回,有些情况下肯定是不行的,比如消息处理函数:如果“消息处理” 不能  “并行” 操作,那么可能消息堵塞!

    所以,有些函数应该设计成类似 “线程” 的非等待类型函数。这时候主调函数回收栈的方式就不能接收了,因为主调函数不等待被调函数结束!

    然而,上面的都不重要!指定函数为WINAPI 基本上不会出错

    4、四个参数,两个句柄 (HINSTANCE),句柄其实就是一个32位的无符号整数,Windows管理文件、内存、GDI(画笔、画刷等待绘图工具)、图标、光标、菜单等待,各种各样的资源。为了管理方便,给每个资源进行编号(就像身份证)就可以理解了,但是。。。一个无符号整数是很难理解的,所以用typedef 给 unsigned int 搞几个别名吧!这样就好理解!

    Windows下出现的各种 “新” 数据类型中,很多都是这样的操作!

    5、第一个参数,操作系统分配给应用程序的句柄(身份ID),后面属于该程序的窗口等等,都可以利用它来表明身份,第二个参数已经被弃用(程序运行多个副本),第三个参数是命令行,运行程序的同时可以加入命令行参数(类似ping ******),第四个参数就是窗口的显示方式,最大化、隐藏、最小化等等

    6、WinMain的基本流程是,定义一个描述窗口特征的结构体(WNDCLASS),填写结构体的分量值(其中最重要的填入窗口的消息处理函数),注册这个窗口类(此类并非面向对象的类),根据注册的窗口类名称创建窗口、显示窗口,然后进入一个类似“死”循环的消息处理。最后在获取到主窗口销毁消息后退出程序。

    7、窗口函数:LRESULT也是一个32位无符号整数,返回消息处理结果。四个参数,第一个是窗口句柄,注册窗口类绑定了窗口函数,注册的窗口类是可以创建多个窗口的,所以消息是发给哪个窗口的,必须区分。第二个参数是消息的类型,枚举类型(其实也是int);第三和第四个参数是附加信息,比如鼠标点击消息需要附加鼠标位置、按键信息等等。

    窗口函数肯定是一个switch 结构,对不同消息进行不同入口处理,这里其实是窗口程序设计的重点

    8、WinMain消息循环中,GetMessage的第二个参数必须设置成NULL (所有窗口),否则程序无法通过关闭窗口进行退出。(窗口关闭,销毁窗口,回收窗口句柄,只捕获该窗口消息则无法获取后续的WM_QUIT消息)。

  • 相关阅读:
    SpringCloud笔记之Rest环境搭建
    python安装selselenium,chromedriver,秒杀脚本教程
    小插曲 -- 使用Linux编写 判断程序是否在运行的小程序
    Linux虚拟服务器-LVS-集群技术
    他潜伏三年想插它后门,最终还是输给了另一个他
    ACL访问控制列表 基础、创建ACL访问控制列表的两种方式、配置ACL访问控制列表规则、修改ACL规则的默认步长。子网掩码、反掩码、通配符掩码的区别和作用。
    主主复制主从复制3台服务器部分不能同步问题
    Flink部署——高可用
    306周赛t4 6151. 统计特殊整数 记忆化搜索
    探索TiDB Lightning源码来解决发现的bug
  • 原文地址:https://blog.csdn.net/yixiaobo2001/article/details/127782352