Одержание 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 потрібне поле з потрібним іменем і заповнити. Мені бажано знайти відразу ктивне поле Надеюсь, кому цей приклад допоможе, ось додаткові посилання, які будуть цікаві, і, звичайно, у будь-який час можна милити :-)