PDA

View Full Version : سوال: چطور به پنجره یه برنامه دیگه فوکوس بدم؟



mbshareat
دوشنبه 01 آبان 1391, 08:50 صبح
سلام
من یه برنامه دارم به نام Easy Soud Player که تو این پست (http://barnamenevis.org/showthread.php?364322-%D9%85%D8%B4%DA%A9%D9%84-%D8%A8%D8%A7-%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D8%B2%D9%85%D8%A7%D9%86-%D8%AA%D9%88%D8%B3%D8%B7-%D8%AA%D8%A7%DB%8C%D9%85%D8%B1-%D9%87%D9%86%DA%AF%D8%A7%D9%85-%D9%BE%D8%AE%D8%B4-%D8%B5%D9%88%D8%AA&p=1608466&viewfull=1#post1608466) گذاشتم.
می خوام از رویداد MouseUp یه Image از یه برنامه دیگه، پنجره این برنامه رو که در حال اجراست فعال کنم.
چند تا پروسیجر رو امتحان کردم که ممکنه پارامترها رو درست نداده باشم اما هیچیک کمکی نکردند:

function FindWindowByTitle(WindowTitle: string): Hwnd;
var
NextHandle: Hwnd;
NextTitle: array[0..260] of char;
begin
NextHandle := GetWindow(Application.Handle, GW_HWNDFIRST);
while NextHandle > 0 do
begin
GetWindowText(NextHandle, NextTitle, 255);
if Pos(WindowTitle, StrPas(NextTitle)) <> 0 then
begin
Result := NextHandle;
Exit;
end
else
NextHandle := GetWindow(NextHandle, GW_HWNDNEXT);
end;
Result := 0;
end;
procedure TQuranMain.LPagePicMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Var
FormHand:THandle;
begin
FormHand:= FindWindowByTitle('Easy Sound Player');
If FormHand<>0 then
Begin
Windows.SetFocus(FormHand);
SetActiveWindow(FormHand);
SendMessage(FormHand,WM_MOUSEACTIVATE,0,0);
SendMessage(FormHand,WM_Activate,WA_CLICKACTIVE,0) ;
SendMessage(FormHand,WM_SetFocus,0,0);
SendMessage(FormHand,WM_MBUTTONDOWN,MK_LBUTTON,0);
SendMessage(FormHand,WM_MBUTTONUP,MK_LBUTTON,0);
SendMessage(FormHand,WM_MBUTTONDBLCLK,MK_LBUTTON,0 );
End;
end;


کسی میتونه بگه مشکل چیه؟

Felony
دوشنبه 01 آبان 1391, 09:12 صبح
مورد اول ؛ تابع FindWindowByTitle رو از کجا پیدا کردید ، کد به درد نخوری هستش ، وقتی شما Title یک پنجره رو داشته باشی به جای اون همه کد با تابع FindWindow میتونی پیداش کنی ( نام کلاس رو پوچ پاس میدی ) ، یعنی اون همه کد میشه این :

function FindWindowByTitle(WindowTitle: string): Hwnd;
begin
Result:= FindWindow(nil, PChar(WindowTitle));
end;

مورد دوم ؛ تو کدت شما نوشتی :

FormHand:= FindWindowByTitle('Easy Sound Player');

در صورتی که تو برنامه Easy Player ی که داری عنوان فرم این نیست و قبلش 2 کاراکتر Space وجود داره ، یعنی :

FormHand:= FindWindowByTitle(' Easy Sound Player');

مورد سوم ؛ تابع SetActiveWindow زمانی درست عمل میکنه که پنجره ای که هندلش رو به عنوان پارامتر به تابع دادید جزء همون Thread فراخوان تابع باشه ، یعنی تو یک برنامه بخواین یک فرم دیگه از همون برنامه رو فعال کنید ، برای کاری که شما میخواین انجام بدید باید از تابع SetForegroundWindow استفاده کنید :

var
Hand: THandle;
begin
Hand:= FindWindow('TMainForm', ' Easy Sound Player');
SetForegroundWindow(Hand);
end;

mbshareat
دوشنبه 01 آبان 1391, 10:12 صبح
سلام
چرا اینطور قضاوت می کنین؟ FindWindowByTitle کد به درد نخوری نیست . مورد استفادش جاییه که عنوان برنامه متغیره. در برنامه مزبور ممکنه اسم فایل هم به عنوان اضافه شه.

قبلش 2 کاراکتر Space وجود داره
ممنون اما به خاطر استفاده از FindWindowByTitle مشکلی وجود داره و پنجره هندل رو صفر گزارش نمی کنه.

باید از تابع SetForegroundWindow استفاده کنید
دستتون درد نکنه.جواب داد. به ذهنم رسیده بود ولی گفتم پنجره برنامه Easy Sound Player که خودش همیشه بالای پنجره های دیگه هستش و مقصود من فوکوس دادنه. به همین دلیل امتحانش نکردم.
اگه ممکنه میشه لطف کنین بفرمایین چرا پیغامهای ماوس عمل نکردند؟

Felony
دوشنبه 01 آبان 1391, 10:37 صبح
چرا اینطور قضاوت می کنین؟ FindWindowByTitle کد به درد نخوری نیست .

وقتی شما Title یک پنجره رو داشته باشی به جای اون همه کد با تابع FindWindow میتونی پیداش کنی
گفتم وقتی عنوان یک پنجره رو داشته باشی ، یعنی برای کار شما به درد نخور هست ( نگفته بودی عنوان برنامت ثابت نیست ) .


مورد استفادش جاییه که عنوان برنامه متغیره. در برنامه مزبور ممکنه اسم فایل هم به عنوان اضافه شه.
کاربرد اون کد بیشتر جایی هست که میخوای 2 تا کنترل که Title ندارن و از کلاس یکسانی مشتق شدن رو پیدا کنی ، مثلا کنترل Username و Password در پنجره Dialup Connection که هیچ کدوم عنوان ندارن و هر دو از یک کلاس واحد تشکیل شدن ، در این صورت وقتی از تابع FindWIndow و FindWindowEX استفاده کنی هندل اولین کنترلی که با مشخصات خواسته شده مطابقت داره واکشی میشه ، شما با اون شیوه میتونی بگی برو به کنترل بعدی ؛ البته برای این کار هم باید تغییراتی تو اون کد داده بشه .

اگر عنوان برنامت ثابت نیست کار فنی تر استفاده از تابع EnumWindowsهست ( این تابع یک Callback Function هست ) :

function FindSoundPlayer(hWnd: hWnd; lParam: lParam): boolean; stdcall;
var
TheText: array [0 .. MAX_PATH] of char;
begin
if (GetWindowText(hWnd, TheText, MAX_PATH) <> 0) and
(Pos('Easy Sound Player', TheText) > 0) then
SetForegroundWindow(hWnd);
end;

استفاده :

EnumWindows(@FindSoundPlayer, 0);

البته با همین تابع EnumWindow هم میشه اون تابعی که شما قرار دادی رو نوشت .

و در آخر به نقل از MSDN :


This function is more reliable than calling the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to a window that has been destroyed.

This Function به همون تابع EnumWindows اشاره میکنه ، پس با این حساب باز هم اون کد به درد نخور هست .