《windows环境下32位汇编语言程序设计》

下载本书

添加书签

windows环境下32位汇编语言程序设计- 第73节


按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!

            invoke  SendMessage;hWinEdit;EM_STREAMIN;SF_TEXT;addr @stES

程序中流入和流出操作的回调函数使用同一个子程序,通过设置EDITSTREAM结构的自定义值dwCookie字段来表示进行的是流入还是流出的操作,子程序中通过判断dwCookie参数是TRUE还是FALSE来决定进行读文件还是写文件的操作(读写文件的函数ReadFile和WriteFile的用法请参考第10章)。



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第9章 通用控件


9。4 使用Richedit控件(9)

    
5。 查找和替换

在Richedit控件中可以通过发送EM_FINDTEXT或者EM_FINDTEXTEX消息来完成查找字符串的功能,EM_FINDTEXTEX消息是EM_FINDTEXT消息的扩展,它们的用法是:

invoke  SendMessage;hWinEdit;EM_FINDTEXT;uFlags;lpFindText

invoke  SendMessage;hWinEdit;EM_FINDTEXTEX;uFlags;lpFindTextEx

消息的wParam参数中的uFlags指定查找的选项,它可以是以下取值的组合:

●   FR_DOWN(2。0版本及以上使用)——向后查找,不设置的话表示向前查找。

●   FR_MATCHCASE——查找字符串区分大小写。

●   FR_WHOLEWORD——匹配整个单词。

EM_FINDTEXT的lParam参数指向一个FINDTEXT结构,而EM_FINDTEXTEX消息的lParam参数指向一个FINDTEXTEX结构,这两个结构的定义如下:

FINDTEXT STRUCT

  chrg              CHARRANGE    ;查找区域

  lpstrText        DWORD      ?   ;查找字符串地址

FINDTEXT ENDS

FINDTEXTEX STRUCT

  chrg              CHARRANGE   ;查找区域

  lpstrText        DWORD      ?   ;查找字符串地址

  chrgText         CHARRANGE   ;如果找到则在这里返回找到文字的起始/结束位置

FINDTEXTEX ENDS

可以看出,EM_FINDTEXTEX消息的扩展之处在于直接在chrgText字段中返回找到文字的区域,程序可以马上使用这个区域数据进行其他操作,而EM_FINDTEXT消息必须根据找到的位置和查找字符串的长度自己计算这个区域。

两个消息的返回值是一样的,如果没有找到指定文字则返回?1,否则返回找到文字的起始位置。例子程序在_FindText子程序中完成查找功能,这个子程序分别在“查找下一个”、“查找上一个”和“查找文字”通用对话框的自定义消息中被调用,子程序中通过下面的代码来设置查找区域:

    invoke  SendMessage;hWinEdit;EM_EXGETSEL;0;addr @stFindText。chrg

    。if     stFind。Flags & FR_DOWN

            push        @stFindText。chrg。cpMax

            pop     @stFindText。chrg。cpMin

    。endif

    mov     @stFindText。chrg。cpMax;…1

当找到一个匹配字符串后,字符串被设置为选择区域,如果向下继续查找下一个的话,必须将这个选择区域的结束位置用做下一次查找的起始点,所以程序发送EM_EXGETSEL消息获取选择区域并将cpMax字段放到cpMin字段中,并将cpMax字段设置为…1,表示一直查找到全部文本的最后。

在第8章中已经有所介绍:“查找文字”通用对话框使用FINDREPLACE结构,不知道是巧合还是Microsoft的故意安排,FINDREPLACE结构中的Flags字段和EM_FINDTEXTEX消息中的wParam参数的标志定义是一样的,所以程序直接取出Flags字段,然后屏蔽掉FR_MATCHCASE,FR_DOWN和FR_WHOLEWORD等不需要使用的标志以后,就可以直接在消息的wParam参数中使用了:

    mov     ecx;stFind。Flags

    and     ecx;FR_MATCHCASE or FR_DOWN or FR_WHOLEWORD

    invoke  SendMessage;hWinEdit;EM_FINDTEXTEX;ecx;addr @stFindText

找到字符串以后,进行替换操作就不是一件复杂的事情了,因为FINDTEXTEX结构的chrgText字段中已经返回了找到文本的起始和结束位置,将它设置为选择区域以后就可以通过发送EM_REPLACESEL消息进行替换操作了。

9。4。3  Richedit控件的通知消息

Richedit控件也可以向父窗口发送多种通知消息,使用“可以”一词的意思是,控件在默认状态下并不发送通知消息,如果需要控件发送某个消息,必须首先对控件进行设置。通过向Richedit控件发送EM_SETEVENTMASK消息可以激活需要的通知消息:

    invoke  SendMessage;hWinEdit;EM_SETEVENTMASK;0;dwMask

dwMask是事件掩码,可以是下面标志的组合,分别代表激活不同的通知消息:

●   ENM_CHANGE——允许EN_CHANGE通知码,本消息在用户的操作可能改变控件中的文本的时候发送。

●   ENM_CORRECTTEXT——允许EN_CORRECTTEXT通知码。

●   ENM_DRAGDROPDONE——允许EN_DRAGDROPDONE通知码,本消息在用户完成了一个拖放操作后发送。

●   ENM_DROPFILES——允许EN_DROPFILES通知码,本消息在用户将一个文件拖放进控件后发送。

●   ENM_KEYEVENTS——允许为键盘消息发送EN_MSGFILTER通知码。

●   ENM_MOUSEEVENTS——允许为鼠标消息发送EN_MSGFILTER通知码。

●   ENM_PROTECTED——允许发送EN_PROTECTED通知码。

●   ENM_SCROLL——允许发送EN_HSCROLL和EN_VSCROLL通知码。

●   ENM_SCROLLEVENTS——允许为鼠标滑轮发送EN_MSGFILTER通知码。

●   ENM_SELCHANGE——允许发送EN_SELCHANGE通知码,本消息在选择区域改变以后发送(包括光标位置改变)。

●   ENM_UPDATE——允许发送EN_UPDATE通知码,本消息在控件将要显示被改变的文本之前发送。

当这些通知消息被激活的时候,父窗口就可以收到包含相应通知码的WM_NOTIFY消息。一般来说,将控件设置为仅发送程序感兴趣的通知消息,如当在Richedit控件中按下右键需要弹出一个菜单的时候,需要检测鼠标消息,那么就需要指定ENM_MOUSEEVENTS标志;另外,如果需要随时检测选择区域的状态,以便随时设置工具栏中“拷贝”与“剪切”等按钮的状态,那么就要使用ENM_SELCHANGE标志,这样光标一移动或者选择区域一改变,父窗口就可以收到EN_SELCHANGE通知码,于是程序就可以在WM_NOTIFY消息中随时改变工具栏上各按钮的状态。

由于Richedit。asm例子中没有使用工具栏,所以没有对通知消息进行示例,有兴趣的读者可以查看所附光盘的Chapter09Wordpad目录中的例子文件,这个例子中使用工具栏和状态栏等控件,需要随时显示光标位置等信息,程序中就包含了处理通知消息的代码。



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第9章 通用控件


9。5 窗口的子类化(1)

    
9。5。1  什么是窗口的子类化

在使用控件的过程中,常常会遇到这样一种情况:我们需要一种窗口,它和某种现成的控件提供的功能很相似,如果使用现成控件的话,那么控件几乎能提供所有需要的功能,仅我们要求的某个细节无法实现。举例来说,要编写一个16进制与10进制的转换程序,程序中需要两个编辑控件来输入数值,输入10进制数值可以使用现成的Edit控件,只要指定ES_NUMBER风格就能让编辑框只能输入数字0~9,但输入16进制数值的时候就不行了,因为指定ES_NUMBER风格的话就无法输入A~F,不指定的话用户就可能输入0~9和A~F之外的东西,那么该如何处理呢?

解决的办法有两种,第一种当然是自己创建一个窗口类,然后在自己的窗口过程中完成所有的功能,这显然是一项费时又费力的工作,因为我们几乎要自己重新写一遍Edit控件的全部功能;第二种方法就是使用本节要介绍的窗口子类化,窗口子类化最适合做的就是这一类工作。

窗口子类化的含义是接管被子类化的控件窗口,以达到对它进行控制的目的。虽然控件的窗口过程被封装在Windows内部,无法对它进行直接修改,但只要能截获Windows给控件的窗口过程发送的消息,就能够控制控件窗口。以上面的要求为例,只要截获Windows向编辑控件发送的WM_CHAR消息,就能够根据需要丢弃包含非16进制字符的WM_CHAR消息,只把包含16进制字符的WM_CHAR转发给控件的窗口过程,这样编辑控件将根本收不到16进制字符之外的字符,我们的要求也就达到了。

控件窗口子类化的流程如图9。8所示。

子类化的操作并不局限于控件窗口,实际上任何窗口都可以子类化。但是对于应用程序自身使用的窗口类来说,它的控制权本来就是100%属于应用程序自身的,要实现某种功能就直接修改源代码好了,没有必要再进行一个子类化的过程,所以子类化的操作往往是对“黑匣子”类型的控件窗口进行的。


图9。8  窗口子类化的工作原理

9。5。2  窗口子类化的实现

窗口子类化的要点是截获窗口的窗口过程,如何实现这一点呢?每个窗口的内部都保存有它所属的窗口类的WNDCLASSEX 结构,结构中的lpfnWndProc字段指出了窗口过程的地址,如果能用自己的窗口过程地址来替换这个地址,那么Windows就会把消息发送到自定义的窗口过程中来了。通过调用函数SetWindowLong可以实现这个功能,SetWindowLong函数的用法是这样的:

    invoke  SetWindowLong;hWnd;nIndex;dwNewLong

    mov dwOldLong

hWnd参数指定要子类化窗口的窗口句柄,nIndex参数指定需要修改窗口的哪个属性,它可以是以下的取值:

●   GWL_EXSTYLE——窗口的扩展风格。

●   GWL_STYLE——窗口风格。

●   GWL_WNDPROC——窗口过程地址(这就是我们需要的)。

●   GWL_HINSTANCE——窗口所属的模块实例句柄。

●   GWL_ID——窗口ID。

●   GWL_USERDATA——窗口附带的32位自定义数值。

 dwNewLong参数指定新的属性值。如果nIndex为GWL_WNDPROC,dwNewLong表示新的窗口过程地址;如果nIndex为GWL_STYLE,dwNewLong则表示新的窗口风格,依此类推。函数的返回值是指定属性的原先数值。当函数用于窗口子类化的时候,在nIndex参数中使用GWL_WNDPROC,以便将窗口过程地址设置到自定义的子程序中,这时函数返回的是控件窗口原来的窗口过程地址,由于窗口子类化的出发点就是为了尽量使用控件窗口原有的功能,程序为了“偷懒”而不去处理的大部分消息还要靠原来的窗口过程来处理,所以这个地址必须被保存下来。

让我们通过一个简单的例子来演示窗口子类化的实现过程,程序实现的就是前面介绍的16进制与10进制转换的程序,源代码位于所附光盘的Chapter09SubClass目录中。程
小提示:按 回车 [Enter] 键 返回书目,按 ← 键 返回上一页, 按 → 键 进入下一页。 赞一下 添加书签加入书架