ورود

View Full Version : تبديل PID به هندل پنجره برنامه



FiACKER
جمعه 21 فروردین 1388, 11:17 صبح
سلام

دوستان مي شه لطف كنيد و بگيد چطور با داشتن pid يك پروسه ، هندل پنجره ي (window) اون پروسه رو بدست بيارم ؟

تشكر

vcldeveloper
جمعه 21 فروردین 1388, 18:05 عصر
نمیدونم آیا API مستقیمی برای این کار هست یا نه، ولی می تونید با استفاده از EnumWindows لیست پنجره های باز را بدست بیارید، و با استفاده از GetWindowThreadProcessId هم Process ID مربوط به هر پنجره را بدست بیارید، و با مقایسه آن با Process ID مورد نظرتان، متوجه بشید که آیا پنجره مربوط به اون Process هست یا نه.

FiACKER
شنبه 22 فروردین 1388, 11:51 صبح
سلام

تشکر از جوابتون.
یه همچین سورسی دارم ولی مشکل اینجاست که زمانه این کار بالاست !
من یه همچین کدی داشتم تویه وی بی که خیلی راحت و بدونه Enum کردن هندل رو می داد !
فکر کنم با همین تابع GetWindowThreadProcessId بود. با چد خط دستور هندل رو از طریقه pid می گرفت.
رفتم خونه کد رو می زارم ببینید می تونید کاری کنید...
خودم که امتحان کردم نتونستم.

ممنون

FiACKER
شنبه 22 فروردین 1388, 18:40 عصر
ببخشيد ! ببخشيد !
من گفته ي اخيره خود رو در مورد اينكه بدونه Enum کردن هندل رو بدست مي اوردم ، شديدا تكذيب مي كنم و از بروبچز عذر مي خوام....
اصلا يادم نبود... اونم Enum مي كنه البته كدش خيلي ساده تر هست...

vcldeveloper
شنبه 22 فروردین 1388, 18:53 عصر
اونم Enum مي كنه البته كدش خيلي ساده تر هست...
ساده تر از چی؟!

FiACKER
یک شنبه 23 فروردین 1388, 00:35 صبح
ساده تر از كدي كه تويه دلفي براي اين كار نوشته مي شه !

خودم يه چيزايي نوشتم.
ولي نمي دونم چرا كار نمي ده. در كله برنامه فقط همين يه if هم كار نمي ده ! شما ببينيد مشكلش چيه... به هر حال من تازه كارم و از شي گرايي دلفي چيزه زيادي نمي دونم...شايد از نحوه استفاده از توابع تو در تو باشه...راستي اسمه اين كار چيه ؟

اون خطي كه bold شده رو اگه pid رو مستقيما بنويسم (به جايه Pid بنويسم مثلا 4565) جواب مي ده ! و اصلا مشكلي نداره.




function Hwnd_To_Pid(WhatHandle : HWND):DWORD;
var pid : dword ;
begin
GetWindowThreadProcessId(WhatHandle, pid);
result := pid;
end;

Function TForm1.GetProcessList(Pid : DWORD):TStringList;
function EnumWindowsProc (Wnd: HWND; List: TStrings): BOOL; stdcall;
var
caption: array [0..256] of Char;
GetPid : DWORD ;
begin
Result := True;
if GetWindowText (Wnd, Caption, SizeOf(Caption)-1) <> 0 then
begin
if IsWindowVisible(wnd) then
begin
GetPid := Hwnd_To_Pid(wnd) ;
if (GetPid = Pid) then
List.AddObject( caption, TObject( Wnd ));
end;
end;
end;
begin
Result:=TStringList.Create;
EnumWindows(@EnumWindowsProc, Integer(result));
end;


استفاده:


procedure TForm1.Button1Click(Sender: TObject);
var
asdf : TStrings ;
i : Integer ;
begin
asdf := GetProcessList(696);
for i:=0 to asdf.Count-1 do
begin
lst1.Items.Add(asdf.Strings[i]);
end;
end;

FiACKER
یک شنبه 23 فروردین 1388, 00:46 صبح
اقا بله ! خودشه ! مثله اينكه مشكل استفاده از متغييره Pid از تابع GetProcessList هست !اين متغيير با اينكه دارايه مقدار pid مورده نظر هست، ولي در مقايسه كار نمي ده !

ايا راه حلي داريد براي اينكار ؟

FiACKER
یک شنبه 23 فروردین 1388, 00:53 صبح
خودم براي اين كار يه متغيير در بخش متغييرهاي عمومي فرم قرار دادم كه مشكل حل شد.
و اون متغيير عمومي رو در تابع GetProcessList با pid مقدار دهي كردم.

اما اينكار از پُرتابليه تابع مي كاهه ! به خاطره اينكه اگه خواستم در جايه ديگه از اين تابع استفاده كنم مجبورم اون متغييره عمومي رو هم در يونيته مربوطه تعريف كنم.

با تغيير دادن نوع متغييره pid هم نتونستم به جايي برسم... به integer و cardinal و longint تغيير دادم ولي بازم كار نداد.

اقايه كشاورز نظره شما چيه ؟

vcldeveloper
یک شنبه 23 فروردین 1388, 03:09 صبح
هر چند شما به جواب رسیدید، یک کد برای مطالعه شما و سایر کاربرانی که بعدا به این تاپیک مراجعه خواهند کرد، قرار میدم.
این کد بیشتر از اون چیزی هست که شما نیاز داشتید. بخشی از کدهای اضافی برای این هستند که در این کد از یک روش شی گرا بجای توابع و متغیرهای Global استفاده شده؛ همه چیز در داخل کلاس های مربوطه کپسوله سازی شده. بخش دیگه هم برای این هستند که چگونگی استفاده از قابلیت های مختلف دلفی مثل ایجاد interfaceها، Enumeratorها، متدهای static، و غیره نمایش داده بشند، تا بشه بعدا به این کد به عنوان مثالی برای آن قابلیت ها ارجاع داد.



/// <summary>
/// TProcessWinEnumerator enumerates top-level windows which belong to a given process.
/// </summary>
///
/// <author>Ali Keshavarz</author>
/// <date> 2009/04/12 </date>

unit uProcessWinEnumerator;

interface

uses Windows, SysUtils, Classes;

type
TWinInfo = record
Caption : string;
Handle : THandle;
end;

TWinInfoEnumerator = class
private
FList : TStringList;
FListIndex: integer;
public
constructor Create(AList: TStringList);
function GetCurrent: TWinInfo;
function MoveNext: boolean;
property Current: TWinInfo read GetCurrent;
end;

IProcessWindowsList = interface
function GetCount: integer;
function GetItem(Index: integer): TWinInfo;
procedure SetItem(Index: integer; const Value: TWinInfo);
function GetProcessID: Cardinal;
procedure SetProcessID(Value: Cardinal);
function GetEnumerator: TWinInfoEnumerator;
procedure UpdateWindowsList;
property ProcessID: Cardinal read GetProcessID write SetProcessID;
property Count: integer read GetCount;
property Items[Index: integer]: TWinInfo read GetItem write SetItem; default;
end;

TProcessWindowsList = class(TInterfacedObject, IProcessWindowsList)
private
FProcessID : Cardinal;
FWindowsList : TStringList;
function GetCount: integer;
function GetItem(Index: integer): TWinInfo;
procedure SetItem(Index: integer; const Value: TWinInfo);
function GetProcessID: Cardinal;
procedure SetProcessID(Value: Cardinal);
class function EnumWindowsProc(hwnd: THandle; lparam: integer): Bool; stdcall; static;
public
constructor Create(AProcessID: Cardinal);
destructor Destroy; override;
function GetEnumerator: TWinInfoEnumerator;
procedure UpdateWindowsList;
property ProcessID: Cardinal read GetProcessID write SetProcessID;
property Count: integer read GetCount;
property Items[Index: integer]: TWinInfo read GetItem write SetItem; default;
end;

/// <summary>
/// Factory function which returns a list of windows belonging to a given process.
/// </summary>
function GetProcessWindows(ProcessID: Cardinal): IProcessWindowsList;

implementation

uses Messages;


{ TWinInfoEnumerator }

constructor TWinInfoEnumerator.Create(AList: TStringList);
begin
FList := AList;
FListIndex := -1;
end;

function TWinInfoEnumerator.GetCurrent: TWinInfo;
begin
Result.Caption := FList[FListIndex];
Result.Handle := THandle(FList.Objects[FListIndex]);
end;

function TWinInfoEnumerator.MoveNext: boolean;
begin
Inc(FListIndex);
Result := (FListIndex < FList.Count);
end;


{ TProcessWinEnumerator }

constructor TProcessWindowsList.Create(AProcessID: Cardinal);
begin
FProcessID := AProcessID;
FWindowsList := TStringList.Create;
UpdateWindowsList;
end;

destructor TProcessWindowsList.Destroy;
begin
FreeAndNil(FWindowsList);

inherited;
end;

/// <summary>
/// Callback function called by EnumWindows API function every time a top-level window
/// is enumerated.
/// </summary>
///
/// <param name='hwnd'> Handle of the enumerated window</param>
/// <param name='lparam'> An applicatin defined value - passes a TProcessWinEnumerator instance to the callback function.</param>
///
/// <returns> True, if enumeration should be continued.</returns>
///
class function TProcessWindowsList.EnumWindowsProc(hwnd: THandle; lparam: integer): Bool;
var
Instance : TProcessWindowsList;
PID : Cardinal;
WindowCaption : string;
CaptionLength : integer;
begin
Result := False;
//Retriev current instance from lparam. class functions do not have implicit Self parameter.
Instance := TProcessWindowsList(lparam);
if not Assigned(Instance) then Exit;
//Get process ID of the enumerated window, and compare it with the desired processID.
GetWindowThreadProcessId(hwnd,PID);
//If the two process IDs match, then add caption of the enumerated window to the list.
if PID = Instance.ProcessID then
begin
//Get length of enumerated window's caption.
CaptionLength := SendMessage(hwnd,WM_GETTEXTLENGTH,0,0) + 1;
SetLength(WindowCaption,CaptionLength);
//get caption of enumerated window.
SendMessage(hwnd,WM_GETTEXT,CaptionLength,Integer( PChar(WindowCaption)));
WindowCaption := Trim(WindowCaption);
//Add window caption to the list, also add window handle as an object to the list.
Instance.FWindowsList.AddObject(WindowCaption,TObj ect(hwnd));
end;
Result := True;
end;

function TProcessWindowsList.GetCount: integer;
begin
Result := FWindowsList.Count;
end;

function TProcessWindowsList.GetEnumerator: TWinInfoEnumerator;
begin
Result := TWinInfoEnumerator.Create(FWindowsList);
end;

function TProcessWindowsList.GetItem(Index: integer): TWinInfo;
begin
Result.Caption := FWindowsList[Index];
Result.Handle := THandle(FWindowsList.Objects[Index]);
end;

function TProcessWindowsList.GetProcessID: Cardinal;
begin
Result := FProcessID;
end;

procedure TProcessWindowsList.SetItem(Index: integer; const Value: TWinInfo);
begin
FWindowsList[Index] := Value.Caption;
FWindowsList.Objects[Index] := TObject(Value.Handle);
end;

procedure TProcessWindowsList.SetProcessID(Value: Cardinal);
begin
FProcessID := Value;
end;

/// <summary>
/// Refreshes windows list for the given process ID (ProcessID property).
/// </summary>
procedure TProcessWindowsList.UpdateWindowsList;
begin
EnumWindows(@EnumWindowsProc,Integer(Self));
end;


function GetProcessWindows(ProcessID: Cardinal): IProcessWindowsList;
begin
Result := TProcessWindowsList.Create(ProcessID);
end;

end.




روش استفاده:



for Window in GetProcessWindows(ProcessID) do
Memo1.Lines.Add(IntToStr(Window.Handle) + ' : ' + Window.Caption);
* برای سایر روش های استفاده از این، به پروژه ضمیمه شده مراجعه کنید.

به همراه این کد، یک پروژه نمونه هم برای نمایش روش های استفاده ازش ضمیمه کردم. به سه روش برای استفاده از کد اشاره شده، که روش های دوم و سوم فقط در دلفی 2007 و 2009 کامپایل میشند. همچنین، اگر از نسخه های قدیمی دلفی مثل دلفی 7 استفاده می کنید، امکان استفاده از توابع static را هم نخواهید داشت، پس کاربرانی که قصد کامپایل کد با نسخه های قدیمی دلفی را دارند:
1- تعریف تابع EnumWindowsProc در کلاس TProcessWindowsList را باید به یک تابع عمومی (خارج از کلاس) و بدون راهنمای کامپایلر static تبدیل کنند؛ یعنی:

function EnumWindowsProc(hwnd: THandle; lparam: integer): Bool; stdcall;

2- در مثال ضمیمه شده، کدهایی که در آنها از ساختار for...in استفاده شده است (کد OnClick مربوط به Button2 و Button23) حذف کنند.


در این کد این موارد نمایش داده شده است:


چگونگی تعریف و استفاده از Interfaceها.
چگونگی تعریف Enumerators و استفاده از آنها توسط ساختار for...in
چگونگی تعریف و استفاده از خصوصیت Default برای یک کلاس.
چگونگی استفاده از تابع EnumWindow برای لیست کردن پنجره های باز در سیستم.