Win32    程序开发的流程

message based, event driven

Win32程序是message based, event driven。也就是说Win32程序的运行是依靠外部不断发生的事件来驱动的,也就是说,程序不断等待(有一个while循环),等待任何可能的输入,然后做判断,再做适当的处理。因此Win32程序只需要做好如下几件事情就可以了:

1. 定义窗口的外观;

2. 定义当不同的事件发生时,程序做什么样的反应(定义窗口处理函数);

3. 写一个While循环,不断检测新事件的发生,并将其发送给不同的窗口处理函数

程序进入点WinMain

main是一般C程序的进入点:int main( int argc, char *argv[], char *envp[])

Win32程序的进入点是

int CALLBACK WinMain(  __in  HINSTANCE hInstance,  __in  HINSTANCE hPrevInstance,  __in  LPSTR lpCmdLine,  __in  int nCmdShow);

当用户要执行一个程序时,首先是Windows 的Shell(Explorer)调用CreateProcess这个系统调用,CreateProcess为这个进程创建虚拟地址,然后将代码和数据载入,然后系统再创建一个主线程开始执行run time startup函数的代码,run time startup 函数会最终调用入口点函数(main, WinMain)。如果用户执行的是一个Win32程序,那么C startup就会调用WinMain并开始执行程序。

窗口类注册与窗口诞生

如果前面所说,Win32的一个重要的责任是定义窗口外观和窗口处理函数。这是通过窗口类注册来完成的。创建窗口可以使用CreateWindow来完成,但在调用CreateWindow时必须先设定窗口的各种属性和行为。设定窗口属性和行为是通过API 函数 RegisterClass 来完成的。RegisterClass需要一个大型数据结构WNDCLASS,窗口的属性和行为就是在这个数据结构中指定的。

ATOM WINAPI RegisterClass(  __in  const WNDCLASS *lpWndClass);

下面是数据结构WNDCLASS的定义:

typedef struct tagWNDCLASS {   UINT      style;   WNDPROC   lpfnWndProc;   int       cbClsExtra;   int       cbWndExtra;   HINSTANCE hInstance;   HICON     hIcon;   HCURSOR   hCursor;   HBRUSH    hbrBackground;   LPCTSTR   lpszMenuName;   LPCTSTR   lpszClassName; } WNDCLASS, *PWNDCLASS;

消息循环是怎么工作的

应用程序可以获得的输入有两种类型:硬件装置产生的消息房子系统队列中、由Windows系统或者其他Windows程序传送过来的消息,放在程序队列中。以应用程序的眼光来看,消息就是消息,来自哪里或放在哪里没有太大区别,程序每次GetMessage就取得一个消息。

每个窗口都应该有一个函数负责处理消息,程序员必须负责设计这个所谓的窗口函数(Window Procedure),如果窗口获得一个消息,则这个窗口必须判断消息的类别,决定处理方式。下面是主消息循环的例子:

// Main message loop: while (GetMessage(&msg, NULL, 0, 0)) {     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))     {         TranslateMessage(&msg);         DispatchMessage(&msg);     } }

GetMessage的原型:

BOOL WINAPI GetMessage(  __out     LPMSG lpMsg,  __in_opt  HWND hWnd,  __in      UINT wMsgFilterMin,  __in      UINT wMsgFilterMax);

调用线程的消息队列中获取一个消息,这个函数会一直等到有一个可用的Message时才会返回;

int WINAPI TranslateAccelerator(  __in  HWND hWnd,  __in  HACCEL hAccTable,  __in  LPMSG lpMsg);

该函数处理菜单命令中的加速键。该函数将一个WM_KEYDOWN或WM_SYSKEYDOWN消息翻译成一个WM_COMMAND或WM_SYSCOMMAND消息(如果在给定的加速键表中有该键的入口),然后将WM_COMMAND或WM_SYSCOMMAND消息直接送到相应的窗口处理过程。

TranslateMessage是用来把虚拟键消息转换为字符消息。由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。 TranslateMessage函数用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。 也就是说TranslateMessage会发现消息里是否有字符键的消息,如果有字符键的消息,就会产生WM_CHAR消息,如果没有就会产生什么消息。

windows消息处理机制是这样的: 首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息放到一个系统消息队列中去。而应用程序需要有自己的消息队列,也就是线程消息队列,每一个线程有自己的消息队列,对于多线程的应用程序就有和线程数目相等的线程消息队列。winsows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口,不断循环直到程序退出。这个循环就是靠消息环(while(GetMessage()) TranslateMessage();DispatchMessage(); 实现的.GetMessage()只是从线程消息中取出一条消息,而DispatchMessage 则把取出的消息发送到目的窗口。如果收到WM_CLOSE消息则结束循环,发送postqiutmessage(0),处理WM_DESTROY销毁窗口!

其实问题的关键在于DispatchMessage到底干了什么 如果只是去调用相应的窗口,那自己写个switch不就可以了。DispatchMessage与switch不同之处在于DispatchMessage会先调用windows,进入管态(大概是range 0),然后再由windows调用窗口的函数。 为什么这么麻烦? 因为这样windows就可以知道你的程序运行到什么情况了, windows来调用你的窗口,这样你的窗口返回的时候windows就知道你已经处理过一个消息了,如果没有新的消息进入消息队列windows就不再会给你的进程分配时间片如果是你自己写switch的话,windows就不可能这样灵活的分配时间资源利用率就会降低那么还要消息循环干什么,windows直接把消息发给窗口不就可以了吗?因为你要在消息循环里把KEY_DOWN和KEY_UP组合成WM_CHAR,还可以直接屏蔽掉许多对你来说无用的消息,加快速度。

GetMessage: 从线程的消息队列取出一个消息   TranslateMessage: 将msg结构传给Windows,进行一些转换,比如A键按下,转换成WM_CHAR消息等   DispatchMessage():再将msg结构传给Windows,Windows将该消息发给窗口过程,由窗口过程处理.

TranslateMessage是对一些键盘事件做预处理。GetMessage是从系统为每个应用程序自动分配的消息对列的头部得到一个消息。

TranslateMessage是翻译需要翻译的消息

DispatchMessage()则会把翻译好的消息发送到系统的消息处理函数中,而这个函数又会把这个消息传    递到注册窗体时用户指定的消息处理函数中翻译消息不是简单的转换,一个消息被翻译后,可能会产生几个消息。

问题:

系统是如何把一个消息发送到线程消息队列的?

每个程序只有一个UI线程。

Win32 编程 基础的更多相关文章

  1. (转)Windows驱动编程基础教程

    版权声明     本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...

  2. win32编程简介

    win32编程简介 复习Win32整理下知识. 为什么学习win32? 我们要编写windos程序.都离不开API. 也就是我们所说的win32程序. 所以学好win32是你能不能再windows下编 ...

  3. 《网络安全编程基础》之Socket编程

    <网络安全编程基础>之Socket编程 我的代码 server.c // server.cpp : Defines the entry point for the console appl ...

  4. 第二章 Matlab面向对象编程基础

    DeepLab是一款基于Matlab面向对象编程的深度学习工具箱,所以了解Matlab面向对象编程的特点是必要的.笔者在做Matlab面向对象编程的时候发现无论是互联网上还是书店里卖的各式Matlab ...

  5. [.net 面向对象编程基础] (1) 开篇

    [.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...

  6. Android开发4: Notification编程基础、Broadcast的使用及其静态注册、动态注册方式

    前言 啦啦啦~(博主每次开篇都要卖个萌,大家是不是都厌倦了呢~) 本篇博文希望帮助大家掌握 Broadcast 编程基础,实现动态注册 Broadcast 和静态注册 Broadcast 的方式以及学 ...

  7. T-Sql编程基础

    T-sql编程 入门小游戏 T-sql编程基础,包括声明变量,if判断,while循环,以及使用一些基本函数. 记得在学校的时候,写过一个二人对打的文字输出游戏. 上代码 alter proc usp ...

  8. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  9. 如何夯实(Java)编程基础,并深入学习和提高

    如何夯实(Java)编程基础,并深入学习和提高? 240赞同反对,不会显示你的姓名 匿名用户 240 人赞同 多学习...网上自学的学习网站很多,见以下榜单~一.汇总榜单: 公开课_学习网站导航 收录 ...

随机推荐

  1. require是什么?能做什么

    本来是做后端的,拿到一个偏前端的项目,js文件里好多define和require,看的有点蒙,只能自己动手查找资源了,了解这到底是个什么,它能做什么? 1.什么是require.js? 1):requ ...

  2. WinMain lpCmdLine

    int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE, LPSTR lpCmdLine, int){ //命令行参数 TCHAR pCommandLine[2 ...

  3. RocketMQ和Kafka的差异对比

    Broker差异 主从差异: kafka的master/slave是基于partition维度的,而rocketmq是基于broker维度的:kafka的master/slave是可以切换的,而roc ...

  4. java笔记1-面向对象思想

    合适的方法放在合适的类之中. 设计中,分解出应该具有哪些对象(面向对象),不要再想步骤了(这是面向过程).设计过程: step1:问题中有哪些类和对象(找名词,之后区分是类还是属性) step2:这些 ...

  5. Java——静态代理、动态代理

    https://blog.csdn.net/giserstone/article/details/17199755 代理的作用:业务类只需要关注业务逻辑本身,保证了业务类的重用性 一 静态代理 特点: ...

  6. EF Core命令

    新建 Add-Migration init Update-Database init 修改model后,执行迁移的命令 更新数据库 每次更新都要{update}修改 Add-Migration {up ...

  7. SharpCompress 压缩解压

    public class SharpCompressHelper { public static void UnRAR(string srcUrl,string targetUrl) { using ...

  8. sublime text怎么格式化PHP代码

    手动安装: 可能由于各种原因,无法使用代码安装,那可以通过以下步骤手动安装Package Control: 1.点击Preferences > Browse Packages菜单 2.进入打开的 ...

  9. 2018 焦作网络赛 L Poor God Water ( AC自动机构造矩阵、BM求线性递推、手动构造矩阵、矩阵快速幂 )

    题目链接 题意 : 实际上可以转化一下题意 要求求出用三个不同元素的字符集例如 { 'A' .'B' .'C' } 构造出长度为 n 且不包含 AAA.BBB CCC.ACB BCA.CAC CBC ...

  10. Linux命令-磁盘管理(一)

    Linux命令-磁盘管理(一) Linux cd命令 Linux cd命令用于切换当前工作目录至 dirName(目录参数). 其中 dirName 表示法可为绝对路径或相对路径.若目录名称省略,则变 ...