PDA

View Full Version : حرفه ای: چطور می شود از داخل یک برنامه C#‎ به اجزاء یک برنامه در حال اجرا دسترسی داشت؟



mohammad reza beizavi
چهارشنبه 15 بهمن 1393, 12:41 عصر
درود بر دوستان
یه نرم افزار در حال اجرا دارم که به برخی از اجزای اون با استفاده از class name اونها دسترسی دارم. می تونم روی کنترلهایی که class name دارند کلیک کنم و یا به بعضی از کنترلهای مشابه TextBox متن بفرستم.
اما مشکل:
بعضی از کنترلها مثل Menu و Toolbar تنها با یک Class name واحد شناخته میشند (با استفاده از Spy++) و احتمالا به همین خاطر نمیشه رویداد کلیک رو براشون فرستاد.
حالا می خواستم ببینم اساتید تجربه ای در زمینه دسترسی به اعضای یه نرم افزار دیگه از داخل C#‎‎‎‎‎ را دارند و اگر جواب مثبته چطور میشه به تک تک منو ها و زیر منوها و اجزای toolbar دسترسی داشت؟
مثلا من می خوام منوی file رو باز کنم و از قسمت open یه فایل رو انتخاب و توی برنامه باز کنم.

امیدوارم توضیحاتم روشن باشه.
اگر نیاز به توضیحات بیشتر هست کاملتر توضیح میدم.

ممنون از دوستان و اساتید

Saman_12
چهارشنبه 15 بهمن 1393, 16:02 عصر
احتمالا با GetWindowText یا WM_GetText بتونید متن منو رو بخونید.
با FindWindowEx یا EnumChild و GetParent و GetClassName هم چک کنید همه پنجره هایی با کلاس مشخص متعلق به یک پنجره اصلی هستند و متنشون رو چک کنید.(وقتی با FindWindowEx کارمی کنید ترتیبی که پیدا میکنه ثابته-البته درست یادم نیست-)
البته اینا برای حالت عادیه تا حالا با منو کار نکردم.(به نظر میرسه منو تاوقتی که روش کلیک نشه زیر پنجره ای نداره و وقتی که کلیک شد اونو میسازه) که برای این مورد هم میتونیدموس رو به مکان دلخواه روی منو ببرین و اونجا کلیک کنید تا پنجره ساخته شه بعدش بقیه کار ها.

Saman_12
چهارشنبه 15 بهمن 1393, 17:46 عصر
فهمیدم. اگر منو منو واقعی باشه (نه کنترل سفارشی) میتونید از GetMenu استفاده کنید-مث منو نوت پد-

mohammad reza beizavi
پنج شنبه 16 بهمن 1393, 00:08 صبح
ممنون بابت راهنماییتون
پیشتر گفتم که به بعضی کنترلها دسترسی دارم، اما مشکل سر اون قسمتهاییه که ClassName ندارند و تنها شناسه یکتا Handle همون کنترل هست و هیچ کدوم از متد ها external ی که فرمودید و البته overload های اونها با Handle کار نمی کنند.
مسئله بعد هم اینکه بعضی کنترلها مثل نوار ابزار کلا یه نام داره با عنوان tool_menu_all ولی Child ی داخلش نیست که بشه بهش دسترسی داشت.
ممنون میشم اگر بازم راهنمایی بفرمایید

mojtabamalaekeh
پنج شنبه 16 بهمن 1393, 08:32 صبح
سلام
این کاری که شما میخوای تا حالا نکردم
اما هروقت توی دسترسی به آبجکتی به بن بست خوردم مجبور شدم تمام کنترل ها رو لیست کنم تا ببینم اشکال کار از کجاست که نمیشه به یه آبجکت دسترسی پیدا کرد.
کدی که توی نت بود برای لیست کردن همه child ها:

private List<IntPtr> GetAllChildrenWindowHandles(IntPtr hParent, int maxCount, string className)
{
List<IntPtr> result = new List<IntPtr>();
int ct = 0;
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;
while (true && ct < maxCount)
{
currChild = FindWindowEx(hParent, prevChild, null, null);
if (currChild == IntPtr.Zero) break;
if (getClassName(currChild) == className)
result.Add(currChild);
prevChild = currChild;
++ct;
}
return result;
}
بار اول هندل پنجره اصلی رو بهش پاس میدم تا هرچی توی پنجره هست رو لیست کنه.
گرفتن هندل پنجره اصلی هم با عنوان پنجره (wTitle) انجام میدم:

IntPtr hwnd = FindWindow(null, wTitle);
List<IntPtr> children = GetAllChildrenWindowHandles(hwnd, 100, "#32770");
حالا لیست هندل های هرچی که تو پنجره اصلی هست داخل children موجوده که با حلقه for به یه listBox اضافه شون میکنم و موقع انتخاب هر آیتم از listBox دوباره تابع GetAllChildrenWindowHandles رو فراخوانی می کنم اما این بار نه با هندل پنجره ی اصلی، بلکه با مقداری که از توی لیست انتخاب شده!
ایندفعه لیست هندل هایی که به دست میاد باید به یه listBox دیگه اضافه بشه که اگه بخوایم اصولی تا تهش پیش بریم بهتره ساختار درختی استفاده بشه نه listBox

در ضمن پارامتر سوم تابع GetAllChildrenWindowHandles رو اول کار میتونی حذف کنی. من آخر سر که فهمیدم کلاس اشیاء مورد نظرم چیه ("#32770") اینو اضافه کردم که جستجو محدود بشه.
اگر حذفش کردی، شرط زیر رو هم حذف کن:

if (getClassName(currChild) == className)


حالا همه این کارها برا چی بود؟ این ها که فقط لیست کردن هندل ها بود. هندل هم یه شماره است که معلوم نیست menu, frame, textbox و ... باشه؟
هدف این بود که بعد از لیست کردن هندل ها، یه رویداد به عنوان تست روی هندلی که از لیست انتخاب کردی، اجرا کنی ببینی آبجکت مورد نظرت واکنشی نشون میده یا نه؟
مثلا من رو تک تک هندل های لیست شده، تابع SendMessage رو با هدف تغییر text تست میکردم چون دنبال یه جعبه متن میگشتم. شما SendMessage رو با هدف کلیک شدن، تست کن چون دنبال یه منو میگردی.

فکر نکنم دکمه های نوار ابزار یا نوار منو، جزو لیست بچه های اون نوار نباشن. شما یک نوار (ابزار یا منو) رو به این روش ازش لیست فرزند بگیرید معلوم میشه.

Saman_12
پنج شنبه 16 بهمن 1393, 11:46 صبح
در تمام API هایی که نام بردم Handle به عنوان اولین پارمتر هست!(+SendMessage)
برای منو های استاندارد از همون GetMenu استفاده کنید و API های مربوطه.(GetSubMenu - GetMenuInfo - GetMenuItemID و ...) - منوی استاندارد یا واقعی تعریف م(ا-ی)کروسافته-
برای اونای هم که استاندارد نیستن فعلا این به نظرم میرسه که برنامه رو فعال کنید بعد Alt رو بفرستید بعد هم با ارسال Left - Right-Down-Up به برنامه بین منو ها جابه جا بشید (SendKeys یا WM_KeyDown/UP یا SendInput) یا موس رو روی منوی مورد نظر قرار بدین و کار های قبل رو با موس بکنید.(SetCursor - SetInput - WM_LBUTTONDOWN/UP - Mouse_Event - System.Windows.Forms.Cursor)