友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
VC语言6.0程序设计从入门到精通-第41部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
实例 10…2:界面汉化实例。源代码在光盘中“10实例 10…2”目录下。
本节以创建一个默认语种为简体中文的 Languages 应用程序为例,进一步详细说明。该
程序不含任何资源,应用程序根据系统的语种设置连接对应的资源链接库,以完成对中文和
英文两种语言的支持。
附带光盘中的 chinese。dll 和 english。dll 两个动态链接库分别封装了中文资源和英文资源,
下面具体介绍 Languages 应用程序的实现过程。
1.创建 Languages
用 MFC AppWizad(exe)创建新项目的工作区,选择 Simple Document 类型、中国中文(其
他的选项选择默认) ,并且为了明确,将工作区目录改为“多语种支持”。
2 .添加数据成员
由于要动态地装入资源链接库,所以需要保存链接库的句柄以便在程序结束的时候释放
·267 ·
…………………………………………………………Page 279……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
资源。将下述数据成员添加到 CLanguagesApp 类中,代码如下:
protected:
//资源链接库句柄
HINSTANCE m_hLangDLL;
3 .修改 InitInstance() 函数
应用程序需要判别系统的默认语种,并装入对应的资源链接库。将下面的代码加到
InitInstance 函数中,代码如下:
BOOL CLanguagesApp::InitInstance()
{
AfxEnableControlContainer();
// 判定系统默认语种
WORD wLangPID=PRIMARYLANGID(::GetSystemDefaultLangID());
// 载入资源动态链接库
switch( wLangPID)
{
case LANG_CHINESE:
m_hLangDLL=::LoadLibrary(〃chinese。dll〃);
break ;
default:
m_hLangDLL=::LoadLibrary(〃english。dll〃);
break;
}
if(!m_hLangDLL)
{
AfxMessageBox(_T(〃无法装载资源链接库!〃)) ;
return FALSE ;
}
// 连接资源
AfxSetResourceHandle(m_hLangDLL) ;
……
}
其中,操作系统所使用的默认语种由 Win 32 函数 GetSystemDefaultLangID 取得。宏
PRIMARYLANGID 取出主语言标识符进行判断,以正确选择应该调用的链接库。链接库的
加载由 Win32 函数 LoadLibrary 实现。程序中所使用的资源库由 AfxSetResourceHandle 函数
指定。
4 .处理 ExitInstance() 函数
程序退出时使用 Win 32 函数 FreeLibrary 卸载已经装入的动态链接库。将下列代码添加
到 ExitInstance 函数中,代码如下:
·268 ·
…………………………………………………………Page 280……………………………………………………………
第 10 章 动态链接库
int CLanguagesApp::ExitInstance()
{
//释放资源链接库
if(m_hLangDLL)
AfxFreeLibrary(m_hLangDLL);
return CWinApp::ExitInstance();
}
5 .修改 OnDraw
为了说明是从资源链接库中动态地获取数据而不是从程序的执行体中获取,该程序从资
源链接库中获取了一个字符串,并绘制在屏幕上。代码如下:
void CLanguagesView::OnDraw(CDC* pDC)
{
CLanguagesDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CString strMsg;
strMsg。LoadString(IDS_HELLO);
pDC…》TextOut(60;15;strMsg);
// TODO: add draw code for native data here
}
6 .从项目中移走 Languages。rc 文件
因 为 Languages 自 身 并不 需 要 含 有 任 何 资 源 , 所 以 可 以从 项 目 列 表 文 件 中 移 走
Languages。rc 文件(并不删除)。ClassWizad 不允许项目不包含资源文件,可以创建一个空资
源文件并将其加入到项目中,然后重建信息文件(Languages。CLW ),使得 ClassWizad 可以继
续管理程序的消息处理 。但在本例中所有的函数都已经加入,可不必为项目创建空资源文件。
7 .建立项目
修 改 设 置 , 选 择 “ Project| Setting … ” 菜 单 命 令 , 在 Link 标 签 下 将 输 出 文 件 名
DebugLanguages。exe 改为 Languages。exe 。编译项目,如果应用程序中没有任何资源,会出
现找不到资源链接库的错误,下面的一系列步骤为本项目分别创建简体中文和美国英语的资
源链接库。在这两个链接库建立后,把它们放到 Languages 项目目录中,程序就可以运行了。
建立中文资源链接库的主要步骤如下。
o 选择 Regular DLL…based 应用程序并单击“Finish ”按钮完成创建。动态链接库项目只
包含资源,不需要其他文件,所以从项目中删除所有其他文件。
o 把 Languages 相关的资源文件拷贝到 Language_chinese 项目的对应目录下。
o 把 Languages。rc 加入到 Language_chinese 项目中,使得 Languages。rc 为项目中的惟一
文件。
o 在串资源表(String Table)中添加串 IDS_HELLO=200 ,标题为“这是中文版 !!”。
·269 ·
…………………………………………………………Page 281……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
o 从 Project 菜单中选择“Setting…”选项。首先,将输出文件名DebugLanguage_chines
e。dll 改为。。chinese。dll,将动态链接库直接建立在 Languages 项目目录下。然后在链接
命令行中添加“/NOENTRY ”选项。最后,编译并建立动态链接库。
生成英文版资源文件最快捷的方法是创建一个基于英文版的临时项目,并把资源文件复
制到英文链接库项目中。其处理方法与中文资源链接库类似。
注意:在修改资源组件设置时,不但要将 Project 菜单 Setting 对话框中 Resource 标签的默认文字
改为“英语(美国)”,还要删除预处理定义中的“_AFXDLL ”。删除_AFXDLL 预处理器,
可以使用户的链接库包含通用的 MFC 资源。否则,应用程序会从系统安装的 MFC 动态链
接库中收集通用的 MFC 资源,应用程序特定资源会被本地化。
这样,应用程序和动态链接库都成功地建立完毕,Languages 应用程序将根据操作系统
/英文版的应用程序运行结果分别如图
的不同版本来决定是加载中文资源还是英文资源。中文
10…6 和图 10…7 所示。
图 10…6 汉化的中文版应用程序界面
图 10…7 英文版的应用程序界面
·270 ·
…………………………………………………………Page 282……………………………………………………………
第 10 章 动态链接库
10。7 使用钩子(Hook )函数
Windows 系统是建立在事件驱动的机制上的,即整个系统都是通过消息的传递来实现的。
而钩子是 Windows 系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消
息,然后完成普通应用程序难以实现的功能。钩子可以监视系统或进程中的各种事件消息,
截获发往目标窗口的消息并进行处理。这样,就可以在系统中安装自定义的钩子,监视系统
中特定事件的发生,完成特定的功能,比如截获键盘/ 鼠标的输入、屏幕取词、日志监视等。
可见,利用钩子可以实现许多特殊而有用的功能。因此,对于高级编程人员来说,掌握钩子
的编程方法是很有必要的。
10。7。1 钩子函数的类型
1.按事件类型分类
按事件分类,钩子函数有如下几种常用类型。
o 键盘钩子和低级键盘钩子可以监视各种键盘消息;
o 鼠标钩子和低级鼠标钩子可以监视各种鼠标消息;
o 外壳钩子可以监视各种 Shell 事件消息。比如启动和关闭应用程序;
o 日志钩子可以记录从系统消息队列中取出的各种事件消息;
o 窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。
下面对常用的 Hook 类型进行介绍:
(1)WH_CALLWNDPROC 和 WH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC 和 WH_CALLWNDPROCRET Hooks 可以监视发送到窗口过
程的消息。系统在消息发送到接收窗口过程之前调用 WH_CALLWNDPROC Hook 子程,
并 且 在 窗 口 过 程 处 理 完 消 息 之 后 调 用 WH_CALLWNDPROCRET Hook 子 程 。
WH_CALLWNDPROCRET Hook 传递指针到 CWPRETSTRUCT 结构,再传递到 Hook 子程。
CWPRETSTRUCT 结构包含了来自处理消息的窗口过程的返回值,同样也包括了与这个消息
关联的消息参数。
(2 )WH_CBT Hook
在如下事件之前,系统都会调用 WH_CBT Hook 子程。
o 激活、建立、销毁、最小化、最大化、移动、改变尺寸等窗口事件。
o 完成系统指令。
o 来自系统消息队列中的移动鼠标、键盘事件。
o 设置输入焦点事件。
o 同步系统消息队列事件。
o Hook 子程的返回值确定系统是否允许或者防止这些操作中的一个。
·271 ·
…………………………………………………………Page 283……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
(3 )WH_DEBUG Hook
在系统调用系统中与其他 Hook 关联的 Hook 子程之前,系统会调用 WH_DEBUG Hook
子程。可以使用这个 Hook 来决定是否允许系统调用与其他 Hook 关联的 Hook 子程。
(4 )WH_FOREGROUNDIDLE Hook
当应用程序的前台线程处于空闲状态时,可以使用 WH_FOREGROUNDIDLE Hook 执行
低 优 先 级 的 任 务 。 当 应 用 程 序 的 前 台 线 程 要 变 成 空 闲 状 态 时 , 系 统 就 会 调 用
WH_FOREGROUNDIDLE Hook 子程。
(5 )WH_GETMESSAGE Hook
应用程序用 WH_GETMESSAGE Hook 来监视从 GetMessage 或者 PeekMessage 函数返回
的消息。可以使用 WH_GETMESSAGE Hook 去监视鼠标和键盘输入,以及其他发送到消息
队列中的消息。
(6 )WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook 使应用程序可以插入消息到系统消息队列。可以使用
该 Hook 回放用 WH_JOURNALRECORD Hook 记录下来的连续的鼠标和键盘事件。只要
WH_JOURNALPLAYBACK Hook 已 经 安 装 , 正 常 的 鼠 标 和 键 盘 事 件 就 是 无 效 的 。
WH_JOURNALPLAYBACK Hook 是全局 Hook ,它不能像线程特定 Hook 一样使用。
WH_JOURNALPLAYBACK Hook 返回超时值,这个值告诉系统在处理来自回放 Hook 当前消
息 之 前 需 要 等 待 多 长 时 间 ( 毫 秒 )。 这 就 使 Hook 可 以 控 制 实 时 事 件 的 回 放 。
WH_JOURNALPLAYBACK 是 system…wide local hooks,它们不会被映射到任何进程的地址空
间中。
(7 )WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook 用来监视和记录输入事件。可以使用这个 Hook 记录连续的
鼠 标 和 键 盘 事 件 , 然 后 通 过 使 用 WH_JOURNALPLAYBACK Hook 来 回 放 。
WH_JOURNALRECORD Hook 是 全 局 Hook , 它 不 能 像 线 程 特 定 Hook 一 样 使 用 。
WH_JOURNALRECORD 是 system…wide local hooks,它们不会被映射到任何进程的地址空
间中。
(8)WH_KEYBOARD Hook
在应用程序中,WH_KEYBOARD Hook 用来监视 WM_KEYDOWN 和 WM_KEYUP 消
息,这些消息通过 GetMessage 或 PeekMessage function 返回。可以用该 Hook 来监视输入到
消息队列中的键盘消息。
(9 )WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook 监视输入到线程消息队列中的键盘消息。
(10)WH_MOUSE Hook
WH_MOUSE Hook 监视从 GetMessage 或者 PeekMessage 函数中返回的鼠标消息。使用
这个 Hook 监视输入到消息队列中的鼠标消息。
(11)WH_MOUSE_LL Hook
WH_MOUSE_LL Hook 监视输入到线程消息队列中的鼠标消息。
·272 ·
…………………………………………………………Page 284……………………………………………………………
第 10 章 动态链接库
(12)WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks 可以监视菜单、滚动条、消息框、对
话框消息并且发现用户使用 ALT+TAB 或者 ALT+ESC 组合键切换窗口。WH_MSGFILTER
Hook 只能监视传递到菜单、滚动条、消息框的消息,以及传递到通过安装了 Hook 子程的应
用 程 序 建 立 的 对 话 框 的 消 息 。 WH_SYSMSGFILTER Hook 监 视 所 有 应 用 程 序 消 息 。
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks 可以在模式循环期间过滤消息,这等价于
在主消息循环中过滤消息。通过调用 CallMsgFilter function 可以直接调用 WH_MSGFILTER
Hook 。通过使用这个函数,应用程序能够在模式循环期间使用相同的代码去过滤消息,如同
在主消息循环里一样。
(13)WH_SHELL Hook
外壳应用程序可以使用 WH_SHELL Hook 去接收重要的通知。当外壳应用程序为激活状
态并且当顶层窗口建立或者销毁时,系统调用 WH_SHELL Hook 子程。WH_SHELL 共有 5
种情況:
o 只要有 top…level 、unowned 窗口被产生、起作用、或是被摧毁;
o 当 Taskbar 需要重画某个按钮;
o 当系统需要显示关于 Taskbar 的一个程序的最小化形式;
o 当目前的键盘布局状态改变;
o 当使用者按 Ctrl+Esc 去执行 Task Manager (或相同级别的程序)。
按照惯例,外壳应用程序都不接收 WH_SHELL 消息。所以在应用程序能够接收
WH_SHELL 消息之前,应用程序必须调用 SystemParametersInfo function 注册它自己。
2 .按使用范围分类
按使用范围分类,主要有线程钩子和系统钩子。线程钩子监视指定线程的事件消息,系
统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所
DLL )中。
以钩子函数必须放在独立的动态链接库(
o 如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会
自动先调用线程钩子,然后调用系统钩子。
o 对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩
子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开
始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。
o 钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装
钩子,在使用完毕后要及时卸载。
10。7。2 使用钩子函数
使用钩子函数的程序的步骤分为定义钩子函数、安装钩子和卸载钩子这 3 步。下面详细
介绍这 3 个过程。
·273 ·
…………………………………………………………Page 285……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
1.定义钩子函数
钩子函数是一种特殊的回调函数 。钩子监视的特定事件发生后,系统会调用钩子函数进
行处理。不同事件的钩子函数的形式是各不相同的。下面以鼠标钩子函数举例说明钩子函数
的原型:
LRESULT CALLBACK HookProc(int nCode ;WPARAM wParam;LPARAM lParam)
参数 wParam 和 lParam 包含所钩消息的信息,比如鼠标位置/状态、键盘按键等。nCode
包含有关消息本身的信息,比如是否从消息队列中移出。
先在钩子函数中实现自定义的功能,然后调用函数 CallNextHookEx。把钩子信息传递给钩
子链的下一个钩子函数。CallNextHookEx。 的原型如下:
LRESULT CallNextHookEx(HHOOK hhk; int nCode; WPARAM wParam; LPARAM lParam)
参数 hhk 是钩子句柄。nCode 、wParam 和 lParam 是钩子函数。
也可以通过直接返回 TRUE 来丢弃该消息,阻止该消息的传递。
2 .安装钩子
在程序初始化的时候,调用函数 SetWindowsHookEx 安装钩子。其函数原型为:
HHOOK SetWindowsHookEx(int idHook;HOOKPROC lpfn; INSTANCE hMod;DWORD dwThreadId)
参数 idHook 表示钩子类型,它是和钩子函数类型一一对应的。比如 WH_KEYBOARD
表示安装的是键盘钩子,WH_MOUSE 表示是鼠标钩子等。Lpfn 是钩子函数的地址。HMod
是钩子函数所在的实例的句柄。对于线程钩子,该参数为 NULL ;对于系统钩子,该参数为
钩子函数所在的 DLL 句柄。dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,
该参数为 NULL 。SetW
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!