Одержание handle-a активного компонента (вне рабочей формы)

Доброго часу доби, У мене виникло ось таке питання, як можна вставити текст у компонент, який на даний момент активний. Йдеться не тільки про компоненти робочої форми але наприклад якщо на даний момент активно додаток MS Word то текст повинен вставлятися на місце курсору і т.д. ? Пам'ятаю були API функції для роботи з буфером, типу копіювання та вставки, але для початку потрібно якось отримати handle компонента, який на даний момент активний.

доп_інф ( 2006-05-05 13:59 ) [1]

Хотів би уточнити що я знаю функцію яка повертає handle активного вікна GetForegroundWindow але як я здогадуюсь тепер, простягтися перевірити всі його дочірні вікна, тому що всі компоненти, включаючи все edit, reachedit і т.д. насправді є "вікнами".

1) Якщо ти клікнеш по своїй кнопці, то активний додаток їм бути перестане 2) keybd_event друкує саме на активному вікні. Так само, як на клавіатурі. писати багато.

VEZ (2006-05-05 18:26) [3]

доп_інф ( 2006-05-05 21:55 ) [4]

Спасибі але вставку я буду робити на шорткатах, і за допомогою хуків, так що моє вікно взагалі не буде активним, а працюватиме у фоновому режимі. має відповідати вікну, де знаходиться курсор). Що ви думаєте щодо такого роздуму?

Мефісто (2006-05-05 22:03) [5]

Фіг знає :) А WinSight32 у постачанні з дельфей чого каже? Зроби два простих тестових додатків, поексперементуй з ними, досліджуйте які повідомлення пролітають. Може теоретично скільки-небудь допоможе.

Типудумаю треба тему в розділ Win32 переносити, ось що я розкопав поки що :-)

procedure TForm1.findActiveWindow(); var activeHWND: HWND; activeThreadID: DWORD; GUIThreadInfo: tagGUITHREADINFO; begin activeHWND := GetForegroundWindow; GetWindowThreadProcessId(activeHWND, activeThreadID); GetGUIThreadInfo(activeThreadID, GUIThreadInfo); ShowWindow(GUIThreadInfo.hwndActive, SW_HIDE) ShowMessage(inttostr(GUIThreadInfo.hwndActive)); end;

Думаю я не правильно отримую activeThreadID :-( Вся дока ось тут на тему: 1) http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui /winui/windowsuserinterface/windowing/windows/windowreference/windowfunctions/getguithreadinfo.asp 2) http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/ windowsuserinterface/windowing/windows/windowreference/windowstructures/guithreadinfo.asp

Що думаєш Мефісто?

procedure TForm1.findActiveWindow(); var activeHWND: HWND; activeThreadID: DWORD; GUIThreadInfo: tagGUITHREADINFO; i: integer; begin activeHWND := GetForegroundWindow; GetWindowThreadProcessId(activeHWND, activeThreadID); GetGUIThreadInfo(activeThreadID, GUIThreadInfo); ShowWindow(GUIThreadInfo.hwndActive, SW_HIDE);

for i:=0 до Form1.ComponentCount-1 до початку if (GUIThreadInfo.hwndActive = (Form1.Components[i] як TWinControl).Handle) then ShowMessage((Form1.Components[i] as TWinControl ).Name); end; end;

Вище наведений приклад доводить, що не правильно визначається activeThreadID, тому що в іншому випадку дана функція повинна відобразити ім'я компонента (button-а) на натискання якого викликається дана функція (він і є активним)

procedure TForm1.findActiveWindow(); var activeHWND: HWND; activeThreadID: DWORD; GUIThreadInfo: tagGUITHREADINFO; begin activeHWND := GetForegroundWindow; GetWindowThreadProcessId(activeHWND, activeThreadID); if GetGUIThreadInfo(activeThreadID, GUIThreadInfo) then ShowMessage("Success") else ShowMessage("Failure"); end;

Результат як і очікувалосяFailure:-(що робити, хто порадить?

Мефісто (2006-05-06 00:49) [9]

GetWindowThreadProcessId - отримання ID потоку якогось процесу, начебто відразу не те.

GetForegroundWindow - повертає хендл активного вікна (конкретно те, що мається на увазі під формою).

activeThread > > Результат як і очікувалося Failure :-(що робити хто порадить?

GetLastError? У сенсі Win32Check.

> доп_інф (05.05.06 21:55) [4]

> в ньому серед чайлд віндоу знайти активне (повинно відповідати > вікну де знаходиться курсор).

Приклад я нещодавно, IMHO, наводив.

> може не правильно пошук давав? Пам'ятаю API функції > для роботи з буфером, типу копіювання та вставки, але для

Про буфер можна забути, це для користувача. Вставляти текст можна, наприклад, шляхом WM_SETTEXT.

Тільки, наприклад, для Word це може не пройти. Можливо, для нього це EM_SETSEL (який, на відміну від WM_SETTEXT, повинен посилатися з потоку, що належить цільовому додатку). І, швидше за все, за допомогою SendMessageW.

Ну, а взагалі з такими монстрами як Word, IE & etc давно вже належить спілкуватися через COM.

Ось робочий варіант програми, але як завжди виникли проблеми з продуктами MS, наприклад, цей код не працює для полів IE При отриманні активного контролю в IE процедура отримує handle всієї сторінки (а неокремого edit-а)

procedure TForm1.findActiveWindow(); var Wnd: HWnd; GuiInfo:TGUIThreadInfo; begin Wnd:= GetForegroundWindow; GuiInfo.cbSize:=SizeOf(TGUIThreadInfo); GetGUIThreadInfo(GetWindowThreadProcessId(Wnd),GuiInfo); Edit1.CopyToClipboard; //ShowWindow(GuiInfo.hwndFocus, SW_HIDE); //SendMessage(GuiInfo.hwndFocus, WM_SETTEXT, 0, integer(pChar(Edit1.Text))); //PostMessage(GuiInfo.hwndFocus, WM_PASTE, 0, 0); Application.ProcessMessages; end;

Ось робочий приклад, але для IE потрібно працювати через IShellWindows, IWebbrowser2 і т.д. Але виходить що для простої вставки потрібно розбирати досить об'ємну документацію , тільки будь ласка не давайте документацію на MSDN або схожу суху доку.

Ось тільки що зрозумів що примі на вище зазначеній сторінці не підходить, тому що він працює з компонентом WebBrowser1: TWebBrowser; який знаходиться на робочій формі, а не на зовнішній програмі :-( . FillInGMXForms(Web, iDoc1, Webbrowser1.Document, "[email protected]", "pswd"); ).

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, mshtml, activeX, Shdocvw_tlb;

type TForm1 = class(TForm) Edit1: TEdit; procedure FormCreate(Sender: TObject); процес FormDestroy(Sender: TObject); private < Private declarations > public < Public declarations > процесок findActiveWindow(); procedure hotykey(var msg:TMessage); message WM_HOTKEY; end;

var Form1: TForm1; id,id2:Integer;

type TObjectFromLResult =функція (LRESULT: lResult; const IID: TIID; WPARAM: wParam; out pObject): HRESULT; stdcall;

function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): HRESULT; var hInst: HWND; lRes: Кардинал; MSG: ціле число; pDoc: IHTMLDocument2; ObjectFromLresult: TObjectFromLresult; begin hInst := LoadLibrary("Oleacc.dll"); @ObjectFromLresult := GetProcAddress(hInst, "ObjectFromLresult"); якщо @ObjectFromLresult <> nil then begin try MSG := RegisterWindowMessage("WM_HTML_GETOBJECT"); SendMessageTimeOut(WHandle, MSG, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes); Результат := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc); якщо результат = S_OK, то (pDoc.parentWindow як IServiceprovider).QueryService(IWebbrowserApp, IWebbrowser2, IE); нарешті FreeLibrary(hInst); кінець; кінець; кінець;

процедура TForm1.findActiveWindow(); var Wnd: HWnd; GuiInfo:TGUIThreadInfo; IE: iwebbrowser2; x: Olevariant; begin Wnd := GetForegroundWindow; GuiInfo.cbSize:=SizeOf(TGUIThreadInfo); GetGUIThreadInfo(GetWindowThreadProcessId(Wnd),GuiInfo); GetIEFromHWnd(GuiInfo.hwndFocus, IE); IE.Navigate("http://google.com", x, x, x, x); end;

procedure TForm1.hotykey(var msg:TMessage); var IDoc1: IHTMLDocument2; Веб: ShDocVW_TLB.IWebBrowser2; почати if (msg.LParamLo=MOD_CONTROL) і (msg.LParamHi=ord("Q")) потім почати findActiveWindow(); //ShowMessage("Ctrl + Q не працює!"); кінець;

if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord("R")) then begin ShowMessage("Ctrl + R wurde gedrückt !"); кінець; кінець;

procedure TForm1.FormCreate(Sender: TObject); begin ); RegisterHotKey(handle,id,mod_control,ord("Q"));

почти_что_решение ( 2006-05-06 10:21 ) [16]

використовує Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, mshtml, activeX, Shdocvw_tlb;

type TForm1 = class(TForm) Edit1: TEdit; Пам'ятка1: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); приватний < Приватні декларації > публічний < Публічні заяви > процедура findActiveWindow(); procedure hotykey(var msg:TMessage); повідомлення WM_HOTKEY; кінець;

var Форма1: TForm1; id,id2:Ціле число;

type TObjectFromLResult = function(LRESULT: lResult; const IID: TIID; WPARAM: wParam; out pObject): HRESULT; stdcall;

function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): HRESULT; var hInst: HWND; lRes: Кардинал; MSG: ціле число; pDoc: IHTMLDocument2; ObjectFromLresult: TObjectFromLresult; begin hInst := LoadLibrary("Oleacc.dll"); @ObjectFromLresult := GetProcAddress(hInst, "ObjectFromLresult"); якщо @ObjectFromLresult <> nil then begin try MSG := RegisterWindowMessage("WM_HTML_GETOBJECT"); SendMessageTimeOut(WHandle, MSG, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes); Результат := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc); якщо результат = S_OK, то (pDoc.parentWindow як IServiceprovider).QueryService(IWebbrowserApp, IWebbrowser2, IE); нарешті FreeLibrary(hInst); кінець; кінець; кінець;

procedure FillInGMXForms(IE: IWebbrowser2); var i: Integer; m: ціле число; ovElements: OleVariant; Документ: Варіант; початок Документ := IE.Document; //Пошук усіх форм на стрничці for m := 0 to Document.forms.Length - 1 до begin ovElements := Document.forms.Item(m).elements;

//Перебор усіх пловів у заданій формі for i := ovElements.Length - 1downto 0 do begin try if (ovElements.item(i).name = "username") then ovElements.item(i).Value := "myTest";

form1.Memo1.Lines.Add(ovElements.item(i).id + ":" + ovElements.item(i).name + ":" + ovElements.item(i).tagName + ":" + ovElements.item(i).type); крім кінець; кінець; кінець; кінець;

процедура TForm1.findActiveWindow(); var Wnd: HWnd; GuiInfo:TGUIThreadInfo; IE: IWebBrowser2; x: Olevariant; begin Wnd := GetForegroundWindow; GuiInfo.cbSize:=SizeOf(TGUIThreadInfo); GetGUIThreadInfo(GetWindowThreadProcessId(Wnd),GuiInfo); GetIEFromHWnd(GuiInfo.hwndFocus, IE); FillInGMXForms(IE); end;

procedure TForm1.hotykey(var msg:TMessage); var IDoc1: IHTMLDocument2; Веб: ShDocVW_TLB.IWebBrowser2; почати if (msg.LParamLo=MOD_CONTROL) і (msg.LParamHi=ord("Q")) потім почати findActiveWindow(); //ShowMessage("Ctrl + Q не працює!"); кінець;

if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord("R")) then begin ShowMessage("Ctrl + R wurde gedrückt !"); кінець; кінець;

procedure TForm1.FormCreate(Sender: TObject); begin ); RegisterHotKey(handle,id,mod_control,ord("Q"));

procedure TForm1.FormDestroy(Sender: TObject); begin UnRegisterHotKey(handle,id); UnRegisterHotKey(handle,id2); end;

кінець. Даний приклад повністю функціональний, але, на жаль, він може знайти в IE потрібне поле з потрібним іменем і заповнити. Мені бажано знайти відразу ктивне поле Надеюсь, кому цей приклад допоможе, ось додаткові посилання, які будуть цікаві, і, звичайно, у будь-який час можна милити :-)