2011-08-18 15 views
6

他のアプリケーションのモーダルウィンドウに項目を追加する最も良い方法は何ですか?他のアプリケーションのモーダルウィンドウにアイテムを追加する最も良い方法は?

私がこれを(概念の証明として)書いた簡単な例は、私が思うに、非常に多くのプロセッサ集中型で、簡単なバックグラウンドプロセスではありませんが、別の問題が発生しています。

たとえば、医師が処方箋データでモーダルウィンドウを記入しているとします。 11回の詰め替えで30日間入力すると、患者は3回の詰め替えで90日を要すると言います。元のアプリケーション(ソースにアクセスできない)には簡単な変換はありません。私はこの特定のウィンドウ(timerとfindwindowを使って)を監視する小さなユーティリティを書いていて、それを見つけたらそれを見せて、ターゲットモーダルウィンドウ上の空いた場所に置く。 "30"ボタンが押されると、Rxは11日間の詰め替えで30日間書かれ、 "90"ボタンが押されると、それはあなたが期待することをします。モーダルウィンドウが動くと、30と90のボタンも一緒に移動します。これは動作しますが、私はfindwindowをタイマーで繰り返し実行する際のオーバーヘッドについて懸念しています。

1)良い方法がありますか? 2)私はこれについて心配する権利がありますか? 3)私のクルージュがどれほど非効率的であるか、あなたは笑っていますか?

ありがとうございます - 私はここにいる人々に非常に感銘を受けました!

+4

のいずれか..あなたはあまりにも急速にポーリングされていない場合、タイマーはいいですね。 –

+0

@Sertac:だから...あなたは「あまりにも速いポーリング」と思われますか?私は250msのポーリング間隔でシステムパフォーマンスの低下やCPUの増加に気付きませんが(これは非常に原油対策です)、これはちょうど「間違っているようです」...それより遅いものは、ボタンがフォームに従うことを妨げますスムーズに。 –

+1

@ b-pウィンドウを見る(ポーリングする)ために1秒の間隔を使い、スムーズにするために250ミリ秒のスイッチが見つかったときにそれを使うことができます。この方法では、ターゲットウィンドウが存在しない場合でもシステムに負荷をかけることはありません。 – ain

答えて

1

最も良い方法は... DLL注入です。

代替がはるかにエラーが発生しやすいと問題、グローバルCBTフックをインストールすることであると私は考えることができる、そしてそれは資源が懸念している限り多くを解放していない何
// The DLL: 
library dll_inj; 

uses 
    ShareMem, 
    System.SysUtils, 
    System.Classes, Vcl.Dialogs, 
    windows, messages; 

{$R *.res} 

var 
    hWndMain, hDemoButton, hEdit, hNewButton, hWndEnter: THandle; 
    OldWndProc: TFarProc; 
    hBtnFont: hFont; 
    Times: integer; 
    dwThreadId: DWORD; 

function NewWndProc(hWnd: hWnd; Msg: UINT; wParam: wParam; lParam: lParam) 
    : Longint; stdcall; 
begin 
    if Times = 0 then 
    begin 
    Times := Times + 1; 
    hWndMain := FindWindowEx(0, 0, 'TForm1', 'Injection test'); 
    if hWndMain = 0 then 
     OutputDebugString('hWndMain is 0!'); 

    hNewButton := CreateWindow('button', 'NewBtn', WS_CHILD or WS_VISIBLE, 20, 
     20, 100, 24, hWndMain, 2000, GetWindowLong(hWndMain, GWL_HINSTANCE), nil); 
    if hNewButton = 0 then 
     OutputDebugString('CreateWindow failed!') 
    else 
    begin 
     hWndEnter := FindWindowEx(hWndMain, 0, 'TBitBtn', 'Enter'); 
     if hWndEnter <> 0 then 
     hBtnFont := SendMessage(hWndEnter, WM_GETFONT, 0, 0); 
     if hBtnFont <> 0 then 
     SendMessage(hNewButton, WM_SETFONT, hBtnFont, 1); 
    end; 

    hDemoButton := FindWindowEx(hWndMain, 0, 'TButton', 'Demo'); 
    if hDemoButton <> 0 then 
    begin 
     if not EnableWindow(hDemoButton, true) then 
     OutputDebugString('EnableWindow failed!'); 
    end 
    else 
     OutputDebugString('hDemoButton is 0!'); 

    hEdit := FindWindowEx(hWndMain, 0, 'TEdit', 'Serial'); 
    if hEdit = 0 then 
     OutputDebugString('hEdit is 0!') 
    else if not SetWindowText(hEdit, 'You have been hacked') then 
     OutputDebugString('SetWindowText failed!'); 
    end; 

    case Msg of 
    WM_COMMAND: 
     if (hNewButton <> 0) and (DWORD(lParam) = hNewButton) then 
     MessageBox(HWND_DESKTOP, 'You pressed a new button!', 'Yay!', MB_OK) 
     else if (hWndEnter <> 0) and (DWORD(lParam) = hWndEnter) then 
     begin 
     MessageBox(HWND_DESKTOP, 'This message is not default anymore!', 
      'Override!', MB_OK); 
     Exit(0); // Suppress default event completely 
     end; 
    end; 
    Result := CallWindowProc(OldWndProc, hWnd, Msg, wParam, lParam); 
end; 

procedure EntryPoint(Reason: integer); 
begin 
    hWndMain := FindWindowEx(0, 0, 'TForm1', 'Injection test'); 
    if hWndMain = 0 then 
    begin 
    OutputDebugString('hWndMain is 0!'); 
    Exit; 
    end; 

    OldWndProc := TFarProc(SetWindowLong(hWndMain, GWL_WNDPROC, 
    LONG(@NewWndProc))); 

    MessageBox(0, 'DLL Injected', 'OK', 0); 
end; 

begin 
    CreateThread(nil, 0, @EntryPoint, nil, 0, &dwThreadId); 

end. 

// The injector: 
program exe_inj2; 

{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    System.SysUtils, windows, TLHelp32; 

Function EnumThreadProc(wnd: HWND; Var appHwnd: HWND): LongBool; stdcall; 
Var 
    buf: array [0 .. 256] of Char; 
Begin 
    Result := LongBool(1); 
    if GetClassname(wnd, buf, sizeof(buf)) > 0 then 
    If StrComp(buf, 'TApplication') = 0 Then 
    Begin 
     appHwnd := wnd; 
     Result := False; 
    End; 
End; 

Function FindApplicationWindow(forThreadID: DWORD): HWND; 
Begin 
    Result := 0; 
    EnumThreadWindows(forThreadID, @EnumThreadProc, lparam(@Result)); 
End; 

Function ProcessIDFromAppname32(appname: String): DWORD; 
{ Take only the application filename, not full path! } 
Var 
    snapshot: THandle; 
    processEntry: TProcessEntry32; 
Begin 
    Result := 0; 
    appname := UpperCase(appname); 
    snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    If snapshot <> 0 Then 
    try 
     processEntry.dwSize := sizeof(processEntry); 
     If Process32First(snapshot, processEntry) Then 
     Repeat 
      If Pos(appname, 
      UpperCase(ExtractFilename(StrPas(processEntry.szExeFile)))) > 0 Then 
      Begin 
      Result := processEntry.th32ProcessID; 
      Break; 
      End; { If } 
     Until not Process32Next(snapshot, processEntry); 
    finally 
     CloseHandle(snapshot); 
    End; { try } 
End; 

function InjectDLL(dwPID: DWORD; DLLPath: PWideChar): integer; 
var 
    dwThreadID: Cardinal; 
    hProc, hThread, hKernel: THandle; 
    BytesToWrite, BytesWritten: SIZE_T; 
    pRemoteBuffer, pLoadLibrary: Pointer; 
begin 
    if not FileExists(DLLPath) then 
    begin 
    MessageBox(0, PWideChar('File ' + DLLPath + ' does not exist'), 'Error', 0); 
    Exit(0); 
    end; 

    hProc := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or 
    PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwPID); 
    if hProc = 0 then 
    Exit(0); 
    try 
    BytesToWrite := sizeof(WideChar) * (Length(DLLPath) + 1); 
    pRemoteBuffer := VirtualAllocEx(hProc, nil, BytesToWrite, MEM_COMMIT, 
     PAGE_READWRITE); 
    if pRemoteBuffer = nil then 
     Exit(0); 
    try 
     if not WriteProcessMemory(hProc, pRemoteBuffer, DLLPath, BytesToWrite, 
     BytesWritten) then 
     Exit(0); 
     hKernel := GetModuleHandle('kernel32.dll'); 
     pLoadLibrary := GetProcAddress(hKernel, 'LoadLibraryW'); 
     hThread := CreateRemoteThread(hProc, nil, 0, pLoadLibrary, pRemoteBuffer, 
     0, dwThreadID); 
     try 
     WaitForSingleObject(hThread, INFINITE); 
     finally 
     CloseHandle(hThread); 
     end; 
    finally 
     VirtualFreeEx(hProc, pRemoteBuffer, 0, MEM_RELEASE); 
    end; 
    finally 
    CloseHandle(hProc); 
    end; 
    Exit(1); 
end; 

const 
    PROCESS_NAME = 'Default_project.exe'; 

begin 
    try 
    { TODO -oUser -cConsole Main : Insert code here } 
    WriteLn(PROCESS_NAME + ' PID: ' + 
     IntToSTr(ProcessIDFromAppname32(PROCESS_NAME))); 
    InjectDLL(ProcessIDFromAppname32(PROCESS_NAME), 'dll_inj.dll'); 
    ReadLn; 
    except 
    on E: Exception do 
     WriteLn(E.ClassName, ': ', E.Message); 
    end; 

end. 
関連する問題