代码思路原作者,不详.......................膜拜第一位作者的开创思维
本人只是稍作修改和写入一些原作者没有告诉的东西
首先输入法必备的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
|