PDA

View Full Version : سوال: پیدا کردن هندل پنجره ی فرزند بعدی



vasilopita
پنج شنبه 04 مهر 1392, 11:47 صبح
سلام. من یه پنجره ی دیالوگ دارم. حالا این پنجره هم چندتا پنجره ی فرزند داره که همشون از یک کلاس ان و کپشن هم ندارن و هرکدومشون هم یه پنجره ی فرزند داره. حالا فرض کنید من هندل نوه ی آخر رو بخوام.

اینم تصویرش
111207
اینم کد من:

if(phwnd=FindWindow(NULL,L"Rename"))
if(chwnd1=FindWindowEx(phwnd,NULL,L"DirectUIHWND",NULL))
while(chwnd2=FindWindowEx(chwnd1,NULL,L"CtrlNotifySink",NULL))
{
if(phwnd=FindWindowEx(chwnd2,NULL,L"Button",L"&Yes"))
resault=SendMessage(phwnd,WM_COMMAND,IDYES,0L);
chwnd1=GetWindow(chwnd1,GW_HWNDNEXT);
}
ولی کدم جواب نمیده! مشکل از کجاست ؟
ممنونم

mehdi.mousavi
پنج شنبه 04 مهر 1392, 12:50 عصر
سلام.
من کدتون رو اجرا نکردم، حقیقتش فرصتش رو ندارم اما کدی که نوشته اید از نظر منطقی صحیح نیست.
اما در واقع سوال اصلی اینه، که چرا شما از EnumChildWindows (http://msdn.microsoft.com/en-us/library/ms633494%28v=VS.85%29.aspx) استفاده نمی کنید که نیازی به نوشتن تابع
Recursive نداشته باشید؟ اینطوری کدتون خیلی بهتر و خواناتر هم خواهد شد...

لطفا یه امتجان بکنید، اگر موفق نشدید یه پروژه ساده شده (که Dialog ای باشه، با چند تا Control مورد نظرتون
که فقط مساله رو بشه باهاش حل کرد) برای من ارسال کنید تا کدش رو براتون بنویسم.

موفق باشید.

Felony
پنج شنبه 04 مهر 1392, 18:31 عصر
@mehdi.mousavi :
دلمون برات تنگ شده حاجی ... :)


من کدتون رو اجرا نکردم، حقیقتش فرصتش رو ندارم اما کدی که نوشته اید از نظر منطقی صحیح نیست.
اما در واقع سوال اصلی اینه، که چرا شما از EnumChildWindows استفاده نمی کنید که نیازی به نوشتن تابع
Recursive نداشته باشید؟
بعضی وقت ها EnumChildWindow کارامد نیست ، مثلا برنامه ای رو فرض کنید که تو قسمتیش 3 تا ادیت پشت هم داره ( منظور از پشت هم z-order شون هست ، هر 3 از کلاس TextBox و هر سه متنشون خالی هست ، با تابع EnumChildWinodw میشه هندلشون رو به دست آورد ولی از کجا بدونیم کدوم هندل ، هندل ادیت سوم هست ؟ نه میشه عنوان پنجره مربوط به هندل رو گرفت ( عنوان خالیه ) ، نه میشه کلاسش رو گرفت ( کلاسشون یکیه ) و نه ...

در این صورت باید با هر روشی به ادیت اولی رسید و بعد با تابع GetNextWindow (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633509(v=vs.85).aspx) و پاس دادن هندل پنجره جاری به عنوان پارامتر اول و GW_HWNDNEXT به عنوان پارامتر دوم بیاید و هندل پنجره بعدی رو به دست بیارید ، تا اینجا ادیت دوم به دست اومد ، حالا باید یک بار دیگه با همین تابع هندل پنجره بعدی رو به دست بیارید که میشه ادیت سوم ، این روش به نوعی Hard Code هست چون باید به تعداد پنجره ها باید تابع GetNextWindow رو صدا بزنید ، ولی گاهی موارد چاره ای نیست و توی نوشتن ابزارهای امنیتی ، Bypass و این قبیل موارد زیاد کاربرد داره .

مثلا یادمه تو ویندوز XP پنجره Dialup Connection همین طور بود و 2 تا ادیت Username و Password پشت سر هم قرار داشت و وقتی میخواستی با DLL Injection پسورد موجود تو ادیت دوم رو به دست بیاری باید با همین روش به هندل ادیت دوم که پسورد بود میرسیدی .

موفق باشید .

vasilopita
جمعه 05 مهر 1392, 00:27 صبح
لطفا یه امتجان بکنید، اگر موفق نشدید یه پروژه ساده شده (که Dialog ای باشه، با چند تا Control مورد نظرتون
که فقط مساله رو بشه باهاش حل کرد) برای من ارسال کنید تا کدش رو براتون بنویسم.

بعد از کلی سرچ تو اینترنت و نرسیدن به هیچ جوابی سعی کردم همچین دیالوگی رو بسازم اما نتونستم. من خودم روی اون دیالوگی کار کردم که وقتی می خوای یه فایل تکس رو فرمتش رو تغییر بدی یه دیالوگ میاد بالا به اسم Rename و در مورد تغییر فرمت سوال میکنه!عکسش هم تو همون پست اولیه که گذاشتم. اگه ممکنه شما هم همین کار رو کنید و روی همین دیالوگ کار کنید. ممنونم


@mehdi.mousavi :
دلمون برات تنگ شده حاجی ... :)

من کدتون رو اجرا نکردم، حقیقتش فرصتش رو ندارم اما کدی که نوشته اید از نظر منطقی صحیح نیست.
اما در واقع سوال اصلی اینه، که چرا شما از EnumChildWindows استفاده نمی کنید که نیازی به نوشتن تابع
Recursive نداشته باشید؟
بعضی وقت ها EnumChildWindow کارامد نیست ، مثلا برنامه ای رو فرض کنید که تو قسمتیش 3 تا ادیت پشت هم داره ( منظور از پشت هم z-order شون هست ، هر 3 از کلاس TextBox و هر سه متنشون خالی هست ، با تابع EnumChildWinodw میشه هندلشون رو به دست آورد ولی از کجا بدونیم کدوم هندل ، هندل ادیت سوم هست ؟ نه میشه عنوان پنجره مربوط به هندل رو گرفت ( عنوان خالیه ) ، نه میشه کلاسش رو گرفت ( کلاسشون یکیه ) و نه ...

در این صورت باید با هر روشی به ادیت اولی رسید و بعد با تابع GetNextWindow و پاس دادن هندل پنجره جاری به عنوان پارامتر اول و GW_HWNDNEXT به عنوان پارامتر دوم بیاید و هندل پنجره بعدی رو به دست بیارید ، تا اینجا ادیت دوم به دست اومد ، حالا باید یک بار دیگه با همین تابع هندل پنجره بعدی رو به دست بیارید که میشه ادیت سوم ، این روش به نوعی Hard Code هست چون باید به تعداد پنجره ها باید تابع GetNextWindow رو صدا بزنید ، ولی گاهی موارد چاره ای نیست و توی نوشتن ابزارهای امنیتی ، Bypass و این قبیل موارد زیاد کاربرد داره .

مثلا یادمه تو ویندوز XP پنجره Dialup Connection همین طور بود و 2 تا ادیت Username و Password پشت سر هم قرار داشت و وقتی میخواستی با DLL Injection پسورد موجود تو ادیت دوم رو به دست بیاری باید با همین روش به هندل ادیت دوم که پسورد بود میرسیدی .

موفق باشید .

الان این صحبت شما از لحاظ منطقی چه تفاوتی با کد من داره! در واقع مشکل کد من چیه!؟
if(phwnd=FindWindow(NULL,L"Rename"))
if(chwnd1=FindWindowEx(phwnd,NULL,L"DirectUIHWND",NULL))
{
chwnd2=GetTopWindow(chwnd1);
while(1)
{
chwnd3=GetNextWindow(chwnd2,GW_HWNDNEXT);
if(chwnd1=FindWindowEx(chwnd3,NULL,L"Button",L"&Yes"))
break;
}
}

Felony
جمعه 05 مهر 1392, 12:55 عصر
الان این صحبت شما از لحاظ منطقی چه تفاوتی با کد من داره! در واقع مشکل کد من چیه!؟
از لحاظ منطقی مشکلی نداره ، من توضیحات رو برای روشن شدن دلیل این نوع استفاده دادم ، شما تا برنامه ای که قصد دراوردن هندلش رو داری ، نزاری یا معرفیش نکنی نمیشه کمکی خاصی کرد ، کد در ظاهر مشکلی نداره ولی در هر صورت اشتباه در ترتیب به دست آوردن هندل ها یا نادیده گرفته شدن هندل یک والد یا ... مشکل ساز شده که باید تستش کرد .

mehdi.mousavi
جمعه 05 مهر 1392, 13:21 عصر
@mehdi.mousavi : دلمون برات تنگ شده حاجی ... :)

سلام. :)
همچنین! چند صباحی دور بودم از سایت...


بعضی وقت ها EnumChildWindow کارامد نیست ، مثلا برنامه ای رو فرض کنید که تو قسمتیش 3 تا ادیت پشت هم داره ( منظور از پشت هم z-order شون هست ، هر 3 از کلاس TextBox و هر سه متنشون خالی هست ، با تابع EnumChildWinodw میشه هندلشون رو به دست آورد ولی از کجا بدونیم کدوم هندل ، هندل ادیت سوم هست ؟ نه میشه عنوان پنجره مربوط به هندل رو گرفت ( عنوان خالیه ) ، نه میشه کلاسش رو گرفت ( کلاسشون یکیه ) و نه ... در این صورت باید با هر روشی به ادیت اولی رسید و بعد با تابع GetNextWindow (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633509(v=vs.85).aspx) و پاس دادن هندل پنجره جاری به عنوان پارامتر اول و GW_HWNDNEXT به عنوان پارامتر دوم بیاید و هندل پنجره بعدی رو به دست بیارید ، تا اینجا ادیت دوم به دست اومد ، حالا باید یک بار دیگه با همین تابع هندل پنجره بعدی رو به دست بیارید که میشه ادیت سوم ، این روش به نوعی Hard Code هست چون باید به تعداد پنجره ها باید تابع GetNextWindow رو صدا بزنید ، ولی گاهی موارد چاره ای نیست و توی نوشتن ابزارهای امنیتی ، Bypass و این قبیل موارد زیاد کاربرد داره. مثلا یادمه تو ویندوز XP پنجره Dialup Connection همین طور بود و 2 تا ادیت Username و Password پشت سر هم قرار داشت و وقتی میخواستی با DLL Injection پسورد موجود تو ادیت دوم رو به دست بیاری باید با همین روش به هندل ادیت دوم که پسورد بود میرسیدی. موفق باشید .

تابعی که Stable نیست، FindWindow هستش و لزوما نمیتونه Handle به Window ی مورد نظر رو در همه شرایط برگردونه. حالا اینکه در یک سناریوی خاص، EnumChildWindow نمیتونه ما رو به هدفمون برسونه، اون یه بحث دیگه است. :) اینجا، برای این سوال، گزینه خوبیه.


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

بسیار خوب، من با پست اول شما متوجه نشدم منظورتون کدوم پنجره بوده، اما با توضیحی که دادید متوجه منظورتون شدم که کدوم Dialog رو میگید... کد شما، مشکلش اینه که FindWindow اون پنجره DirectUIHWND رو پیدا نمیکنه. بعد هم Loop رو بنظرم اصلا خوب ننوشتید و خیلی بهتر و کارآمد تر میشد اونو نوشت. در هر حال، همونطوریکه گفتم، FindWindow حواشی عجیب و غریبی داره و نمیشه زیاد بهش اتکا کرد. الان خاطرم نیست که بخوام دقیقا بگم در کدام شرایط نباید ازش استفاده کنید، اما با جستجویی رو اینترنت حتما میتونید به پاسخ این سوال برسید. من چون مطمئن نبودم شما از MFC استفاده می کنید یا خیر، توابع Win32 رو Call کردم و با استفاده از EnumChildWindows کد مورد نظرتون رو نوشتم:

HWND hWndParent = ::FindWindow(NULL, _T("Rename"));
if(hWndParent)
::EnumChildWindows(hWndParent, EnumChildProc, NULL);


سپس، تابع Callback ای باید تعریف کنیم که OS اون تابع رو Call کنه:

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
TCHAR szText[256];
::GetWindowText(hwnd, szText, 256);

if(_tcscmp(szText, _T("&Yes")) == 0)
{
//This is the window you're seeking for...
return FALSE;
}

return TRUE;
}


اینجا، به ازای تک تک Child Window های موجود در Parent Window، تابع فوق Call میشه. سپس، من Title پنجره رو میگیرم و بررسی میکنم که &Yes هست یا خیر. اگر بود، حالا می تونید در درون if با اون hwnd هر کاری مایل بودید انجام بدید. فقط دفت کنید که در if مورد نظر، FALSE رو به Caller برگردوندم. این یعنی اینکه من کارم رو انجام دادم و دیگه نیازی نیست Callback Function ام رو برای مابقی Child Window ها Call کنی.

موفق باشید.