Подтвердить что ты не робот

Есть ли способ получить имя VCL Control через API окон?

У меня есть Hwnd элемента управления VCL, который находится в другом окне процесса. Есть ли способ получить свое имя VCL (свойство TControl.Name) этого элемента управления через API окон? Мне нужно имя, потому что в этом окне есть несколько TEdits, и мне нужно определить тот, который я хочу, чтобы отправить ему сообщение WM_SETTEXT.

Оба приложения были созданы с Delphi 2010.

4b9b3361

Ответ 1

Delphi имеет встроенную функцию FindControl(), которая возвращает TWinControl указанного hWnd. Но он работает для того же экземпляра VCL. Я думаю, вам следует его исследовать. После указания указателя на объект TWinControl его имя (строка), расположенное в смете +8. Вы можете попробовать ReadProcessMemory для его чтения. Основная проблема здесь заключается в том, чтобы создать версию FindControl(), которая соответствует вашим потребностям.

Изменить: (Наконец получил: D) Вызвать функцию GetWinControlName

// Get Pointer to TWinControl in another process
function GetWinControl(Wnd: HWND; out ProcessId: THandle): Pointer;
var
  WindowAtomString: String;
  WindowAtom: ATOM;
begin
  if GetWindowThreadProcessId(Wnd, ProcessId) = 0 then RaiseLastOSError;

  // This is atom for remote process (See controls.pas for details on this)
  WindowAtomString := Format('Delphi%.8X',[ProcessID]);
  WindowAtom := GlobalFindAtom(PChar(WindowAtomString));
  if WindowAtom = 0 then RaiseLastOSError;

  Result := Pointer(GetProp(Wnd, MakeIntAtom(WindowAtom)));
end;

function GetWinControlName(Wnd: HWND): string;
var
  ProcessId: THandle;
  ObjSelf: Pointer;
  Buf: Pointer;
  bytes: Cardinal;
  destProcess: THandle;
begin
  ObjSelf := GetWinControl(Wnd, ProcessId);

  destProcess := OpenProcess(PROCESS_VM_READ, TRUE, ProcessId);
  if destProcess = 0 then RaiseLastOSError;

  try
    GetMem(Buf, 256);
    try
      if not ReadProcessMemory(destProcess, Pointer(Cardinal(ObjSelf) + 8), Buf, 4, bytes) then RaiseLastOSError;
      if not ReadProcessMemory(destProcess, Pointer(Cardinal(Buf^)), Buf, 256, bytes) then RaiseLastOSError;
      Result := PChar(Buf);
    finally
      FreeMem(Buf);
    end;
  finally
    CloseHandle(destProcess);
  end;
end;

Ответ 2

Нет, нет функции Windows API, которая даст имя элемента управления. Это частная деталь реализации Delphi.

Если вы контролируете код целевого процесса, тогда вы можете реализовать некоторую форму IPC для решения проблемы. В противном случае любое решение, которое дает управляющее имя, будет связано с довольно мерзким взломом. Один из подходов заключался бы в том, чтобы внедрить в процесс DLL, построенную с той же версией среды выполнения. Получите эту DLL, чтобы найти ссылку управления VCL из HWND и зачитать имя. На этом есть много вариантов, и красиво выполненная трюк ReadProcessMemory, предлагаемая ответом @Samaliani, типична для обручей, с которыми вы должны прыгать.

Однако я могу придумать гораздо более простое решение вашей проблемы. Найдите ручки ко всем элементам управления редактирования и используйте эти ручки для получения координат элементов управления. Относительных положений элементов управления редактирования будет достаточно, чтобы определить, какая из них является целевой. И, пожалуйста, прочитайте ниже комментарии @dthorpe для более полезных мыслей.