预备知识

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. 通过tile和url判断页面跳转是否正确

    通过webdriver中的.title和.current_url获取title和url from time import sleep from selenium import webdriver br ...

  2. Java多线程系列 JUC锁08 LockSupport

    转载 http://www.cnblogs.com/skywang12345/p/3505784.html https://www.cnblogs.com/leesf456/p/5347293.htm ...

  3. Fidder工具抓包及篡改数据

    下载fiddler的最新版本: 运行fiddler之后测试要调试的页面是否可以捕获,刷新页面后左边列表会实时显示目前http请求的条目.如图红色部分 测试成功,开始断点捕获数据 点击菜单栏按钮[Rul ...

  4. 2.微信小程序-B站:需要先知道这些

    文件结构 小程序包含一个描述整体程序的 app 和多个描述各自页面的 page.一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下: 文件 必须 作用 app.js 是 小程序逻辑 app. ...

  5. Android_微信_设置

    减少 内存的使用 (http://news.ifeng.com/a/20170716/51440541_0.shtml) 1.关闭“附近的人” 打开微信,依次点击[我]—[设置]—[通用]—[功能], ...

  6. 关于IDT报错乱码总结

    可算是把我折腾坏了.一筹莫展.最后才把这些问题搞好.有些事不知道做以前,怎么都想不到.发现了方法之后,原来也不过这样.我觉得自己记性太差.还是好好写下来吧.写下来顺便会帮我重新再梳理一遍.原先乱码是因 ...

  7. AngularJS-Basic(一)

    MVC:作为DataModel的$scope 依赖注入DI 模块化Module Service Filter Two way DateBinding Directive Unit Testing&am ...

  8. JavaWEB - JSP 指令

  9. C语言小程序(八)、统计字母个数

    这么简单的程序本不应贴在这里,但每写一篇博客,积分涨10分,距离摆脱千里之外的排名又进一步,相当于刷榜了,哈哈! #include <stdio.h> #include <strin ...

  10. luogu1901 发射站

    单调栈 正着插一遍反着插一遍 记录每个点左边右边第一个比他高的... yyc太强辣 #include<iostream> #include<cstdlib> #include& ...