找尋其他exe 的 handle |
答題得分者是:rick060
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
請問各位!
我有 A,B兩支程式都分別RUN起來, 在工作管理員中可以看的到, 我想在A程式, 想把 B程式調到前景來(即FOUCS), 現在我是用 FINDWINOW(nil, 'B程式的標題CAPTION') 來取得 B的Handle 值 然後在 A程式中把 B程式再叫出來, 但因為使用 CAPTION標題來搜尋, 我覺得 很不理想, 萬一CAPTION改變, 或換成其他語系時, A程式又要重改, 再者例如 NOTEPAD 在 WIN7上開啟, 會變成 "未命名 - 記事本", 除非 FINDWINDOW() 要下完整的CAPTION, 否則就取不到該HANDLE 值, 所以是不是還有其他方法取得指定程式的HANDLE的方式, 我在想, 可不可以 由工作管理員中的 PROCESS 來取得, 但我嘗試的結果, 取到的HANDLE 並不 正確, 謝謝! |
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
1. interface function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean; stdcall; implementation function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean; var dwPID : DWORD; begin Result := True; if hw = 0 then Exit; //其它還要加什麼判斷就隨意了... //已知檔名的方法 //GetModuleBaseName //自行變化... //或 //已知 PID 的方法 GetWindowThreadProcessId(hw, @dwPID); if dwPID = 1760 then //已知 PID begin if IsIconic(hw) then //是不是縮小 ShowWindow(hw, SW_RESTORE) else BringWindowToTop(hw); SetForegroundWindow(hw); //設到前景 end; end; procedure TMainForm.Button12Click(Sender: TObject); begin EnumWindows(@EnumWindowsProc,0); end;
2.記錄自身的 HANDLE 給第二支程式抓 |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
感謝, 但如果我不知道PID 值的話, 有其他的方法嗎?
假設這兩支程式, 其中一支不是我寫的, 只是別人的檔案 我利用以下的程式, 可以取得所有被啟動的程式及PID, 但我如何將列表(TStringList 中)找到我想要的程式 讓A可以呼叫B並調到前景 [code delphi] function TForm1.ListAllActiveWnd(var SL: TStringList): TStringList; type PStringList = ^TStringList; function EnumWndProc(hWin: HWND; Param: LPARAM): BOOL; stdcall; var szBuf: array[0..100] of Char; begin // 取得所有可見的視窗 if (IsWindow(hWin) and IsWindowVisible(hWin)) then begin // 只取最上層可見視窗 if (Windows.GetParent(hWin) = 0) then begin FillChar(szBuf, SizeOf(szBuf), 0); GetWindowText(hWin, szBuf, SizeOf(szBuf)); if (szBuf <> '') then PStringList(Param)^.AddObject(szBuf, TObject(hWin)); end; end; result := true; end; var i: Integer; slWnd: TStringList; dwProcess1, dwProcess2: DWORD; begin SL.Sorted:= True; slWnd:= TStringList.Create; // 用 EnumWindows 列舉出所有可能的視窗, 並記在TStringList中 EnumWindows(@EnumWndProc, LPARAM(@slWnd)); // 比對所有可能的視窗, 去掉屬於同一個Process的視窗 // 最後一個一定是Program Manager, 所以loop只到slWnd.Count - 2, 直接去掉 // Program Manager for i := 0 to slWnd.Count - 2 do begin GetWindowThreadProcessId(HWND(slWnd.Objects[i]), @dwProcess1); GetWindowThreadProcessId(HWND(slWnd.Objects[i 1]), @dwProcess2); if ((CheckBox1.Checked=True) and (dwProcess1 <> dwProcess2)) or (CheckBox1.Checked=False) then SL.Add(slWnd.Strings[i] ' PID1:' InttoStr(dwProcess1) ' PID2:' InttoStr(dwProcess2)); end; slWnd.Free; result:= SL; end; [/code] ===================引 用 rick060 文 章=================== 1. interface function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean; stdcall; implementation function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean; var dwPID : DWORD; begin Result := True; if hw = 0 then Exit; //其它還要加什麼判斷就隨意了... //已知檔名的方法 //GetModuleBaseName //自行變化... //或 //已知 PID 的方法 GetWindowThreadProcessId(hw, @dwPID); if dwPID = 1760 then //已知 PID begin if IsIconic(hw) then //是不是縮小 ShowWindow(hw, SW_RESTORE) else BringWindowToTop(hw); SetForegroundWindow(hw); //設到前景 end; end; procedure TMainForm.Button12Click(Sender: TObject); begin EnumWindows(@EnumWindowsProc,0); end;
2.記錄自身的 HANDLE 給第二支程式抓 |
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
那我假設可以知道 程式檔名
var pProcess : array[0..1023] of DWORD; szModule : array[0..1023] of Char; hMods : array[0..1023] of HMODULE; cbNeeded : DWORD; cProcesses : DWORD; dwPID : DWORD; nIndex : Integer; nModIndex : Integer; pHandle : Cardinal; pWinHandle : Cardinal; begin //列出所有 Process EnumProcesses(@pProcess,sizeof(pProcess),@cbNeeded); for nIndex := 0 to (cbNeeded div sizeof(DWORD) - 1) do begin //取得該 Handle pHandle := OpenProcess( PROCESS_ALL_ACCESS , False , pProcess[nIndex] ); if pHandle = 0 then Continue; //取得 ProcessName / 也可以用 GetProcessImageFileName GetModuleBaseName(pHandle,0,szModule,sizeof(szModule)); if CompareText( String(szModule) , 'outlook.exe' ) = 0 then begin //抓出來的並不是 Form Handle ,所以再透過 PID 抓下去 pWinHandle := GetTopWindow(0); while pWinHandle <> 0 do begin GetWindowThreadProcessId(pWinHandle,@dwPID); if dwPID = pProcess[nIndex] then begin if IsIconic(pWinHandle) then ShowWindow(pWinHandle, SW_RESTORE) else BringWindowToTop(pWinHandle); SetForegroundWindow(pWinHandle); Windows.SetFocus(pWinHandle); break; //對有些 form 仍然會無效,自行再調整了.. end; pWinHandle := GetNextWindow(pWinHandle,GW_HWNDNEXT); end; //這邊是列出該 Process 所用到的模組,要不要取就隨意了 {EnumProcessModules(pHandle,@hMods,sizeof(hMods),@cbNeeded); for nModIndex := 0 to (cbNeeded div sizeof(HMODULE) - 1 ) do begin GetModuleFileNameEx( pHandle, hMods[nModIndex], szModule,sizeof(szModule) div sizeof(Char) ); Memo.Lines.Add(szModule); end; } end; end; end;
|
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
我用 d7 需要做以下 external
function GetModuleBaseName(hProcess : Cardinal ; hMod : HMODULE ; lpBaseName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; function GetProcessImageFileName( hProcess : Cardinal ; lpBaseName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; function EnumProcesses(pProcessIds:PDWORD ; cb : DWORD ;pBytesReturned:PDWORD):Boolean;stdcall; function GetModuleFileNameEx(hProcess : Cardinal ; hMod : HMODULE ; lpFileName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; {$IFDEF UNICODE} function GetModuleBaseName;external 'psapi.dll' name 'GetModuleBaseNameW'; function GetProcessImageFileName ;external 'psapi.dll' name 'GetProcessImageFileNameW'; function EnumProcesses;external 'psapi.dll' name 'EnumProcesses'; function GetModuleFileNameEx;external 'psapi.dll' name 'GetModuleFileNameExW'; {$ELSE} function GetModuleBaseName;external 'psapi.dll' name 'GetModuleBaseNameA'; function GetProcessImageFileName ;external 'psapi.dll' name 'GetProcessImageFileNameA'; function EnumProcesses;external 'psapi.dll' name 'EnumProcesses'; function GetModuleFileNameEx;external 'psapi.dll' name 'GetModuleFileNameExA'; {$ENDIF}
|
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
[code delphi] procedure TMainForm.Button14Click(Sender: TObject); function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean;stdcall; var dwPID : DWORD; begin Result := True; GetWindowThreadProcessId(hw,@dwPID); if dwPID = PInteger(lparam)^ then begin if IsIconic(hw) then ShowWindow(hw, SW_RESTORE) else BringWindowToTop(hw); // SetForegroundWindow(hw); Windows.SetFocus(hw); end; end; var pProcess : array[0..1023] of DWORD; szModule : array[0..1023] of Char; cbNeeded : DWORD; nIndex : Integer; pHandle : Cardinal; begin //列出所有 Process EnumProcesses(@pProcess,sizeof(pProcess),@cbNeeded); for nIndex := 0 to (cbNeeded div sizeof(DWORD) - 1) do begin //取得該 Handle pHandle := OpenProcess( PROCESS_ALL_ACCESS , False , pProcess[nIndex] ); if pHandle = 0 then Continue; //取得 ProcessName / 也可以用 GetProcessImageFileName GetModuleBaseName(pHandle,0,szModule,sizeof(szModule)); if CompareText( String(szModule) , 'chrome.exe' ) = 0 then begin EnumWindows(@EnumWindowsProc,Integer(@pProcess[nIndex])); break; end; end; end; [/code] 這種方式我測出來的效果較好 |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
我實作了rick兄的demo, 確實可行, 讓執行程式調到前景, 但又遭遇到一個新問題,
就是這支程式(要調前景的cust.exe) 是呼叫另一支 cust1.dll , 但我實際要調出的 cust1.dll的 form畫面 以現在的做法, 只能顯示出 cust.exe 的畫面, 我還必須到工作列去切換, 看來是沒有取得 cust1.dll正確的pid [code delphi] unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; function GetModuleBaseName(hProcess : Cardinal ; hMod : HMODULE ; lpBaseName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; function GetProcessImageFileName( hProcess : Cardinal ; lpBaseName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; function EnumProcesses(pProcessIds:PDWORD ; cb : DWORD ;pBytesReturned:PDWORD):Boolean;stdcall; function GetModuleFileNameEx(hProcess : Cardinal ; hMod : HMODULE ; lpFileName : PAnsiChar ; nSize : DWORD):DWORD;stdcall; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; {$IFDEF UNICODE} function GetModuleBaseName;external 'psapi.dll' name 'GetModuleBaseNameW'; function GetProcessImageFileName ;external 'psapi.dll' name 'GetProcessImageFileNameW'; function EnumProcesses;external 'psapi.dll' name 'EnumProcesses'; function GetModuleFileNameEx;external 'psapi.dll' name 'GetModuleFileNameExW'; {$ELSE} function GetModuleBaseName;external 'psapi.dll' name 'GetModuleBaseNameA'; function GetProcessImageFileName ;external 'psapi.dll' name 'GetProcessImageFileNameA'; function EnumProcesses;external 'psapi.dll' name 'EnumProcesses'; function GetModuleFileNameEx;external 'psapi.dll' name 'GetModuleFileNameExA'; {$ENDIF} implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); function EnumWindowsProc(hw:Cardinal;lparam:Longint):Boolean;stdcall; var dwPID: DWORD; begin Result:= True; GetWindowThreadProcessId(hw,@dwPID); if dwPID = PInteger(lparam)^ then begin if IsIconic(hw) then ShowWindow(hw, SW_RESTORE) else BringWindowToTop(hw); Windows.SetFocus(hw); end; end; var pProcess : array[0..1023] of DWORD; szModule : array[0..1023] of Char; cbNeeded : DWORD; nIndex : Integer; pHandle : Cardinal; begin //列出所有 Process EnumProcesses(@pProcess,sizeof(pProcess),@cbNeeded); for nIndex:= 0 to (cbNeeded div sizeof(DWORD) - 1) do begin //取得該 Handle pHandle := OpenProcess( PROCESS_ALL_ACCESS , False , pProcess[nIndex] ); if pHandle = 0 then Continue; //取得 ProcessName / 也可以用 GetProcessImageFileName GetModuleBaseName(pHandle,0,szModule,sizeof(szModule)); if CompareText( String(szModule) , 'cust.exe') = 0 then begin EnumWindows(@EnumWindowsProc,Integer(@pProcess[nIndex])); break; end; end; end; [/code] |
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
任何 AP call dll 都是把 dll 的區段放到自己的 stack ,所以 dll 不會有 PID 所以若要不指定 Form 的 Caption 或有共通的自定資料 而要抓 dll 所建的 Form handle 變成不可能。 利用 FindWindow 抓出來的 Window Handle 抓出來的 Image 也都是原本 call DLL 的 exe 檔. 這就難解了。 |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
這樣看來, 似乎還是只有回到原本我使用的 FindWindow 方式來解決, 至少這個做法是可以的,
只是要正確的判斷 caption 的內容, 是難度很高的! 不過還是謝謝 rick兄這麼多的提點, 我對 API 的部份其實非常弱, 由這邊又加深了對這些 API的了解! ===================引 用 rick060 文 章=================== 任何 AP call dll 都是把 dll 的區段放到自己的 stack ,所以 dll 不會有 PID 所以若要不指定 Form 的 Caption 或有共通的自定資料 而要抓 dll 所建的 Form handle 變成不可能。 利用 FindWindow 抓出來的 Window Handle抓出來的 Image 也都是原本 call DLL 的 exe 檔. 這就難解了。 |
wameng
版主 發表:31 回覆:1336 積分:1188 註冊:2004-09-16 發送簡訊給我 |
P.D.
有疑問在告訴我,也許我有解決方法也說不定。 cool.evon@msa.hinet.net ===================引 用 P.D. 文 章=================== 這樣看來, 似乎還是只有回到原本我使用的 FindWindow 方式來解決, 至少這個做法是可以的, 只是要正確的判斷 caption 的內容, 是難度很高的! 不過還是謝謝 rick兄這麼多的提點, 我對 API 的部份其實非常弱, 由這邊又加深了對這些 API的瞭解! ===================引 用 rick060 文 章=================== 任何 AP call dll 都是把 dll 的區段放到自己的 stack ,所以 dll 不會有 PID 所以若要不指定 Form 的 Caption 或有共通的自定資料 而要抓 dll 所建的 Form handle 變成不可能。 利用 FindWindow 抓出來的 Window Handle抓出來的 Image 也都是原本 call DLL 的 exe 檔. 這就難解了。 |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
|
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
整整一年半。又偶然看到這篇突然有個想法,若不在乎可能的效率損失,可以用 hook 的方式取得 form handle ,也試作了一下是可行的。 (用 c 寫的...歹勢啦) //列出所有 process #define TARGETPRGM "targetProg.exe" //要抓出來的行程名 BOOL EnumProcess() { return FALSE; pe32.dwSize = sizeof( PROCESSENTRY32 ); if( !Process32First( hProcessSnap, &pe32 ) ) if( stricmp(pe32.szExeFile,TARGETPRGM) == 0) hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID ); } } while( Process32Next( hProcessSnap, &pe32 ) ); CloseHandle(hProcessSnap); return TRUE; } void CatchProcess(HANDLE handle) { LPVOID remoteParam; //安一個 dll 進去該行程的 user space WriteProcessMemory(handle,remoteParam,HOOKDLL,strlen(HOOKDLL) 1 , &writeSize); if(remoteThread == NULL) WaitForSingleObject(remoteThread,INFINITE); VirtualFreeEx(handle,remoteParam,strlen(HOOKDLL) 1,MEM_DECOMMIT); //WaitForSingleObject(handle,INFINITE); } dll 的部份 BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved switch (ul_reason_for_call) case DLL_PROCESS_ATTACH: WriteLog("DLL_PROCESS_ATTACH"); break; WriteLog("DLL_THREAD_ATTACH"); case DLL_THREAD_DETACH: break; WriteLog("DLL_PROCESS_DETACH"); break; return TRUE; } //主要方法是直接改寫 IAT 讓該行程在建立視窗時先跑我們的 func 取得 HANDLE 記錄下來 #define MakePtr(cast,base,offset) (cast)((DWORD)(base) (DWORD)(offset)) #define INJECTDLL "User32.dll" #define REMARKFUNC "CreateWindowExA" void HookProcess() { PIMAGE_SECTION_HEADER section; PIMAGE_NT_HEADERS nt; FARPROC injectFunc; LPVOID moduleName; BOOL ret; imageBase = GetModuleHandle(NULL); nt = MakePtr(PIMAGE_NT_HEADERS,imageBase,dos->e_lfanew); while(importDesc->Name) moduleName = MakePtr(LPVOID,imageBase,importDesc->Name); { break; importDesc ; if(importDesc->Name) thunk = MakePtr(PIMAGE_THUNK_DATA,imageBase,importDesc->FirstThunk); { { ret = VirtualProtect(thunk, 4, *(DWORD*)thunk = (DWORD)_CreateWindowEx; oldProtect, &oldProtect); } } } } //改寫的 api HWND WINAPI _CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ) { HWND handle = CreateWindowExA(dwExStyle,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); //可在此過瀘是不是我們要的 windows,可事先用 spy 取得 classname,windowname MessageBox(NULL,msg,"info",MB_OK); //把 form handle 存下來 return handle; } 一切正常 SetForegroundWindow((HWND)5375984); ShowWindow((HWND)5375984,SW_RESTORE); 那該視窗就出來啦
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |