(一)MiniGUI的各种消息的区别
MiniGUI中的消息种类通常可分为系统消息、对话框消息、窗口绘制消息、窗口创建和销毁消息、键盘和鼠标(后处理)消息以及用户自定义消息。
总结使用消息时需注意的问题:
1. PostMessage和SendMessage函数的区别即前者将消息置于指定窗口的消息队列后便返回,通常用于发送一些非关键性信息(如键盘和鼠标消息),而后者则是通知指定窗口的窗口过程立即完成某项任务后才返回.“PostMessage是非阻塞的,而SendMessage是阻塞的。结和源码说明,为什么SendMessage是阻塞的。注意:SendMessage有两种工作模式”
通过阅读PostMessage和SendMessage的实现源码,在MiniGUI-Threads运行模式下,PostMessage仅把消息添加至消息队列即返回成功(消息队列满或没有消息队列时都会立即返回相应的信息,故为非阻塞的);而SendMessage当处理的消息在同一线程内时立即将调用窗口过程或桌面过程处理函数,当处理的消息不在同一线程时将会调用SendasyncMessage来处理,这个函数会使发送线程将阻塞(等待接收线程处理的结果)。
源码见minigui-1.6.2/src/kernel/message.c 。
SendMessage是同步消息,但是有同线程同步消息和异线程同步消息。牢记这个概念,对以后的调试有用。
2. 定时器消息
(MSG_TIMER)是优先级最低的消息类型,只有消息队列中不存在其他类型的消息时,系统才会去检查是否定时器到期。
通过阅读minigui源码message.c文件,总结出消息的优先级如下:(由高至低)
Timer消息的确是优先级最低的,这也是MMI部分不能通过MSG_TIEMR来实现照相机延迟拍摄、秒表、录音时间统计等功能。
MSG_QUIT< MSG_NOTIFY< MSG_SYNC(包括MSG_COMMAND、MSG_INITDIALOG、 MSG__SETTEXT、MSG_GETTEXT、MSG_FONTCHANGED、MSG_CREATE、MSG_NCCREATE、MSG_DESTROY、MSG_CLOSE等)<MSG_PAINT< MSG_POST(包括MSG_KEYDOWN、MSG_CHAR、MSG_LBUTTONDOWN、MSG_MOUSEMOVE等) < MSG_TIMER。
响应顺序是:
MSG_QUIT < SYNCMSG < NOTIFYMSG < POSTMSG < MSG_PAINT < MSG_TIMER
上述内容只有三种明确消息是摆明优先级的,其他的大多跟发送消息的类型有关。同时,需要明白SYNCMSG是怎么造成的。
3. SendNotifyMessage函数和PostMessage类似,即不等待消息被处理就返回,但其不同在于该函数发送的消息不会因缓冲区满而丢失。
SendNotifyMessage为什么不会丢失?而PostMessage又为什么会丢失。
原因:SendNotifyMessage中的消息存放在一个链式消息队列中,从而消息队列空间可以根据需要不断增加(在系统内存允许的前提下),所以其消息不会丢失;PostMessage中的消息存放在一个循环消息队列(大小固定的循环缓冲区)中,当队列空间满时PostMessage函数采取的策略是丢弃新的消息并返回post消息队列满的信息,所以PostMessage会丢失。
4. Minigui针对控件的通知消息处理引入了SetNotificationCallback函数,该函数可以为控件设置一个通知消息的回调函数,当控件有通知消息时,将调用该函数,而不是发送通知消息到父窗口。
5. 当钩子回调函数是在桌面线程中执行时,不能在该回调函数中向其他线程以SendMessage方式发送消息。
6. 关于消息的优先级,SendMessage发出的消息应该是优先级最高的,其次是SendNotifyMessage发出的消息,最后是PostMessage发出的消息,在PostMessage的所有消息中又以定时器消息的优先级最低。
几个重要消息的使用意义:
1.MSG_NCCREATE :处理该消息时不能使用GetDC等函数获得该窗口的设备上下文,也不能在MSG_NCCREATE消息中建立子窗口。(原因:该消息在minigui建立主窗口的过程中被发送,此时窗口对象未建立。对于输入法窗口,必须在该消息处理中注册)。
2.MSG_SIZECHANGING:通过改变该消息的默认处理,可使消息窗口尺寸固定。
3.MSG_CREATE:通过判断该消息的返回值,可确定窗口创建/添加操作是否成功。
4.MSG_FONTCHANGING:若窗口不允许用户改变默认字体,则截获该消息并返回非零值。
5.MSG_FONTCHANGED:窗口过程收此消息后,就可以进行一些处理一反映出新的字体设置。
6.MSG_PAINT:该消息在窗口重绘时发送到窗口过程,应用程序在处理完该消息后应直接返回。
7.MSG_CLOSE:应用程序在响应该消息时调用DestroyMainWindow销毁主窗口。
8.MSG_ERASEBKGND:用于清除窗口背景,默认窗口过程是用背景色刷新窗口客户区,也可在消息处理中进行填充图片操作。
9.MSG_DESTROY:该消息用来通知系统销毁一个窗口。需注意的是在使用非模式对话窗口和普通主窗口时应遵循如下几个策略:a。应用程序应在MSG_DESTROY消息中销毁被托管主窗口的位图、字体等资源;b.在被托管主窗口响应MSG_CLOSE消息时,调用DestroyMainWindow函数并调用MainWindowCleanup函数;c.在托管主窗口中,处理MSG_CLOSE消息,并调用DestroyMainWindow函数。
注意b的内容,这一点我们目前经常会遗漏,造成内存泄露。请说明b释放了什么资源?
释放的是结构体PMAINWIN的空间,实际上就是HWND地址所指向的内容。可以结合CreateMainWindow看一下。
(二)HDC的各种创建方式、使用条件
在MiniGUI中设备上下文分为图形设备上下文、系统内存中的设备上下文和屏幕设备上下文三种。下面对上述几种设备上下文中HDC的创建方式和使用条件进行简要说明。
1. 图形设备上下文中HDC的创建方式和使用条件
a. 创建HDC的方式之一是通过BeginPaint函数,函数原型如下:
HDC GUIAPI BeginPaint(HWND hWnd);//实际通过调用GetClientDC函数实现
使用条件:此函数只能在处理MSG_PAINT的消息中调用
b. 创建HDC的方式也可通过GetDC\GetClientDC函数,函数原型如下:
HDC GUIAPI GetDC(HWND hwnd);//所获取的设备上下文是针对整个窗口
HDC GUIAPI GetClientDC(HWND hwnd);//所获取的设备上下文是针对窗口客户区
使用条件:避免同时使用多个设备上下文,避免在递归中调用
c. 创建HDC还可通过CreatePrivateDC\CreatePrivateClientDC\GetPrivateClientDC函数(原型略)
使用注意:若建立主窗口时设定了WS_EX_USEPRIVATEDC风格则CreateMainWindow会自动为该窗口函数建立HDC,或控件类具有CS_OWNDC属性时属于该控件类的控件也将自动建立HDC。
在a、b、c所描述的HDC创建方式中,a、b中的HDC在使用完后需及时释放,而c“使用注意”中两种情况的HDC是伴随整个窗口生命期使用后不需另调用释放函数。
2. 系统内存中的设备上下文
创建方式是通过CreateCompatibleDC函数;函数原型:
HDC GUIAPI CreateCompatibleDC(HDC hdc).
屏幕设备上下文
MiniGUI在启动之后,就建立一个全局HDC。该DC用HDC_SCREEN标识,不需进行创建和释放操作。
HDC的复制使用:
在TD272的主菜单源码中函数lct_idle_wind_cnt_proc()和lct_idle_wallpaper_proc()处理消息MSG_PAINT时都通过函数CreateCompatibleDC()把“图形设备上下文”的HDC复制为“系统内存中的设备上下文”,这样做之后即在系统内存中建立一个类似显示内存的区域,然后在该区域进行图形操作,结束后再复制到显示内存。这种方式的意义在于绘图速度快、能减少直接操作显存可能造成的闪烁现象。
CreateCompatibleDC的使用的确可以避免闪烁,同时结合DC的复制,还可以实现显示的放大、缩小,甚至通过计时器还可以实现动画效果。当然,还有一些其他用途。
(三)字串显示风格
在MiniGUI中字串的显示可通过TextOutLen、TabbedTextOutLen、TabbedTextOutEx、DrawTextEx函数实现,下面依次说明各函数的功能。
TextOutLen:用来在给定位置输出指定长度的字符串。
TabbedTextOutLen:用来输出格式化字符串。
TabbedTextOutEx:用来输出格式化字符串,但可以指定字符中每个TAB键的位置
DrawTextEx:以不同的对齐方式在指定的矩形内部输出文本。
(四)窗口的创建方式和默认处理函数
窗口分为主窗口、对话框和控件三类,下面分别列出了三种窗口的创建原型和默认处理函数原型:
1. 主窗口
CreateMainWindow(MAINWINCREATE*);//创建主窗口
Int DefaultMainWinProc (HWND hWnd, int message, wPARAM wParam, LPARAM lParam);
2. 对话框
Int GUIAPI DialogBoxIndirectParam(PDLGTEMPLATE pDlgTemplate, HWND hOwner, WNDPROC DlgProc, LPARAM lParam);//创建模态对话框
HWND GUIAPI CreateMainWindowIndirect(PDLGTEMPLATE pDlgTemplate , HWND hOwner, WNDPROC DlgProc );//创建非模态对话框
Int DefaultDialogProc (HWND hWnd, int message, wPARAM wParam, LPARAM lParam);
它们最大的区别就在于:
模态对话框创建完毕之后会进行消息循环,即窗口不关闭、不销毁的话,软件代码是不会走到创建之后的。但是非模态对话创建完毕之后软件代码继续往下执行。
3. 控件
BOOL GUIAPI RegisterWindowClass(PWNDCLASS pWndClass);//注册控件类
Int GUIAPI CreateWindow(class_name, caption, style, id, x, y, w, h, parent, add_data);//创建控件
注:转载至此纯属学习积累,转载自博主jia0511的文章,地址http://blog.csdn.net/jia0511/article/details/8239404