预备知识

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. ubuntu下android studio生成的unaligned apk的zipalign处理

    在ubuntu系统中使用android studio生成的apk文件始终都是unaligned apk, 在bulid.gradle中设置如下设置后,还是同样生成的是unaligned apk. mi ...

  2. pt-table-checksum检验主从数据不一致

    测试环境:主从架构,操作系统liunx 运行pt-table-checksum需要先安装以下依赖包: yum install perl-IO-Socket-SSL perl-DBD-MySQL per ...

  3. java常用注解(更新中)

    注解根据来源可分为: 系统注解(自带的,取决于JDK版本).自定义注解及第三方注解 系统注解根据用途又可分为: java内置注解和元注解 根据运行机制(保留到什么时候)可分为: 源码注解.编译注解和运 ...

  4. 希尔排序(Shell Sort)

    一.思路 希尔排序是基于插入排序算法,通过允许不相邻的元素进行交换这一简单的改进,使数组变为局部有序,最终再用插入排序. 希尔排序的思想是使数组中任意间隔h的元素都是有序的.这样的数组被称为h有序数组 ...

  5. 算法(Algorithms)第4版 练习 1.5.8

    假设原id数组: 0 1 1 4 4 8 6 1 8 0 输入p = 5, q = 7 则输出结果会出错,最终为: 0 1 1 4 4 1 6 1 8 0 因为当id[p](id[5] = 8)被赋值 ...

  6. DL一(ML基础知识)

    基础知识ML 在进行深度学习前,根据学习网站的建议,首先学习机器学习的基础课程,学习资料主要是Andrew讲的ShortVideo,网址:http://openclassroom.stanford.e ...

  7. codeforces 460D:Little Victor and Set

    Description Little Victor adores the sets theory. Let us remind you that a set is a group of numbers ...

  8. Codeforces Round #250 (Div. 2) D. The Child and Zoo 并查集

    D. The Child and Zoo time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  9. php设计模式课程---2、为什么会用到简单工厂设计模式

    php设计模式课程---2.为什么会用到简单工厂设计模式 一.总结 一句话总结: 比如调用数据库的语句,如果调用的数据库名字改了,或者调用的数据库类型改了(比如从Mysql用到了Mysqli),那么要 ...

  10. python3反射解析

    python反射解析   一. 简介 python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某 ...