Как с помощью Delphi получить значения всех элементов Edit диалога формы?

Приветствую Вас, дорогие посетители! На этом блоге уже написана статья, как на Delphi с помощью библиотеки Synapse отправлять письма. Также было рассказано о получении с помощью Delphi IP-адреса тут и здесь. Эта статья поможет нам разобраться как прочитать все значения элементов диалога Edit из окна другого приложения, средствами Delphi, используя функции WinAPI. Итака, начнем!

Мы будем пользоваться функциями WinAPI для получения элементов диалога класса Edit. Например, нам нужно получить значения Edit c формы с заголовком «MyProgram», поэтому воспользуемся функцией WinAPI FindWindow.


HWND FindWindow(
    LPCTSTR lpClassName,	// указатель на имя класса
    LPCTSTR lpWindowName 	// указатель на имя окна
   );

В первой строке мы запишем:

Hndl:=FindWindow(nil, 'MyProgram');

Как видим, с помощью этой функции мы получаем указатель на окно (Нandle — дескриптор окна). Заносим дескриптор окна в переменную Hndl. Этот Handle нужен нам для следующего действия:

Hedt:=FindWindowEx(Hndl,0,'Edit',''); // получаю первый Edit

Для поиска воспользуемся функцией WinAPI FindWindowEx (ПоискОкнаУлучшенная):


[Не поддерживается в Windows NT]

Функция FindWindowEx отыскивает данные о дескрипторе окна, 
имя класса и имя окна которого соответствуют определенным строкам. 
Функция поиска дочерних окон начинается с первого 
до последнего заданного дочернего окна. 

HWND FindWindowEx
(
    HWND hwndParent,		// дескриптор родительского окна
    HWND hwndChildAfter,	// дескриптор дочернего окна
    LPCTSTR lpszClass,		// указатель имени класса
    LPCTSTR lpszWindow		// указатель имени окна
    );

Теперь мы получаем в переменную Hedt, дескриптор дочернего окна, первого Edit. Осталось открыть перебор по элементам диалога окна. Для этого используем функцию WinAPI GetWindow:


Функция GetWindow возвращает дескриптор окна, которое определено 
отношением (Z индекса или родительским) к указанному окну. 

HWND GetWindow
(
    HWND hWnd,	// дескриптор родительского окна
    UINT uCmd 	// флаг отношений
   );

Поэтому запишем следующий текст:

Hedt:=GetWindow(Hedt,GW_HWNDFIRST);

Теперь в переменной Hedt установлен указатель на первый Edit. Параметр GW_HWNDFIRST указывает на выбор первого элемента. Выборка началась, чтобы её продолжить запишем следующее:

repeat
    //получаю next Edit
    Hedt:=GetWindow(Hedt,GW_HWNDNEXT);
    if Hedt<>0 then 
	SendMessage(Hedt,WM_GETTEXT,WPARAM(512),lparam(HoldString));
    HoldString__ := HoldString__ + ' ' + String(HoldString);
until Hedt=0;

Теперь в переменной Hedt установлен указатель на следующий Edit. Параметр GW_HWNDNEXT указывает на выбор следующего элемента. Выборка будет продолжаться, пока не будут перебраны все элементы. Также мы воспользовались функцией WinAPI SendMessage, с помощью которой мы считываем значение элемента диалога.


LRESULT SendMessage(

    HWND hWnd,		// дескриптор окна назначения
    UINT Msg,		// сообщение
    WPARAM wParam,	// первый параметр сообщения
    LPARAM lParam 	// второй параметр сообщения
   );

Параметр WM_GETTEXT указывает окну с дискриптором Hedt, что нам нужно считать его значение в переменную HoldString, размером не больше, чем 512. Давайте проверим нашу работу. Создадим новый проект. Бросим кнопку на форму. Вот весь листинг:

procedure Form1.Button1Click(Sender: TObject);
var
  HoldString: PChar;
  HoldString__: String;
  Hndl,Hedt: HWND;
begin
    Hndl:=FindWindow(nil, 'MyProgram');
    Hedt:=FindWindowEx(Hndl,0,'Edit',''); // получаю первый Edit
    Hedt:=GetWindow(Hedt,GW_HWNDFIRST); //указатель на первый Edit
    repeat
        //установливаем указатель на следующий Edit
        Hedt:=GetWindow(Hedt,GW_HWNDNEXT);
        if Hedt<>0 then 
	    SendMessage(Hedt,WM_GETTEXT,WPARAM(512),lparam(HoldString));
        HoldString__ := HoldString__ + ' ' + String(HoldString);
    until Hedt=0;
end;

  1. Alex говорит:

    Будет Acces Violation. Как минимум нужно написать
    var HoldString: array[0..512] of char;

  2. Softmaker говорит:

    Хорошо напишите, у меня Acces Violation не выходил.

  3. Е.Багоцкий говорит:

    Все то может и правильно только у меня FindWindowEx упорно возвращает 0
    ChildWnd:=FindWindowEx(ParentWnd, 0,’Button’,»);
    if(ChildWnd <> 0) then
    SendMessage(ChildWnd, BM_CLICK, 0, 0)
    else ShowMessage(‘But в Proba не найден!’);
    Не помогает запись 4 параметра как nil.
    Аналогично не может найти Edit1
    Но окно проги находит!!!

  4. Softmaker говорит:

    Я делал этот скрипт для XP и в XP, на Delphi 5, может из-за этого проблема?

  5. Softmaker говорит:

    Посмотрите не изменилась ли сама функция FindWindowEx, например по параметрам или не появился ли ей какой-нибудь аналог?

  6. Е.Багоцкий говорит:

    Есть 2 имени — имя (однооконного) приложения
    и подпись (Caption) окна формы.
    Самое интересное FindWindow возвр не нулевой дескриптор в обоих случаях. А вот FindWindowEx работает только по дескриптору найденному по Caption.
    Это так? даже когда окна не дельфевые, а скажем Web-приложения?