function proc(wnd:HWND):boolean; stdcall;
begin
SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Tex t')));
Result:=true;
end;
Как можно в Edit'ы другого приложения вывести требуемый текст?
Как можно в Edit'ы другого приложения вывести требуемый текст?
Для решения использовал следующие действия:
function proc(wnd:HWND):boolean; stdcall;
begin
SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text')));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EnumChildWindows(window,@proc,0);//window-родительское окно; Handle получен верно
end;
В файле справки о функции EnumChildWindows говорится, что функция, переданная ей в качестве 2-го
аргумента выполняется для всех дочерних окон. У меня либо выводит текст для последнего Edit'а
( вслучае, если я пытаюсь заполнить Edit'ы приложения, созданного в Delphi) родительского окошка, либо вообще ничего и никуда не выводит (для других приложений). в чём дело?
Код:
но этот код изменит текст даже на кнопках, так что добавь проверку на то, что дочерний элемент это Edit, например можно сделать так:
Код:
var wndClass:array[0..255] of char;
begin
Result:=True;
GetClassName(wnd, wndClass, sizeof(wndClass));
if wndClass='TEdit' then
SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text')));
end;
begin
Result:=True;
GetClassName(wnd, wndClass, sizeof(wndClass));
if wndClass='TEdit' then
SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text')));
end;
кстати в исходниках есть подобное.
Спасибо! Вот что невнимательность делает с людьми! Забыл вернуть результат функции! А как можно присвоить разным Edit'ам разные значения?
если это надо сделать при перечислении, то просто смотри какой по счету данный найденный Edit, и отсылай характерный для данного значения счетчика текст.
А как это оформить на практике?
Код:
var i:word; //счетчик - глобальная переменная
<skip>
function proc(wnd:hWnd):boolean;stdcall;
var wndClass:array[0..255] of char;
begin
Result:=True;
GetClassName(wnd, wndClass, sizeof(wndClass));
if wndClass='TEdit' then
begin
case i of //выбираем Edit по счету и отсылаем сообщение
0: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text0')));
1: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text1')));
2: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text2')));
end;
inc(i); //увеличиваем счетчик на 1
end;
end;
<skip>
EnumChildWindows(window,@proc,0);
<skip>
function proc(wnd:hWnd):boolean;stdcall;
var wndClass:array[0..255] of char;
begin
Result:=True;
GetClassName(wnd, wndClass, sizeof(wndClass));
if wndClass='TEdit' then
begin
case i of //выбираем Edit по счету и отсылаем сообщение
0: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text0')));
1: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text1')));
2: SendMessage(wnd,WM_SETTEXT,0,LParam(PAnsiChar('Text2')));
end;
inc(i); //увеличиваем счетчик на 1
end;
end;
<skip>
EnumChildWindows(window,@proc,0);
Огромнейшее СПАСИБО! Всё работает! Чтобы я без Вас делал, наверное, разбирался бы сам! Ещё раз огромное СПАСИБО!
определённые строки, button'ы нажимаются и прочее. Но кардинально иначе обстоят дела с другими приложениями. Так, например,после
первого нажатия на кнопку появляется другое окно с тем же Handle'ом, именем класса окна и его названием, в котором
Edit'ы остаются пустыми, кнопки не нажимаются и т.д. Трассируя, я выяснил, что имя класса Edit'ов не 'Edit', как принято, а непонятно что, в связи с чем они и не заполняются. Кнопки в этом же окне не нажимаются. В чём причина такого поведения?
ну так и не обязательно имя класса долно быть Edit или TEdit. впринципи может быть все что угодно, хоть абракадабра. уточни свою задачу а там может что и придумать можно будет.
Вызвав функцию GetWindowClass с параметром полученного ранее Handle'a я получаю название "Edit"
для Edit'a, а не белеберду... Это у меня не укладывается в голове.
Задача стоит передо мной следующая... Упростить процесс установки приложений на ПК, а именно
автоматизировать его. Конечно можно написать bat-файл для этой цели или создать дистрибутив.
Либо воспользоваться платной программой LazySetupCD... Меня ни тот, ни другой вариант не устраивает...
Я решил писать программу... Вначале у меня была задумка (вполне приемлемая) запускать инсталяшки,
используя функцию ShellExecute с параметром '/qn' или '/qb'- приложения устанавливаются те,
где не требуется ввод серийного номера в процессе установки. Поэтому мне приходится нажимать
программно на кнопки, вводить программно серийные номера в Edit'ы и т.д.
Цитата: kosfiz
ну так и не обязательно имя класса долно быть Edit или TEdit. впринципи может быть все что угодно, хоть абракадабра. уточни свою задачу а там может что и придумать можно будет.
Вовсе нет, есть стандартизированный класс для edit'а "EDIT"
Есть конечно какие-нибудь надстройки, но это редко... в основном "EDIT"
Я тоже так думал до поры до времени. Оказывается, что нет... Edit'ы могут иметь другой класс, отличный от 'Edit'... К сожалению так показывает моя практика...
Цитата:
Есть конечно какие-нибудь надстройки, но это редко... в основном "EDIT"
Ну... кстати лучше думаю искать по ID
Как я делал:
беру прогу, SIW, там есть смотреть класс окна и handle.
Запускаю Delphi, простенький код
Код:
...
ShowMessage(IntToStr(GetDlgCtrlID(<хендл_полученный_из_проги>)));
...
ShowMessage(IntToStr(GetDlgCtrlID(<хендл_полученный_из_проги>)));
...
И все... а дальше уж дело техники :)
тоже такое когда-то делал, всмысле прогу для упрощения инсталляции. напиши парочку названий программ, с которыми не получается провзаимодействовать, только плиз, чтоб они не редки были и найти можно было. будем разбираться.
Буду пробывать ещё использовать функцию GetDlgCtrlID.
Буду пробывать ещё использовать функцию GetDlgCtrlID.[/quote]
вообщем я попробовал. кнопки и эдиты находит исправно, но... ненажимаются кнопки и не вставляется текст в эдиты. присмотрелся я к классу окна установщика и заметил, что класс MsiDialogCloseClass. особенно меня заинтересовало это Close. вообщем-то мне кажется(это лишь гипотеза), что стоит что-то вроде защиты от подобных нажиманий кнопок. у меня с данной прогой несправляется LazySetupCD, если выбрать опцию наподобие нашей, но вот если имитируются действия пользователя так, что движется курсор, то здесь все работает. возможно тебе придется тогда что-то предпринять, чтобы твоя программа поступала аналогично, т.е. движение курсора в определенную точку и клик.
Хотя нет... Вначале необходимо поместить курсор над кнопкой... Но для этого опять таки надо знать Handle кнопки окна приложения, иначе как узнать её расположение на экране? (GetWindowRect). Далее осуществляем щелчок по кнопке... Для этого используем всё тот же Handle и эмулируем действия пользователя, посылая сообщение SendMessage(button,BM_CLICK,0,button)... Это что касается кнопок... Но вернёмся к нашим Edit'ам. В принципе в таких приложениях фокус передаётся Edit'у. Может можно воспользоваться буфером? Копируем в буфер часть серийного номера, вставляем из него в Edit, при этом фокус передастся другому Edit'у, снова копируем в буфер часть серийного номера и вставляем из него... Может быть это и будет решением проблемы? Как считаете?
возможно это решит твою проблему: здесь тебе выбирать реализацию. а про нажатие кнопок могу сказать, что у меня SendMessage с WM_LBUTTONDOWN и WM_LBUTTONUP(и с BM_CLICK) не справлялась с нажатием, но... есть функция SendInput с помощью неё у меня легко получилось нажать на кнопку в инсталляции Delphi. кроме того, с помощью этой функции можно и набивку сомволов осуществить(не пробовал, но должно сработать), т.е. ввод серийника. так что можно сделать так как ты предложил или посмотреть в сторону SendInput(в эту сторону стоит глянуть, если ты еще не знаком с этой функцией: вдруг пригодится).
А что это за функция? И где есть справка о ней? Неужели только в MSDN? Вот что-то с Clipboard'ом ни получается... Текст то я скопировал в буфер, а вот вставить из него в требуемый Edit не получается. Для получения Handle'а Edit'а я использовал функцию GetFocus, но она позволяет получить его для текущего приложения. Также пытался использовать функцию EnumChildWindows, но и это не помогло... у меня остаётся только один вариант- это использовать функцию SendInput.
здесь. точнее получить представление об этой функции, посмотреть как её используют. ну а если появятся вопросы то сюда - поможем.
ну для начало можно что-нибудь поискать
Я заменил функцию SendInput на функцию keybd_event. Хотя у ф-ции SendInput больше возможностей, но и keybd_event ничем не хуже. Вообщем мне всё таки удалось ввести текст в Edit. Но возникла новая проблема. На этот раз я никак не могу получить Handle переключателя (радиокнопки). Ф-ция FindWindowEx находит Handle для обычной кнопки, а вот с расширенным её стилем работать не хочет... Вопрос: Как можно получить Handle радиокнопки?
Я, конечно, не мастер в Delphi, но кое-что подсказать смогу. Что если сымитировать нажатие клавиш на клавиатуре? Имитируем нажатие <Tab> и постепенно смещаемся к кнопке, а потом "жмем" <Enter>. Или имитируем нажатие горячих клавиш для кнопки (скажем, <Alt>+<N> - для "Next"). В VB есть функция SendKeys. Может быть, есть аналог в API или в самом Delphi?
В WinAPI есть аналог- это либо функция keybd_event, либо функция SendInput. Проблема заключается в том, что не получается симитировать нажатие на переключатель (стрелка "вверх", стрелка "вниз"). Для других, обычных кнопок , этот трюк срабатывает... Но не для переключателей. Поэтому приходится получать Handle радиокнопки и использовать функцию SendMessage... Только так...
Ну так что? Никто не знает?
так ты все с InstallShield Wizard Borland Delphi 6 Enterprise Edition работаешь? я щас попробовал с помощью функции EnumChildWindows найти хэндлы переключателей(класс Button вроде) - находит.
работу, ожидает ли действия пользователя и т.д.?
Обнаружен НОВЫЙ КЛАСС!!! Название ему RichEdit20W!!! Кто-нибудь слышал о таком? Возвращаясь к теме Edit'ов... Почему функции WindowFromPoint и EnumChildWindows работают совершенно по разному? Так, функция WindowFromPoint возвращает название класса "Edit" для Edit'a, для Button'a- "Button"... Функция EnumChildWindows перебирает все контроллеры и нигде не встречается класс "Edit"- вместо всех Edit'ов находит единый класс "RichEdit20W". Число 20 соответсвует общему числу цифробукв, которые нужно ввести во все Edit'ы. Символ "w"-Word... В чём причина такого странного поведения?
да нет это не число символов и не word, это вроде юникод(W) версия класса richedit20, 20 - это версия 2.0 - вроде так. вот смотри подробней здесь. вот тебе цитатка:
[quote=]The name of the Rich Edit 1.0 window class is RichEdit. Rich Edit 2.0 has both ANSI and Unicode window classes—RichEdit20A and RichEdit20W, respectively.[/quote]
[quote=SergPas]Так, функция WindowFromPoint возвращает название класса "Edit" для Edit'a, для Button'a- "Button"... Функция EnumChildWindows перебирает все контроллеры и нигде не встречается класс "Edit"- вместо всех Edit'ов находит единый класс "RichEdit20W".[/quote]
а что Spy++ показывает?
функции WindowFromPoint и EnumChildWindows работают в разнобой...
[quote=SergPas]В это же время
функции WindowFromPoint и EnumChildWindows работают в разнобой...[/quote]
время конечно достаточно много прошло, но что за программка, на которой данные функции работают в разнобой?
P.S. любопытно мне.
Тот же самый инсталятор Borland Delphi. Функция WindowFromPoint получает класс Edit, утилита Spy++ получает класс Edit, а вот функция EnumChildWindow среди всех получаемых ей дочерних окон находит класс RichEdit20w. Две функции, предназначенные для получения Handle'а одного и того же дочернего окна дают разные результаты... В чём причина такого поведения я так до сих пор и не выяснил...
взял непосредственно инсталлятор Borland Delphi 7. использовал для установления классов окон и поиска оных: Spy++(6 версии), FSpy(EnumChildWindows), и еще одну утилку собственного написания(WindowFromPoint). все находят и Edit'ы и RichEdit20W там где положено, за одним исключением: Spy++ Edit'ы почему-то не видит. вообще результаты не могут быть разными, т.к. класс окна определяется с помощью функции GetClassName и в случае с WindowFromPoint и в случае с EnumChildWindows, так что можно сделать вывод что результат разный так как видимо функции GetClassName переданы разные хэндлы.