Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Как определить является ли класс потомком TWinControl...


DayGaykin ©   (12.08.17 21:24

... в чужом процессе?

Начну с преамбулы.

В общем задача кликать и заполнять поля в чужом приложении. Приложение написано на Delphi 2006.
Моя программа на Java (а точнее на Kotlin)

Сначала я думал, что это будет обычный набор SendMessage, но в процессе возникает TMessageForm (стандартные диалоги), а с помощью WinApi считать с них текст нельзя (разве что только Ctrl+C посылать). Плюс, наверняка нельзя понять какой Edit мне использовать, т.к. не к чему привязаться.

Немного покопав я смог залезть в процесс этого приложения (да да, на яве) и достать из него список компонентов и контролов формы с названием классов, именем и текстом, а также со списком дочерних контролов. Делаю это простым чтением памяти процесса и переходя по указателям.

Но вот знаний устройства классовой модели delphi не хватает: список контролов я могу получить, а понять есть ли у компонента этот самый список контролов или нет - не могу. И спрашиваю.

Пока есть еще такая идея: найти на форме все дочерние окна, на основе них составить список WinControl-ов, а потом просто проверять есть ли компонент в списке или нет. Может проще есть?

P.S. Занимаюсь этим очередным извращением на работе.


Игорь Шевченко ©   (12.08.17 21:53[1]

Use SendInput, Luke

Я несколько не понимаю, зачем тебе именно WinControl, обычно, для автоматизированного заполнения окон хватает API Windows.
И да, на сайте есть много разделов форума и сообщения желательно писать не только в Прочее.


Leonid Troyanovsky ©   (13.08.17 10:11[2]


> DayGaykin ©   (12.08.17 21:24) 

> проверять есть ли компонент в списке или нет. Может проще
> есть?

Натравить на приложение Winsight (ws32.exe) или прочий Spy+.

Ну, или EnumChildWindows с получением классов окон и прочей
информации, позволяющей идентифицировать окно ввода.
Кста, это могут быть и координаты окна.
Наверное, еще потребуется знать про юникодность.

Ну, а потом решать, чем именно заполнять,
бо SendInput|keybd_event - оно совсем на край.

--
Regards, LVT.


DayGaykin ©   (14.08.17 12:15[3]


> Кста, это могут быть и координаты окна.
>

По координатам не очень удобно, потому что приложение "растягивается", а наблюдать за ним будут по RDP и я боюсь последствий разных разрешений.

> Winsight

У меня плохие ассоциации с этой программой. Я помню что она работала ровно один раз между перезагрузками:) Я Сашиной программой WndInfo пользуюсь

.
> EnumChildWindows с получением классов окон

Я примерно так сделал. Получил список окон, потом с помощью user32.GetProp('Delphi...') получил указатель на экземпляр класса.  А затем с помощью нескольких ReadProcessMemory считал имя компонента.
Тем самым я получил список WinControl-ов на форме.
Затем аналогичным образом я считываю список всех контролов формы (нахожу по смещение поле FControls и FWinControls и считываю).

Мне кажется я выбрал не самый простой путь, но да ладно.

Спасибо за помощь.


D7   (14.08.17 20:50[4]

TWinControl это класс библиотеки VCL. В чужом процессе никаких TWinControl нету.
Даже если чужая написана на Делфи - не факт что на абсолютно идентичной версии VCL.

Если вам надо работать с чужой программой просто берите EnumThreadWindows(), EnumChildWindows(), GetWindowRect(), GetClientRect(), GetClassName(), GetWindowText(), SendMessage().
Нафига вам ReadProcessMemory()??


D7   (14.08.17 20:53[5]

> но в процессе возникает TMessageForm (стандартные диалоги), а с помощью WinApi считать с них текст нельзя

Я не помню как именно реализовано TMessageForm (не факт что все через "стандартные"), но на WinApi считать можно что угодно и откуда угодно.


DayGaykin ©   (14.08.17 23:14[6]


> Я не помню как именно реализовано TMessageForm (не факт
> что все через "стандартные"), но на WinApi считать можно
> что угодно и откуда угодно

Попробуйте.


Игорь Шевченко ©   (15.08.17 10:36[7]


> Попробуйте.


Я пробовал, получилось.


Leonid Troyanovsky ©   (15.08.17 10:56[8]


> DayGaykin ©   (14.08.17 12:15) [3]

> Тем самым я получил список WinControl-ов на форме.

IMHO, перечисленное путем  EnumChildWindows и есть TWinControl,
бо у TControl окон нет (всякие AllocHwnd не в счет - они верхнего уровня).

> Мне кажется я выбрал не самый простой путь, но да ладно.

Мне не очень ясно, причем тут TMessageForm, т.к. у него Edit'ов нет,
а лежащий на нем TLabel is TControl, т.е. читать его путем
SendMessage никак не получится.

Про Edit мне непонятно, то, что как при таком уровне идентификации
(есть доступ к  самому экземпляру контрола) остаются к.л. трудности
чтения/установки его текста.

--
Regards, LVT.


D7   (15.08.17 19:55[9]

Была бы более конкретная постановка задачи - попробовал бы. А так не особо понятно - что именно пробовать-то...


DayGaykin ©   (16.08.17 20:27[10]


> D7   (15.08.17 19:55) [9]
> Была бы более конкретная постановка задачи - попробовал
> бы. А так не особо понятно - что именно пробовать-то...
>
>

Сделай программу, состоящую из ShowMessage('Hello World'), запусти, а потом с помощью другой программы попробуй считать текст всплывшего окна.


> Я пробовал, получилось.


Если можно в двух словах, напишите, как?


> Мне не очень ясно, причем тут TMessageForm, т.к. у него
> Edit'ов нет,
> а лежащий на нем TLabel is TControl, т.е. читать его путем
> SendMessage никак не получится.

Так мне как раз текст этого TLabel и нужно читать (в том числе), чтобы понять что у меня спрашивает программа.


> Про Edit мне непонятно, то, что как при таком уровне идентификации
> (есть доступ к  самому экземпляру контрола) остаются к.л.
>  трудности
> чтения/установки его текста.

С Edit трудностей нет. WM_SETTEXT работает отлично.

Еще вопрос: На форме есть PageControl, при открытии вкладки он подгружает ее содержимое (создает вложенную форму). Но из своей программы я никак не могу открыть эту вкладу. TCM_SETCURSEL просто переключает "страничку", но сама страница не показывается. А пока она не показывается, у TabSheet нет окна, чтобы ему сделать Show.

TCM_GETITEMRECT, а потом кликнуть - тоже не работает, т.к. судя по всему Windows не "маршалит" "RECT structure" этого сообщения.
Горячей клавиши на вкладке нет.

Подскажите, что можно сделать?


Игорь Шевченко ©   (16.08.17 20:48[11]


> Если можно в двух словах, напишите, как?


Через Clipboard


D7   (16.08.17 22:55[12]

Ага. Имело место быть некоторое недопонимание. Из-за того что вопрос был:

> Как определить является ли класс потомком TWinControl...

А выяснилось что на самом деле нужно:

> Так мне как раз текст этого TLabel и нужно читать

А как раз TLabel же не является TWinControl, у него нет дескриптора. Оно является просто неким рисунком на клиентской области окна...
Тогда да, уже сложнее, надо хорошенько подумать.

> А пока она не показывается, у TabSheet нет окна, чтобы ему сделать Show.

А вот TabSheet это уже TWinControl, у него есть дескриптор/окно. И всегда есть. Просто может оказаться что оно "NOT WS_VISIBLE", и всё что на нём лежит тоже всегда есть но может быть "NOT WS_VISIBLE".
Попробуйте TCM_SETCURFOCUS или TCN_SELCHANGE.


D7   (16.08.17 23:14[13]

Потыкал палочкой в VCL.
Пробуйте вариант #1:
var NMHdr: tagNMHDR;
begin
NMHdr.hwndFrom:=PageControlHandle;
SendMessage(NMHdr.hwndFrom, TCM_SETCURSEL, TabIndex, 0);
NMHdr.code:=TCN_SELCHANGE;
SendMessage(NMHdr.hwndFrom, WM_NOTIFY, NMHdr.hwndFrom, Integer(@NMHdr));

Пробуйте вариант #2:
SendMessage(PageControlHandle, TCM_SETCURFOCUS, TabIndex, 0);

Но если всё же требуется не "показывать/переключать", а просто доставать информацию - это и без листания вкладок можно, все контролы существуют и доступны, просто невидимые.


Leonid Troyanovsky ©   (17.08.17 12:51[14]


> DayGaykin ©   (16.08.17 20:27) [10]

> Если можно в двух словах, напишите, как?

Самое простое как Игорь написал.
У TMessageForm есть метод  WriteToClipBoard, вызываемый при нажатии ctrl-C.

> из своей программы я никак не могу открыть эту вкладу. TCM_SETCURSEL
> просто переключает "страничку", но сама страница не показывается.

Видимо, создание вкладки просходит на OnChange, but MSDN
"A tab control does not send a TCN_SELCHANGING or TCN_SELCHANGE notification message when a tab is selected using this message."

Похоже, что нужно  как  у D7   (16.08.17 23:14) [13] вариант #2

--
Regards, LVT.


DayGaykin ©   (17.08.17 14:24[15]


> Игорь Шевченко ©   (16.08.17 20:48) [11]
> > Если можно в двух словах, напишите, как?
> Через Clipboard

В [0] я это упоминал.


> Похоже, что нужно  как  у D7   (16.08.17 23:14) [13] вариант
> #2

> Пробуйте вариант #2:
> ?
> 1
> SendMessage(PageControlHandle, TCM_SETCURFOCUS, TabIndex,
>  0);

TCM_SETCURFOCUS сработало. Спасибо.


DayGaykin ©   (17.08.17 14:26[16]

Настоящее такое, от-душевное спасибо. Помогли не смотря на сумбурность изложения и сомнительность идеи.


DayGaykin ©   (17.08.17 20:04[17]

Новая проблема: PopupMenu

После нажатия на определенную кнопку возникает меню, где мне надо выбрать второй пункт меню. Изучив немного понял, что нужно отправить WM_COMMAND окну, которое передается в параметре hwnd функции TrackPopupMenu. Изучив генофонд, увидел, что там специально созданное для этого окно и найти его не понятно как.
Как все-таки нажать на второй пункт меню?


Leonid Troyanovsky ©   (18.08.17 11:17[18]


> DayGaykin ©   (17.08.17 20:04) [17]

> Как все-таки нажать на второй пункт меню?

Нажать-то просто:
PostMessage(PopupList.Window), WM_COMMAND, PopupMenu1.Items[1].Command, 0);

Окно PopupList имеет класс TPUtilWindow.
Однако, такой класс могут иметь и другие служебные окна, скажем, таймер.

Поэтому, придется хукнуть или сабклассировать все такие окна и смотреть,
кто получает менюшные сообщения, а заодно прояснив IID пункта.

Возможно, что проще снова эмулировать нажатие стрелки вниз и ентер.

--
Regards, LVT.


DayGaykin ©   (18.08.17 19:37[19]

Это все оказалось сложно.

Пошел по такому пути:
- Нахожу окно #32768.
- Получаю по нему HMENU (MN_GETHMENU).
- Считываю элементы меню по HMENU.
- Нужному пункту отправляю MN_BUTTONDOWN и MN_BUTTONUP.

И уже после всего нашел http://www.delphikingdom.com/asp/answer.asp?IDAnswer=75873


Leonid Troyanovsky ©   (18.08.17 20:57[20]


> DayGaykin ©   (18.08.17 19:37) [19]

> - Нахожу окно #32768.
> - Получаю по нему HMENU (MN_GETHMENU).

Хорошая находка.
Записал в мемориз, спасибо.

--
Regards, LVT,


DayGaykin ©   (07.09.17 10:58[21]

Вчера запустились. Всем спасибо за помощь!


DayGaykin ©   (07.09.17 10:58[22]

P.S. Слава богу обошлось без DBGrig-ов :)


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо