Win32 编程 基础
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 编程 基础的更多相关文章
- (转)Windows驱动编程基础教程
版权声明 本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...
- win32编程简介
win32编程简介 复习Win32整理下知识. 为什么学习win32? 我们要编写windos程序.都离不开API. 也就是我们所说的win32程序. 所以学好win32是你能不能再windows下编 ...
- 《网络安全编程基础》之Socket编程
<网络安全编程基础>之Socket编程 我的代码 server.c // server.cpp : Defines the entry point for the console appl ...
- 第二章 Matlab面向对象编程基础
DeepLab是一款基于Matlab面向对象编程的深度学习工具箱,所以了解Matlab面向对象编程的特点是必要的.笔者在做Matlab面向对象编程的时候发现无论是互联网上还是书店里卖的各式Matlab ...
- [.net 面向对象编程基础] (1) 开篇
[.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...
- Android开发4: Notification编程基础、Broadcast的使用及其静态注册、动态注册方式
前言 啦啦啦~(博主每次开篇都要卖个萌,大家是不是都厌倦了呢~) 本篇博文希望帮助大家掌握 Broadcast 编程基础,实现动态注册 Broadcast 和静态注册 Broadcast 的方式以及学 ...
- T-Sql编程基础
T-sql编程 入门小游戏 T-sql编程基础,包括声明变量,if判断,while循环,以及使用一些基本函数. 记得在学校的时候,写过一个二人对打的文字输出游戏. 上代码 alter proc usp ...
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- 如何夯实(Java)编程基础,并深入学习和提高
如何夯实(Java)编程基础,并深入学习和提高? 240赞同反对,不会显示你的姓名 匿名用户 240 人赞同 多学习...网上自学的学习网站很多,见以下榜单~一.汇总榜单: 公开课_学习网站导航 收录 ...
随机推荐
- WIndows cmd command 指令总结
1. 文件操作 显示当前文件夹内所有文件 dir dir /s 仅显示特定后缀的文件 # 查找当前目录下所有mp3文件dir /s *.mp3
- Centos 7搭建Gitlab服务器以及操作(创建项目,创建群组,创建用户,添加密钥)
一. 安装并配置依赖包 在CentOS系统上安装所需的依赖:ssh,防火墙,postfix(用于邮件通知) ,wget,以下这些命令也会打开 系统防火墙中的HTTP和SSH端口访问 安装前准备 命令: ...
- selenium-Xpath使用方法
01:什么是Xpath Xpath是一门xml文档中查找信息的语言,Xpath可用来在xml文档中对元素和属性进行遍历,主流的浏览器都支持xpath,因为HTML页面在DOM中表示xhtml文档 xp ...
- 【转载】关于java 的InputStream和OutputStream的理解
关于InputStream和OutputStream的输入输出方向的理解 InputStream输入类,首先需要读取的内容转化成输入流,再从它那里进行读取,先关联源:之后过程中关联目的,这样形成了流: ...
- 使用vue写扫雷游戏
上班闲来没事做,,心血来潮.想用刚学的vue,写一个扫雷游戏..好了,直入正题. 第一步,先制作一个10x10的格子图..这个divcss就不说了..大家都会. 第二步,制造一个数组,用来生成随机雷区 ...
- WTL项目各种error的解决方法
error RC1015: cannot open include file 'atlres.h' 解决办法: 向“VC项目属性->资源->附加包含目录” 添加WTL的Include目录( ...
- MYSQL 大文件导出导入
1.导出sql文件 mysqldump --column-statistics=0 -uusername -ppassword -hyour server ip --default-characte ...
- [转] Linux环境变量配置文件以及启动顺序
转自:https://blog.csdn.net/bjnihao/article/details/51775854 一.环境变量配置文件: 对所有用户都起作用 /etc/profile /etc/pr ...
- CSS currentColor 变量
㈠currentColor定义及理解 来自MDN的解释:currentColor代表了当前元素被应用上的color颜色值. 使用它可以将当前这个颜色值应用到其他属性上,或者嵌套元素的其他属性上. 你这 ...
- (转)window.parent和window.opener区别
下面一段代码是关于window.parent和window.opener区别 来讲的,我们如果要用到iframe的值传到另一框架就要用到window.opener.document.getElemen ...