预备知识

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. cookie补充

    之前写cookie中关于突破同源策略共享cookie说的比较含糊,此次来详细说明一下: ## 首先说一下cookie的path和domain这 两个属性值 path: path表示的此条cookie是 ...

  2. 【leetcode刷题笔记】Rotate List

    Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1 ...

  3. sql优化,索引学习

  4. css 采集下载

    软件应用范围: 看到喜欢的网页,另存为的话,并不能直接保存css中引用的图片. 那么就有了本软件的用武之地. 亮点:自动匹配文件内的相对路径.css内图片地址值md5保存,用来避免不同文件夹同名文件的 ...

  5. Cocos2d-x中常用宏的作用

    1. CC_SYNTHESIZE(int, nTest, Test); 相当于: protected: int nTest; public: virtual nTest getTest(void) c ...

  6. SQL2005 2008配置错误,无法识别的配置节 system.serviceModel machine.config配置文件有问题

    当装上2008的时候,你以前的程序突然报出你的machine.config配置文件有问题,比如 “/” 应用程序中的服务器错误. 配置错误 说明 : 在处理向该请求提供服务所需的配置文件时出错.请检查 ...

  7. 分享知识快乐自己:Layui 常用样式

    下载 样式包  Layui  layer 引入 js 及 样式: <link rel="stylesheet" href="${ctx}/static/layui/ ...

  8. java_面试_01_一个月的面试总结(java)

    重点知识 由于我面试的JAVA开发工程师,针对于JAVA,需要理解的重点内容有: JVM内存管理机制和垃圾回收机制(基本每次面试都会问,一定要搞得透彻) JVM内存调优(了解是怎么回事,一般做项目过程 ...

  9. JavaUtil_08_StringUtil_commons-lang3 之 StringUtils

    二.参考资料 1.[commons]字符串工具类——commons-lang3之StringUtils

  10. 并发问题引出ThreadLocal

    ThreadLocal Thread-->人类Runnable-->任务类 多线程并发问题引出ThreadLocal 多线程并发问题的原因: 操作同一个对象,对对象具有读写权限(只读如拍照 ...