全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:10559
推到 Plurk!
推到 Facebook!

找尋其他exe 的 handle

答題得分者是:rick060
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-06-04 01:44:31 IP:118.160.xxx.xxx 未訂閱
請問各位!

我有 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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-06-07 15:46:04 IP:60.250.xxx.xxx 訂閱
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

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-06-08 09:53:13 IP:118.169.xxx.xxx 未訂閱
感謝, 但如果我不知道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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-06-08 14:43:45 IP:60.250.xxx.xxx 訂閱
 那我假設可以知道 程式檔名
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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-06-08 14:46:46 IP:60.250.xxx.xxx 訂閱
 我用 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

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-06-09 10:14:36 IP:60.250.xxx.xxx 訂閱

[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]
這種方式我測出來的效果較好

編輯記錄
rick060 重新編輯於 2011-06-08 20:15:53, 註解 無‧
rick060 重新編輯於 2011-06-08 20:16:55, 註解 無‧
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-06-10 11:44:29 IP:118.169.xxx.xxx 未訂閱
我實作了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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-06-10 11:54:22 IP:60.250.xxx.xxx 訂閱
任何 AP call dll 都是把 dll 的區段放到自己的 stack ,所以 dll 不會有 PID
所以若要不指定 Form 的 Caption 或有共通的自定資料
而要抓 dll 所建的 Form handle 變成不可能。

利用 FindWindow 抓出來的 Window Handle 抓出來的 Image 也都是原本 call DLL 的 exe 檔.

這就難解了。
編輯記錄
rick060 重新編輯於 2011-06-10 01:41:33, 註解 無‧
rick060 重新編輯於 2011-06-10 01:49:12, 註解 無‧
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-06-11 00:21:41 IP:118.169.xxx.xxx 未訂閱
這樣看來, 似乎還是只有回到原本我使用的 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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2011-06-11 03:49:38 IP:122.126.xxx.xxx 訂閱
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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2011-06-12 22:55:34 IP:118.169.xxx.xxx 未訂閱
已發MAIL到您指定的位址, 謝謝!
=============引 用 wameng 文 章===================
P.D.

有疑問在告訴我,也許我有解決方法也說不定。
cool.evon@msa.hinet.net
rick060
高階會員


發表:2
回覆:112
積分:217
註冊:2009-11-17

發送簡訊給我
#12 引用回覆 回覆 發表時間:2012-12-19 15:37:06 IP:114.32.xxx.xxx 訂閱
整整一年半。又偶然看到這篇突然有個想法,若不在乎可能的效率損失,可以用 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);
那該視窗就出來啦
編輯記錄
rick060 重新編輯於 2012-12-19 00:37:51, 註解 無‧
rick060 重新編輯於 2012-12-19 00:39:39, 註解 無‧
rick060 重新編輯於 2012-12-19 00:41:23, 註解 無‧
系統時間:2024-11-22 14:13:26
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!