代码思路原作者,不详.......................膜拜第一位作者的开创思维
本人只是稍作修改和写入一些原作者没有告诉的东西
首先输入法必备的19个接口自己不要删除,不然输入法编译出来安装失败不要狗叫= =
其次输入法的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败不能注入
如何修改参照最下面的方法
------------------------------------------------------------------
思路:
1.创建一个文件映射对象,映射到内存,写入需要注入的dll名称,进程ID
2.保存原有默认输入法句柄,复制输入法程序到系统目录,并调用ImmInstallIME安装输入法
3.创建事件对象,以便同步dll的加载与卸载。
4.向目标进程的窗口句柄发送WM_INPUTLANGCHANGEREQUEST消息,lParam为输入法句柄
5.等待注入完成,广播WM_INPUTLANGCHANGEREQUEST消息,lParam为原有默认输入法句柄
6.卸载输入法,释放事件对象。
先来ime输入法,记得把编译出来的程序后缀设置为ime
library Ime;
uses
Windows,
SysUtils,
Classes,
Psapi,
ImeMain in 'ImeMain.pas',
ImeInject in 'ImeInject.pas';
{$E ime}
{$R Ime.res}
procedure MyDllProc(Reason: Integer);
var
LoadDllEvent:THandle;
UnLoadDllEvent:THandle;
begin
case Reason of
DLL_PROCESS_ATTACH:
begin
UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
if UnLoadDllEvent>0 then
begin
ResetEvent(UnLoadDllEvent);
end;
RegisterImeWindow;
GetImeInjectInfo(@InjectInfo);
if InjectInfo.ProcessId=GetCurrentProcessId then
begin
LoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_LOADDLL);
LoadLibrary(@InjectInfo.DllName);
if LoadDllEvent>0 then
begin
SetEvent(LoadDllEvent);
end;
end;
end;
DLL_PROCESS_DETACH:
begin
UnRegisterImeWindow;
UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
if UnLoadDllEvent>0 then
begin
SetEvent(UnLoadDllEvent);
end;
end;
end;
end;
exports
ImeConversionList,
ImeConfigure,
ImeDestroy,
ImeEscape,
ImeInquire,
ImeProcessKey,
ImeSelect,
ImeSetActiveContext,
ImeSetCompositionString,
ImeToAsciiEx,
NotifyIME,
ImeRegisterWord,
ImeUnregisterWord,
ImeGetRegisterWordStyle,
ImeEnumRegisterWord,
UIWndProc,
StatusWndProc,
CompWndProc,
CandWndProc;
begin
DllProc := @MyDllProc;
MyDllProc(DLL_PROCESS_ATTACH);
end.
-----------------------------------------------------
ime的主要单元
unit ImeMain;
interface
uses Windows,SysUtils,Classes,Imm,ImeInject;
const
IME_WINDOWCLASSNAME='Ime';
IME_SMODE_NONE=$0000;
UI_CAP_2700=$00000001;
SELECT_CAP_CONVERSION=$00000001;
// IME property bits
IME_PROP_END_UNLOAD=$00000001;
IME_PROP_KBD_CHAR_FIRST=$00000002;
IME_PROP_IGNORE_UPKEYS=$00000004;
IME_PROP_NEED_ALTKEY=$00000008;
IME_PROP_NO_KEYS_ON_CLOSE=$00000010;
IME_PROP_AT_CARET=$00010000;
IME_PROP_SPECIAL_UI=$00020000;
IME_PROP_CANDLIST_START_FROM_1=$00040000;
IME_PROP_UNICODE=$00080000;
IME_PROP_COMPLETE_ON_UNSELECT=$00100000;
type
PImeInfo=^TImeInfo;
TImeInfo=record
dwPrivateDataSize:DWORD;
fdwProperty:DWORD;
fdwConversionCaps:DWORD;
fdwSentenceCaps:DWORD;
fdwUICaps:DWORD;
fdwSCSCaps:DWORD;
fdwSelectCaps:DWORD;
end;
PTransMsg = ^TTransMsg;
TTransMsg = record
message: uInt;
wParam: WParam;
lParam: LParam;
end;
PTransMsgList = ^TTransMsgList;
TTransMsgList = record
uMsgCount: uInt;
TransMsg: array[0..0] of TTransMsg;
end;
PPrivContext = ^TPrivContext;
TPrivContext = record
iImeState: Integer;
fdwImeMsg: DWord;
dwCompChar: DWord;
fdwGcsFlag: DWord;
uSYHFlg: uInt;
uDYHFlg: uInt;
uDSMHCount: uInt;
uDSMHFlg: uInt;
bSeq: array[0..12] of Char; // sequence code of input char
fdwGB: DWord;
end;
function RegisterImeWindow:BOOL;
procedure UnRegisterImeWindow;
function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
uBufLen,uFlag:UINT):DWORD;stdcall;
function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer)
:BOOL;stdcall;
function ImeDestroy(uForce:UINT):BOOL;stdcall;
function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;stdcall;
function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD)
:BOOL;stdcall;
function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
lpbKeyState:PKeyboardState):BOOL;stdcall;
function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;stdcall;
function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;stdcall;
function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;stdcall;
function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;stdcall;
function NotifyIME(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
dwValue:DWORD):BOOL;stdcall;
function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;stdcall;
function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;stdcall;
function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;stdcall;
function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;stdcall;
function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
:LRESULT;stdcall;
var
InjectInfo:TImeInject;
implementation
function RegisterImeWindow:BOOL;
var
wc:WNDCLASSEX;
begin
wc.style:=CS_IME or CS_VREDRAW or CS_HREDRAW or CS_DBLCLKS;
wc.lpfnWndProc:=@UIWndProc;
wc.cbClsExtra:=0;
wc.cbWndExtra:=0;
wc.hInstance:=HInstance;
wc.hIcon:=0;
wc.hCursor:=LoadCursor(0, IDC_ARROW );
wc.hbrBackground:=GetStockObject(WHITE_BRUSH);
wc.lpszMenuName:=nil;
wc.lpszClassName:=IME_WINDOWCLASSNAME;
wc.hIconSm:=0;
Result:=Windows.RegisterClassEx(wc)<>0;
end;
procedure UnRegisterImeWindow;
begin
Windows.UnregisterClass(IME_WINDOWCLASSNAME,HInstance);
end;
function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
uBufLen,uFlag:UINT):DWORD;
begin
Result:=0;
end;
function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer):BOOL;
begin
Result:=dwMode=IME_CONFIG_GENERAL;
end;
function ImeDestroy(uForce:UINT):BOOL;
begin
Result:=not BOOL(uForce);
end;
function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;
begin
Result:=0;
end;
function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD):BOOL;
begin
Result := False;
lpImeInfo.dwPrivateDataSize:=SizeOf(TPrivContext);
lpImeInfo.fdwProperty:=IME_PROP_KBD_CHAR_FIRST or IME_PROP_IGNORE_UPKEYS;
lpImeInfo.fdwConversionCaps:=IME_CMODE_FULLSHAPE or IME_CMODE_NATIVE;
lpImeInfo.fdwSentenceCaps:=IME_SMODE_NONE;
lpImeInfo.fdwUICaps:=UI_CAP_2700;
lpImeInfo.fdwSCSCaps:=0;
lpImeInfo.fdwSelectCaps:=SELECT_CAP_CONVERSION;
StrCopy(lpszUIClass,IME_WINDOWCLASSNAME);
Result:=True;
end;
function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
lpbKeyState:PKeyboardState):BOOL;
begin
Result:=False;
end;
function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;
begin
Result:=True;
end;
function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;
begin
Result:=True;
end;
function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;
begin
Result:=False;
end;
function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;
begin
Result:=0;
end;
function NotifyIme(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
dwValue:DWORD):BOOL;
begin
Result:=False;
end;
function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar):BOOL;
begin
Result:=False;
end;
function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
:BOOL;
begin
Result:=False;
end;
function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;
begin
Result:=0;
end;
function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;
begin
Result:=0;
end;
function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;
function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;
function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;
function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
begin
Result:=0;
end;
end.
---------------------------------------------------------------
ime和注入程序的公共单元
unit ImeInject;
interface
uses Windows,SysUtils;
const
GUID_INJECT='{7E145D1D-663A-5BDC-EA47-B11342BF2315}';
GUID_LOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2416}';
GUID_UNLOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2517}';
type
PImeInject= ^TImeInject;
TImeInject= packed record
DllName:array[0..MAX_PATH] of Char;//注入的dll路径
ProcessId: DWORD;//注入的进程ID
end;
procedure CreateImeInjectInfo(DllName: string; ProcessId: DWORD; var FileMapHandle:THandle);
procedure GetImeInjectInfo(ImeInject:PImeInject);
implementation
procedure CreateImeInjectInfo(DllName:string; ProcessId: DWORD; var FileMapHandle:THandle);
var
InjectInfo:PImeInject;
begin
FileMapHandle:=0;
FileMapHandle := CreateFileMapping(INVALID_HANDLE_VALUE,nil,PAGE_READWRITE,0,SizeOf(TImeInject),GUID_INJECT); //以可读写形式创建有名文件映象
if FileMapHandle > 0 then //返回的文件映射对象句柄不为零
begin
InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_ALL_ACCESS,0,0,0); //在调用的进程中地址空间映射一个可完全控制文件视图
if InjectInfo<>nil then //如果返回的映射视图的起始地址不为空
begin
ZeroMemory(InjectInfo,SizeOf(TImeInject)); //TImeInject结构内存填零
CopyMemory(@(InjectInfo.DllName),PChar(DllName),MAX_PATH-1); //填写结构体里的内容
InjectInfo.ProcessId:=ProcessId; //填写进程ID
UnmapViewOfFile(InjectInfo); // 删除映射视图
end;
end;
end;
procedure GetImeInjectInfo(ImeInject:PImeInject);
var
FileMapHandle:THandle;
InjectInfo:PImeInject;
begin
ZeroMemory(ImeInject,SizeOf(TImeInject)); //结构体内存填零
FileMapHandle:=OpenFileMapping(FILE_MAP_READ,False,GUID_INJECT); //打开GUID_INJECT的文件映射
if FileMapHandle>0 then
begin
InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_READ,0,0,0);
if InjectInfo<>nil then
begin
CopyMemory(ImeInject,InjectInfo,SizeOf(TImeInject));
UnmapViewOfFile(InjectInfo);
end;
CloseHandle(FileMapHandle);
end;
end;
end.
-----------------------------------------------------------------------------------------
注入程序,注意引用 ImeInject 单元 ,Imm 单元 和 Registry 单元
const
WM_INPUTLANGCHANGEREQUEST = $0050;
var
FileMapHandle: THandle;
Procedure Inject(WindowName:string;Dllpath:string);
var
WindowHandle: THandle;
InjectProcessId: DWORD;
LoadDllEvent: THandle;
UnLoadDllEvent: THandle;
DefaultImeHandle: THandle;
ImeHandle: THandle;
ImeId: string;
ImePath: string;
SysDir: array[0..MAX_PATH] of Char;
begin
WindowHandle := FindWindow(nil, PChar(WindowName));
if WindowHandle > 0 then
begin
GetWindowThreadProcessId(WindowHandle, InjectProcessId);
if InjectProcessId > 0 then
begin
if FileMapHandle > 0 then
CloseHandle(FileMapHandle);
CreateImeInjectInfo(PChar(Dllpath), InjectProcessId,
FileMapHandle);
if FileMapHandle > 0 then
begin
SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, @DefaultImeHandle, 0);
ZeroMemory(@SysDir, MAX_PATH);
GetSystemDirectory(@SysDir, MAX_PATH);
ImePath := string(SysDir) + '\ImeInject.ime';
//复制输入法文件到系统目录
if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'ImeInject.ime'),
PChar(ImePath), False) then
begin
//安装输入法
ImeHandle := ImmInstallIME(PChar(ImePath), 'zhusjm输入法');
if ImeHandle > 0 then
begin
UnLoadDllEvent := CreateEvent(nil, True, True, GUID_UNLOADDLL);
LoadDllEvent := CreateEvent(nil, True, False, GUID_LOADDLL);
//向目标窗口发送激活输入法的消息
PostMessage(WindowHandle,WM_INPUTLANGCHANGEREQUEST, 0,ImeHandle);
//等待注入完成
if WaitForSingleObject(LoadDllEvent, 3000) = WAIT_OBJECT_0 then
begin
ShowMessage('注入成功');
//广播消息,使我们的输入法卸载
PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, 0,
DefaultImeHandle);
//等待输入法卸载
if WaitForSingleObject(UnLoadDllEvent, 3000) = WAIT_OBJECT_0 then
begin
end;
end;
UnloadKeyboardLayout(ImeHandle);
DeleteFile(ImePath);
CloseHandle(UnLoadDllEvent);
CloseHandle(LoadDllEvent);
end;
end;
end;
end;
end;
end;
---------------------------------------------------------------------
因为ime的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败
输入法ime的 资源文件,新建 rc 写入以下内容用delphi的brcc32.exe编译成res 然后 ime 里面
引用这个资源再编译出来ime输入法才能被ImmInstallIME函数安装
VS_VERSION_INFO VERSIONINFO //版本信息结构
FILEVERSION 1,0,0,1 //文件版本
PRODUCTVERSION 1,0,0,1 //这里是主版本信息
FILEFLAGSMASK 0x3fL //这里设为0x3fL就好
#ifdef _DEBUG
FILEFLAGS 0x1L //VS_FF_DEBUG包括debug信息
#else
FILEFLAGS 0x0L //无
#endif
FILEOS 0x4L //win32程序
FILETYPE 0x3L //文件类型,2是dll,1是exe,3是VFT_DRV 驱动程序
FILESUBTYPE 0xbL //VFT2_DRV_INPUTMETHOD 输入法驱动程序
BEGIN
BLOCK "StringFileInfo" //这里设置文件其他的版本信息(详细信息)
BEGIN
BLOCK "080403A8" //所用语言080403A8简体中文
BEGIN
VALUE "Comments","Microsoft(R) Windows(R) Operating System" //备注
VALUE "CompanyName","Microsoft(R)\0" //公司名
VALUE "FileDescription", "zhu.ime\0" //产品描述
VALUE "FileVersion", "1. 0. 0. 1\0" //文件版本
VALUE "InternalName", "" //内部名称
VALUE "LegalCopyright", "Copyright (C) 2000.01\0" //版权信息
VALUE "OriginalFilename", "zhu.ime\0" //源文件名
VALUE "ProductName", "zhu.ime\0" //产品名
VALUE "ProductVersion", "1. 0. 0. 1\0" //产品版本
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x804, 0x03A8
END
END