预备知识

1.什么是句柄? (HANDLE)

在win32编程中有各种句柄,那么什么是句柄呢?

#define DECLARE_HANDLE(name)

struct name##_

{

  int unused;

};

typedef struct name_* name;

例如HDC的定义

#define DECLARE_HANDLE(HDC)

struct HDC_

{

  int unused;

};

typedef struct HDC_ * HDC

当一个函数需要HWND类型参数的时候,你就不能传递HDC,因为类型不匹配。

总结:1.一个窗口句柄本质上是一个void * 2.win32编程中有特别多不同类型的窗口句柄,所以我们就把他们定义成不同的类型。例如HDC就是 HDC_*类型,HWND就是HWND_*类型。这样能避免参数类型错误。

2.calling convention 函数调用约定

  这些现象通常是出现在C和C++的代码混合使用的情况下或在C++程序中使用第三方的库的情况下(不是用C++语言开发的),其实这都是函数调用约定(Calling Convention)和函数名修饰(Decorated Name)规则惹的祸。函数调用方式决定了函数参数入栈的顺序,是由调用者函数还是被调用函数负责清除栈中的参数等问题,而函数名修饰规则决定了编译器使用何种名字修饰方式来区分不同的函数,如果函数之间的调用约定不匹配或者名字修饰不匹配就会产生以上的问题。

The same constraints apply to the 32-bit world as in the 16-bit world. The parameters are pushed from right to left (so that the first parameter is nearest to top-of-stack), and the caller cleans the parameters. Function names are decorated by a leading underscore.
 
This is the calling convention used for Win32, with exceptions for variadic functions (which necessarily use __cdecl) and a very few functions that use __fastcall. Parameters are pushed from right to left [corrected 10:18am] and the callee cleans the stack. Function names are decorated by a leading underscore and a trailing @-sign followed by the number of bytes of parameters taken by the function.
 
variadic functions:  In computer programming, a variadic function is a function of indefinite arity
 
The first two parameters are passed in ECX and EDX, with the remainder passed on the stack as in __stdcall. Again, the callee cleans the stack. Function names are decorated by a leading @-sign and a trailing @-sign followed by the number of bytes of parameters taken by the function (including the register parameters).
 
The first parameter (which is the "this" parameter) is passed in ECX, with the remainder passed on the stack as in __stdcall. Once again, the callee cleans the stack. Function names are decorated by the C++ compiler in an extraordinarily complicated mechanism that encodes the types of each of the parameters, among other things. This is necessary because C++ permits function overloading, so a complex decoration scheme must be used so that the various overloads have different decorated names.
 
  完成一个简单的win32程序
1.和所有的控制台程序都需要的一个main函数一样,win32程序需要一个WinMain()函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
它有4个参数
hInstance:当前应用程序的句柄,一般是exe或者dll文件
hPrevInstance: win16编程需要的参数,在win32编程中一直为NULL
lpCmdLine:命令行参数
nCmdShow: ShowWindow()函数需要的参数。
2.创建一个窗口需要窗口类。窗口类描述窗口的窗口名称、Icon、背景颜色、弹出方式等等窗口的特征。
WNDCLASS wc; //窗口类
然后我们初始化窗口类:

wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_ASTERISK);
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.lpszClassName = szClassName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;

3.窗口函数WNDPROC。

窗口类初始化中有一个(WNDPROC)WndProc窗口函数。窗口函数就是窗口对各种消息的处理函数(鼠标点击消息,键盘消息)。

我们使用switch case 结构来处理消息。

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
//The PAINTSTRUCT structure contains information for an application.
//This information can be used to paint the client area of a window owned by that application.
PAINTSTRUCT ps;
//The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
RECT rect;

  switch(msg)
  {
  case WM_CREATE:
    PlaySound (L"hello.wav", NULL, SND_FILENAME | SND_ASYNC) ;
  break;
  case WM_PAINT:
    hdc = BeginPaint (hwnd, &ps);
    GetClientRect (hwnd, &rect) ;
    DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
    EndPaint(hwnd, &ps);
  break;
  case WM_CLOSE:
    DestroyWindow(hwnd);
  break;
  case WM_DESTROY:
    PostQuitMessage(0);
  break;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;
}

4.创建窗口

HWND hWnd;  //创建窗口返回的句柄。如果不是NULL则创建成功。

hWnd = CreateWindow(szClassName, L"HelloWorld", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 650, 400, NULL, NULL, hInstance, NULL);

5.显示窗口

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

6.消息循环

while(GetMessage(&msg, NULL, 0, 0) > 0)
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}

  什么是消息循环,它如何工作?

1.消息循环调用while循环中的GetMessage()函数,GetMessage()函数在消息队列中寻找消息。如果没有消息,程序就一直“停”在while循环中。

2.当一个消息进入消息队列时,比如你点击鼠标触发了一个消息。GetMessage()函数返回一个大于0的值,表示这个消息正在被处理,并给msg结构体赋值。

(WM_QUIT消息 GetMessage()函数返回0,如果产生错误 GetMessage()函数负值)。

3.我们获得msg这个消息结构体,传递给TranslateMessage()函数,TranslateMessage()函数将虚拟的鼠标,键盘消息转化成WM_开头的字符串消息。

4.我们将字符串消息传递给DispatchMessage()函数。DispatchMessage()函数将会查找是那个窗口产生的消息,并且调用该窗口的窗口函数来处理。

我们将传递窗口的句柄,msg,wParam,lParam给窗口函数。

5.在窗口处理函数中,将检查消息(该消息是WM_那种消息?),并在特定的case中处理。如果没有这个消息的分类,则在DefWindowProc()函数中,默认处理。

6.一旦处理完消息,窗口处理函数返回,DispatchMessage()函数返回。程序又去消息队列中寻找下一个消息(返回最初始的状态)。

更多win32学习:http://www.winprog.org/tutorial/

完整代码: https://github.com/Superxy/Win32/blob/master/SimpleWindow/SimpleWindow/SimpleWindow.cpp

什么是消息循环,一个简单的win32程序如何运行?的更多相关文章

  1. 第一讲 一个简单的Qt程序分析

    本文概要:通过一个简单的Qt程序来介绍Qt程序编写的基本框架与一些Qt程序中常见的概念 #include <QApplication> #include <QPushButton&g ...

  2. (原创)如何使用boost.asio写一个简单的通信程序(一)

    boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...

  3. [WCF学习笔记] 我的WCF之旅(1):创建一个简单的WCF程序

    近日学习WCF,找了很多资料,终于找到了Artech这个不错的系列.希望能从中有所收获. 本文用于记录在学习和实践WCF过程中遇到的各种基础问题以及解决方法,以供日后回顾翻阅.可能这些问题都很基础,可 ...

  4. Flink源码分析 - 剖析一个简单的Flink程序

    本篇文章首发于头条号Flink程序是如何执行的?通过源码来剖析一个简单的Flink程序,欢迎关注头条号和微信公众号"大数据技术和人工智能"(微信搜索bigdata_ai_tech) ...

  5. 编写一个简单的C++程序

    编写一个简单的C++程序 每个C++程序都包含一个或多个函数(function),其中一个必须命名为main.操作系统通过调用main来运行C++程序.下面是一个非常简单的main函数,它什么也不干, ...

  6. 使用Go开发一个简单的服务器程序

    最近有个小项目,需要一个简单的后台程序来支撑,本来想用Nodejs来做,但是由于本人js一直很菜,并且很讨厌callback,虽然我也很喜欢异步模型,但我一直都觉得JS是反人类的.后台就用了go处理, ...

  7. 一个简单的flask程序

    初始化 所有Flask程序都必须创建一个程序实例. 程序实例是Flask类的对象,经常使用下述代码创建: from flask import Flask app = Flask(__name__) F ...

  8. 利用JSP编程技术实现一个简单的购物车程序

    实验二   JSP编程 一.实验目的1. 掌握JSP指令的使用方法:2. 掌握JSP动作的使用方法:3. 掌握JSP内置对象的使用方法:4. 掌握JavaBean的编程技术及使用方法:5. 掌握JSP ...

  9. 输出多行字符的一个简单JAVA小程序

    public class JAVA { public static void main(String[] args) { System.out.println("-------------- ...

随机推荐

  1. [原创]java WEB学习笔记19:初识MVC 设计模式:查询,删除 练习(理解思想),小结 ,问题

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  2. 0424 collections模块、time模块、rondom模块、sys模块

    昨日回顾:hashlib 摘要 md5 sha系列 文件的一致性校验 密文的认证 logging 记录日志 两种用法 basicConfig不常用 getLogger()常用 可以通过一个参数去控制全 ...

  3. 高通8X16电池BMS算法(一)【转】

    本文转载自:http://www.voidcn.com/blog/yanleizhouqing/article/p-6037399.html 最近一直在搞电源管理相关内容,之前是8610的bms,现在 ...

  4. mysql中的内连接,外连接实例详解

    内连接: 只连接匹配的行左外连接: 包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边表中全部匹配的行右外连接: 包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边 ...

  5. 吴恩达机器学习笔记(三) —— Regularization正则化

    主要内容: 一.欠拟合和过拟合(over-fitting) 二.解决过拟合的两种方法 三.正则化线性回归 四.正则化logistic回归 五.正则化的原理 一.欠拟合和过拟合(over-fitting ...

  6. 51nod 1196

    题目 神犇题解:见题目讨论区曹鹏神犇的讲解. 跪烂..倒地不起.. 对于每一个合法解,我们都可以将其唯一地分解成若干个“链”.所谓链是指由那些小于n/2的字符组成的,并且最后一个字符满足2*i> ...

  7. Sed 命令详解 正则表达式元字符

    1.简介 sed是非交互式的编辑器.它不会修改文件,除非使用shell重定向来保存结果.默认情况下,所有的输出行都被打印到屏幕上. sed编辑器逐行处理文件(或输入),并将结果发送到屏幕.具体过程如下 ...

  8. 第二章 python基础(二)

    第九节 函数 函数就是完成特定功能的一个语句组,这组语句可以作为一个单位使用,并且给它取一个名字. 可以通过函数名在程序的不同地方多次执行(这通常叫做函数调用),却不需要在所有地方都重复编写这些语句. ...

  9. 【论文笔记】基于图机构的推荐系统:Billion-scale Commodity Embedding for E-commerce Recommendation in Alibaba

    论文:https://arxiv.org/abs/1803.02349    题外话: 阿里和香港理工联合发布的这篇文章,整体来说,还挺有意思的. 刚开始随便翻翻看看结构图的时候,会觉得:这也能发文章 ...

  10. 10 - Django应用第七步

    1 自定义管理表单 通过在admin.py注册之后可以在后台中管理相应注册的表 但是我们还学要更多的自定义操作 polls/admin.py from django.contrib import ad ...