输入法注入原理

因为不懂,所以留个记号,方便大家一起查阅
都是转的,不要告我侵权
给你一篇转自vckbase的文章

 
首先我们需要明白输入法是什么东西。目前常用的输入法基本上有两种类型:外挂式(如早期的万能五笔)及输入法接口式(Input Method Editor-IME)。外挂式比较简单,就是一个exe文件,通过模拟一些Windows输入消息来给当前处于活动状态的编辑窗口输入文字,一个显著的优点是输入法只要启动一次,就可以在所有进程中使用;但缺点不不容忽视,首先实现起来也不容易,一个更大的不足是兼容性不够好,通常一个Windows版本需要一人对应的输入法版本,此外这类输入法为了能够截获用户输入,通常需要挂接键盘钩子,容易造成系统不稳定或者效率不高。大部分的输入法还是采用IME来实现,下面本文主要讨论一下IME编程需要注意的问题及解决办法。 

IME是什么?IME是在Windows平台上使用的标准的输入法接口规范。它实质是一个DLL,Windows为这个DLL定义一系列的接口,不同的接口实现指定的功能。程序员在编写输入法程序时只需要实现这些接口并导出就可以作为输入法使用。关于具体接口的定义不是本文的重点,如果您需要了解只需要在网络中搜索“输入法编程指南”就可以明白 ,更多信息参考MSDN。 

刚开始输入法编程最棘手的问题通常是程序框架搭好了却不知道如何使用及调试。这里涉及到一个很重要的问题就是输入法的安装。输入法就是Windows的一个插件,需要先进行注册,Windows才能识别并使用。为此您需要先将您生成的DLL复制到系统目录(WindowsSystem32)再调用API ImmInstallIME就可以实现了,在我的实践中是先编一个简单的程序来做安装工作,在每次输入法重新编译完成以后调用一次以完成输入法的注册。这里还有一个需要注意的问题是:Windows提供了一种机制,它允许输入法程序一旦启动就就不再退出,这就意味着如果你的程序代码经过修改需要重新安装时将不得不重新启动电脑。在IME定义的接口中有一个接口是提供IME的初始化的,它就是BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption),下面的代码来自我写的输入法: 


BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption)
{
lpIMEInfo-dwPrivateDataSize = sizeof(CONTEXTPRIV);系统根据它为INPUTCONTEXT.hPrivate分配空间
lpIMEInfo-fdwProperty = IME_PROP_KBD_CHAR_FIRST 
#ifdef _UNICODE
IME_PROP_UNICODE 
#endif
IME_PROP_SPECIAL_UI 
IME_PROP_END_UNLOAD ;

lpIMEInfo-fdwConversionCaps = IME_CMODE_FULLSHAPE 
IME_CMODE_NATIVE;
lpIMEInfo-fdwSentenceCaps = IME_SMODE_NONE;
lpIMEInfo-fdwUICaps = UI_CAP_2700;
lpIMEInfo-fdwSCSCaps = 0;
lpIMEInfo-fdwSelectCaps = SELECT_CAP_CONVERSION;
_tcscpy(lpszUIClass,CLSNAME_UI);
return TRUE;


lpIMEInfo-fdwProperty告诉Windows系统您编写的输入法的一些特征,注意一下IME_PROP_END_UNLOAD这个标志,有了它您编写的输入法会随着启动您的输入法的应用程序(如NotePad)的退出而退出,否则它将长驻于系统中,这也是为什么很多输入法在升级安装时需要首先重新启动电脑的原因。 

在这个接口中还有一点需要特别注意,那就是lpIMEInfo-dwPrivateDataSize,至少我是经过很多次测试才基本证实Windows根据该值为INPUTCONTEXT.hPrivate分配空间。此外如果您修改了这个接口,按照我个人的经验是需要重新调用ImmInstallIME来安装。

在安装完成后,在输入法列表中应该已经有了您自己的输入法。点击调试,由于它是一个DLL,您需要先选择一个宿主程序,一般选择“记事本”,以调试方式启动“记事本”后,在这个“记事本”中打开您的输入法,您就可以在源代码中设置断点了。需要说明的是,VC6.0调试DLL不太好用,首先需要打上SP5或者SP6,这样也不能够在DLL启动的时候就设置断点,推荐使用.net来调试。

输入法上下文(HIMC):HIMC是什么?在输入法编程时必然要接触到输入法上下文这个术语,刚接触时听起来实在是半懂不懂。由于输入法是一个插件,它需要和调用它的应用程序通讯,在输入法中生成的编码及重码信息保存在哪里应用程序才能正确的读取呢?答案就在于输入法上下文。输入法上下文是由User.exe(一个系统进程)为应用程序分配的内存句柄,在应用程序中启动的输入法在这块内存中写入数据,User.exe再将数据传递到应用程序。

UIWnd:在IME中需要导出一个接口,原型如LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam),hUIWnd是由User.exe传过来的窗口句柄,它是输入法中创建的窗口如编码窗口,重码窗口,状态栏窗口的宿主(Owner),初学输入法编程的人可能会问这个窗口显示在哪里呢?其实它并不是一个普通的窗口,它只是一个用来传递Windows消息的窗口(Message Only),在使用时,您不需要关心它在哪里,只需要使用它就好了。

一个IME需要导出19个(Win98版本)接口,但是对于一个只需要实现一般意义的文字输入的软件,您只需要实现几个基本的接口就可以让输入法正常工作了。下面逐一介绍一下这几个接口。



 ImeSelect() 
 Return Value 
 TRUE - successful, FALSE - failure 

BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect) 
在这个接口中,系统通知输入法当前是否打开了输入法输入。一般输入法启动时会调用一次,在一些软件(如EmEditor)中提供打开与关闭输入法的功能就是通过这个接口实现的。如果打开输入法,一般会在这个接口中做一些数据的初始化工作。 



系统调用这个接口来判断IME是否处理当前键盘输入 
HIMC hIMC输入上下文 
UINT uKey键值 
LPARAM lKeyData unknown 
CONST LPBYTE lpbKeyState键盘状态,包含256键的状态 
return  TRUE-IME处理,FALSE-系统处理 
系统则调用ImeToAsciiEx,否则直接将键盘消息发到应用程序 

BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uKey,LPARAM lKeyData,CONST LPBYTE lpbKeyState) 

观察注释您可以看到在个接口是用来判断用户敲击的哪个键需要处理,哪个键又应该交给系统自己处理,如果输入法需要自己处理用户输入的键,则在这个接口中返回true,否则返回false。 



 function应用程序调用这个接口来进行输入上下文的转换,输入法程序在这个接口中转换用户的输入 
 UINT uVKey键值,如果在ImeInquire接口中为fdwProperty设置了属性IME_PROP_KBD_CHAR_FIRST,则高字节是输入键值
 UINT uScanCode按键的扫描码,有时两个键有同样的键值,这时需要使用uScanCode来区分 
 CONST LPBYTE lpbKeyState键盘状态,包含256键的状态 
 LPDWORD lpdwTransKey消息缓冲区,用来保存IME要发给应用程序的消息,第一个双字是缓冲区可以容纳的最大消息条数 
 UINT fuStateActive menu flag(come from msdn) 
 HIMC hIMC输入上下文 
 return  返回保存在消息缓冲区lpdwTransKey中的消息个数 

UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC) 
这个接口可以说是输入法最重要的部分,程序员需要在这个接口中实现编码与重码的转换,转换完成或者显示在编码窗口及重码窗口,或者发送到应用程序。由于在这个接口中没有传入窗口句柄,如果通知输入法程序的窗口更新显示呢?当然我们可以使用全局变量,在此我个人推荐的方法是使用IME消息(没有什么道理),您将消息类型、参数保存到lpdwTransKey指示的缓冲区中,User.exe会根据消息类型做相应的处理并传递到UIWnd这个窗口中。 

那么如何输入文字呢?要输入文字需要3个消息配合使用,分别是WM_IME_STARTCOMPOSITION、WM_IME_COMPOSITION和WM_IME_ENDCOMPOSITION,它们分别指示开始输入编码,输入编码或者结果(视参数而异)及编码输入完成。在开始编写输入法的时候,为了省事,我的输入法在用户确定要输入一个重码时才连续调用这3个消息以向编码器中输入文字。由于WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION需要成对使用,这种方法可以确保它们配对。最初这种方式工作得很好,但是后来发现在一些软件中出现兼容性问题。如“智能五笔”在“遨游”中就存在这个问题,在“遨游”中的地址栏中打开“智能五笔”,当需要使用回退键来删除错误输入的编码时,会发现删除的不是编码窗口中的编码而是编辑器中的文字。这是因为类似“遨游”这类软件主动接管了按键输入如处理一些控制键,当它发现这些控制键不在WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION这两个消息之间时就自己处理控制键而不是先交给User.exe了。因此正确的流程应该是在开始输入编码时发送WM_IME_STARTCOMPOSITION,输入结束后发送WM_IME_ENDCOMPOSITION消息。


  UIWndProc()   IME UI window procedure   LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam) 
这是一个非常重要的接口,基本上一它负责各种消息的传递。一般您需要在这个接口中根据不同的消息类型,实现输入法窗口(如编码窗口、重码窗口、状态栏窗口)的显示、隐藏及更新等操作。这个接口实现的功能可能非常复杂,视情况而异,在此就不做更加深入的说明了。在使用时可以参见示例工程。 


BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData) 
这是最后一个需要注意的接口,在显示输入法属性配置时会Windows会调用这个接口。 


基本的接口就介绍到这里,下面谈一谈我个人在编写输入法程序时遇到的一些问题或者发现的一些需要注意的地方。

1、关于输入法窗口:阅读一些输入法的代码会奇怪,为什么输入法窗口在创建时需要指定WM_DISABLE属性呢?原来是因为如果不指定这个属性标志,在打开输入法时,会导致当前的应用程序失去输入焦点。但是指定了这个标志后,输入法窗口不能收到鼠标消息怎么办?解决的方法就在于WM_SETCURSOR这个消息。这个消息不管窗口是否可用,只要有鼠标在窗口内窗口都会收到。您可以在这个消息中模拟鼠标消息也可以选择调用SetCapture这个函数,这样窗口就可以收到鼠标消息了。

2、关于窗口模式:使用了几种输入法后,你会发现,有的输入法的编码窗口和重码窗口是一个窗口,有的又是两个窗口,它们有什么区别?或者有的人会觉得这个问题很可笑,但是当您研究了一段输入法可能就会发现您也有类似的问题:因为在输入法的导出接口中关于用户界面的函数就有4个,其它3个分类对应3个窗口回调函数。事实上它们并没有本质的区别,关键在于您的输入法的使用范围。一些软件(如某些游戏)为了界面的整体美观,不希望用户在打开输入法时显示输入法自己的窗口,而是希望输入法按照它的意愿将输入法窗口需要显示的内容显示在它创建的窗口中,英文称之为IME Aware。由于我自己的输入法目标不是在游戏中使用,所在并没有按照这个规矩来管理输入法窗口,而是为了简化,将编码窗口和重码窗口显示的内容放到了一个窗口中。

3、关于自定义消息:UIWndProc在WM_IME_NOTIFY中提供了一个IMN_PRIVATE,最初我理解为这个消息应该和WM_USER一样,当我需要不只一人自定义消息时只需要在这个ID的基础上增加值就好了。但事实是您定义的值可能是系统已经占用的(视Windows的版本而异),您能够使用的自定义消息应该只有这一个,为了指示多个消息类型,我使用的方法是在WM_IME_NOTIFY的LPARAM中进行区分。

4、调试信息输出:一般编写输入法都不会使用MFC,为了输出调试信息,一般只能使用OutputDebugString这个API,在示例代码中的helper.c中我编写了一个模拟TRACE的函数Helper_Trace,您可以用这个函数来将调试信息输出到调试窗口。

5、最后再谈一谈输入法类型:前面提到输入法分为外挂式和IME两种,但是目前一些输入法发展了第3种类型,那就是结合这两种类型的优点。例如拼音加加,启动拼音加加您会发现进程列表里会多一个拼音加加的服务进程,其实它才是拼音加加输入法的内核即数据处理部分。拼音加加的IME部分只是一个外壳,它提供传统的IME输入法一样的系统兼容性。在我的输入法中也采用了这种结构,使用内存文件映射及普通的Windows消息结合来实现两个进程间的通讯。您可以在我的输入法的源代码中找到进程间的通讯源代码及输入法代码。

好象没有更多的经验可言,总之,输入法其实并不神秘,在我看来,只要能够在VC中跟踪代码,我就不相信我会搞不定它!

再发个链接地址:
http://bbs.pediy.com/showthread.php?t=116239
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ring3下注入DLL的另类方法,能过杀软和游戏NP(源码) 注入DLL是做全局钩子或者拦截类软件都有可能用到的技术,如果做外挂的话我们也有 可能需要注入一个DLL到游戏进程中去干点什么“坏事”。 但我们知道现在要注入DLL是越 来越难了。场景1:制作火星文输入法外挂,原理是利用API HOOK拦截并修改输入法相关函 数,需要注入一个DLL到所有进程中,但是后来发现,在开启了瑞星的帐号保险箱后,用户 将不能在QQ中输入火星文。原因是瑞星保护了QQ进程,禁止对其注入DLL,解决方法是提示 用户关闭帐号保险箱 -_-| 确实是很降低用户体验的一个不是办法的办法。场景2:制作某 游戏外挂,需要注入一个DLL到游戏进程中去直接调用游戏函数完成某一功能。结果发现该 游戏有NP保护,OpenProcess打不开,创建远程线程也不行,试用其它方法也一一失败。遇 到上面的情况,高手们自然是转到Ring0下面去,使用驱动之类的办法来对付啦,不过吾等 菜鸟可就是酒井没法子了 -_-| 不过也别太灰心,凡事总会有办法的。我想我们需要一种持久的、稳定的、不容易被安 全软件屏蔽的DLL注入方法,后来发现,输入法程序就是能完成这一任务的理想人选。输入 法程序程序到底是什么?它没有自己的进程,并且在系统还没有登录时就已被加载(在欢迎 界面你也可以调出输入法),它可以在游戏中打开,也可以在控制台程序中打开,还可以在 瑞星保护下的QQ中打开,在杀软中也可以打开,这不就是我们要找的特性吗。那么,输入法 到底是什么呢?根据Windows的规定,输入法其实就是一个DLL,不过它是一个特殊的DLL, 它必须具有标准输入法程序所规定的那些接口,输入法是由输入法管理器(imm32.dll)控 制的,输入法管理器又是由user32.dll控制的。输入法在系统目录是以IME为扩展名的文件 ,当在应用程序中激活某个输入法时,输入法管理器就会在那个应用程序的进程中加载对应 的IME文件,注意,加载IME文件跟加载普通的DLL并没有本质区别,所以,可以认为,输入 法其实就是注入到应用程序中的一个DLL文件,并且,这种“注入”是不会被杀软和游戏NP 拦截的(至少目前是)。现在,我们已经有了一个注入DLL的另类方法,那就是利用输入法 。具体流程是这样,首先制作一个标准输入法文件,但是这个输入法并不完成文字输入工作 ,它的唯一任务就是用来注入DLL,所以称为“服务输入法”,然后,制作一个控制程序, 来控制服务输入法,当然最后还需要一个用于注入的目标DLL,这样一共就有3个文件。开始 工作后,控制程序首先将服务输入法安装到系统中,然后传递几个参数给服务输入法,参数 中包括了需要注入的DLL文件的名称和路径,然后,控制程序将服务输入法设置为系统的默 认输入法,这样新的程序一打开,服务输入法就会注入那个程序。当然,在服务输入法安装 之前打开的程序不会被注入,这时需要向系统中的所有窗口POST一条 WM_INPUTLANGCHANGEREQUEST消息,该消息可以在指定窗口中后台激活服务输入法,这样, 系统中所有拥有窗口的进程就都被我们的服务输入法注入了。服务输入法注入程序之后,就 会根据控制程序传递过来的参数加载目标DLL,这样目标DLL也就随着服务输入法一同注入到 目标程序中了。注意服务输入法是控制程序用WM_INPUTLANGCHANGEREQUEST消息在所有窗口 中自动激活的,如果某个窗口自动激活失败,你就需要在那个窗口中手工切换到服务输入法 ,这样才能注入进去了。至于注入以后,你就可以在窗口中切换到别的输入法,这并不会影 响已经注入进去的DLL。我将这一套功能制作成一个完整的示例,你可以在以下地址下载: http://www.pen88.com/download/imehook.rar 压缩包中的第6个和第8个文件夹演示了此 功能并包含所有源代码。其中文件imedllhost09.dll就是服务输入法,运行时会被安装到系 统中,控制程序退出时会自动卸载该输入法,这样用户就不太容易察觉,你还可以重新编译 该输入法,将名称改为“中文(中国)”,这样隐蔽性更好。文件hxwdllwx.dll是演示用的 目标DLL,你可以替换成自己的DLL,然后那个exe文件就是控制程序了。输入法 imedllhost09.dll在运行时会被复制到系统目录并更名为imedllhost09.ime,它导出了2个 函数用于控制。在VB中的声明为: Public Declare Function IMESetPubString Lib "imedllhost09.ime" (ByVal RunDLLStr As String, ByVal UnloadDll As Long, ByVal loadNextIme As Long, ByVal DllData1 As Long, ByVal DllData2 As Long, ByVal DllData3 As Long) As Long Public Declare Function IMEClearPubString Lib "imedllhost09.ime" () As Long 其中IMESetPubString用于向输入法传递要注入的DLL等参数。RunDLLStr,要注入的DLL命令 和完整路径。UnloadDll,当输入法退出时,是否同时卸载目标DLL 0-是,1-否。 loadNextIme,当切换至该服务输入法时,是否直接切换到下一个输入法(这样服务输入法 就好像被跳过了,可最小限度影响用户的输入法顺序) 0-否,1-是。DllData1,DllData2 ,DllData3是传递给目标DLL的回调函数(函数名称必须为RunDllHostCallBack)的参数, 你可以在目标DLL中导出一个函数,名称为RunDllHostCallBack,这样当输入法注入时会调 用目标DLL的该回调函数并向其传递这3个参数。函数原型为(VC): DWORD RunDllHostCallBack(DWORD calldata1, DWORD calldata2,DWORD calldata3); IMEClearPubString函数用于清除输入法的配置,清除后,输入法将停止在新的程序中注入 目标DLL,但已注入的DLL不会卸载。 好了,利用输入法注入DLL基本上就是这样了,详细的用法大家可以看压缩包中的第8个文 件夹,其中服务输入法VC写的,控制程序是VB的,代码都是有注释的。测试发现该方法能 过目前所有杀软,也能注入冰刃。当然缺点还是有的,就是目标程序如果不接受输入法那就 没办法了,但是现在一般的游戏都不会禁止玩家在里面打字吧,而且杀软也不能禁止用户输 入汉字吧,哈哈,所以通用性应该还是蛮好的。 最后,我再介绍另一个注入DLL的方法,估计也很少被用到。是利用一个未公开函数 RegisterUserApiHook,可以在网上搜索关键词“RegisterUserApiHook”,查到有人在 Windows 2003下测试成功,但是我在Windows XP测试却失败。后来终于找到了失效的原因。 RegisterUserApiHook函数可以在系统中注册一个全局钩子,你需要在钩子中指定一个DLL和 一个回调函数,然后,所有加载了user32.dll的程序就都会在启动时加载你指定的这个DLL 。用这个函数来注入DLL也是很不错的。但是测试发现它的注入能力似乎赶不上上面提到的 利用输入法注入的办法,可以注入一般的程序和某些安全程序,但是对冰刃无效。而且它 有一个限制,就是系统中只能同时存在一个这样的钩子。实际上这个钩子平时是被系统中的 Themes服务占用了,Themes服务正是利用这个钩子HOOK了绘制窗口的相关API,所以才让所 有程序窗口变成XP主题样式的。所以我们要用这个钩子的话,必须先关闭Themes服务,这样 在XP下也可以用了,但是这样系统就变成Windows 2000的样式了 -_-| RegisterUserApiHook函数的VB声明如下: Public Declare Function RegisterUserApiHookXP Lib "user32" Alias "RegisterUserApiHook" (ByVal hInstance As Long, ByVal fnUserApis As Long) As Long Public Declare Function RegisterUserApiHook2003 Lib "user32" Alias "RegisterUserApiHook" (pRegInfo As HookAPIRegInfo2003) As Long 可以看到,在XP和2003下这个函数的参数是不一样的。关于此函数的示例代码,请参见压缩 包中的第5个文件夹。 最后的最后,再介绍一个未公开函数InitializeLpkHooks,这个函数在网上能找到的资料更 少,只有一个声明而已。但是它名称中最后那个“Hooks”误导了我,我以为又是一个可以 用来注入DLL的不错函数,用OD反出来一看,原来只是个局部HOOK而已。虽然没太大用,还 是一并写上吧,也许谁用得着呢。InitializeLpkHooks顾名思义就是HOOK LPK的,Windows 有个lpk.dll,就是支持多语言包的那么个功能。测试发现好多程序在TextOut之前似乎是要 调用lpk.dll里面的相关函数的,可能是支持多语言的程序就需要用这个来判断到底要显示 那种语言吧。而InitializeLpkHooks,就是用来HOOK lpk.dll里面的4个函数的,这4个函数 是LpkTabbedTextOut,LpkPSMTextOut,LpkDrawTextEx,LpkEditControl。我们先打开VB, 在窗体中加入以下代码吧: Private Sub Form_Load() DLLhwnd = LoadLibrary("lpk.dll") '加载DLL DLLFunDre = GetProcAddress(DLLhwnd, "LpkDrawTextEx") '获取回调函数地址 LpkHooksInfo.lpHookProc_LpkTabbedTextOut = 0 LpkHooksInfo.lpHookProc_LpkPSMTextOut = 0 LpkHooksInfo.lpHookProc_LpkDrawTextEx = GetLocalProcAdress(AddressOf HookProc1) '设置要HOOK的LPK函数 LpkHooksInfo.lpHookProc_LpkEditControl = 0 InitializeLpkHooks LpkHooksInfo End Sub Private Sub Form_Unload(Cancel As Integer) LpkHooksInfo.lpHookProc_LpkTabbedTextOut = 0 LpkHooksInfo.lpHookProc_LpkPSMTextOut = 0 LpkHooksInfo.lpHookProc_LpkDrawTextEx = DLLFunDre LpkHooksInfo.lpHookProc_LpkEditControl = 0 InitializeLpkHooks LpkHooksInfo FreeLibrary DLLhwnd End Sub 然后新建一个模块,在模块中加入以下代码: Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long Public Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long Public Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long ' ----------------未公开函数-------------------------------------- Public Declare Sub InitializeLpkHooks Lib "user32" (lpProcType As Any) Type LpkHooksSetting lpHookProc_LpkTabbedTextOut As Long lpHookProc_LpkPSMTextOut As Long lpHookProc_LpkDrawTextEx As Long lpHookProc_LpkEditControl As Long End Type ' ------------------------------- Public DLLhwnd As Long, DLLFunDre As Long Public LpkHooksInfo As LpkHooksSetting Public Function GetLocalProcAdress(ByVal lpProc As Long) As Long GetLocalProcAdress = lpProc End Function Function HookProc1(ByVal a1 As Long, ByVal a2 As Long, ByVal a3 As Long, ByVal a4 As Long, ByVal a5 As Long, ByVal a6 As Long, ByVal a7 As Long, ByVal a8 As Long, ByVal a9 As Long, ByVal a10 As Long) As Long HookProc1 = 0 End Function 运行一下看看,是不是窗体中标题栏和按钮上的文字都没有了,因为我们把函数 LpkDrawTextEx替换成自己的函数HookProc1了。这个函数有10个参数,其中几个好像是字符 串指针,似乎可以用来截获窗体要显示的文字,然后改成另一种语言的文字,我猜想,也许 就是这个用途吧。哈哈,纯属猜测。以上就是函数InitializeLpkHooks的用法了。 以上就是全部。 本文所有示例代码的下载地址是: http://www.pen88.com/download/imehook.rar 我的QQ511795070,欢迎交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值