![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Получение handle-а активного компонента (вне рабочей формы) [D6, WinXP]
Delphi5.01 © (2006-05-05 13:16:00)Доброе время суток,
У меня возник вот такой вопрос, как можно вставить текст в компонент который на данный момент активен. Речь идет не только о компонентах рабочей формы но например если на данный момент активно приложение MS Word то текст должен вставляться на место курсора и т.д.
В интернете уже искал, похожей задачи к сожалению не нашел, может не правильно поиск давал? Помню были API функции для работы с буфером, типа копирования и вставки но для начала нужно как то получить handle компонента который на данный момент активен.
Заранее благодарю всех за уделенное время и желание помочь
почти_что_решение (2006-05-06 10:21:00) [1]
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, OleCtrls,
mshtml, activeX, Shdocvw_tlb;
type
TForm1 = class(TForm)
Edit1: TEdit;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure findActiveWindow();
procedure hotykey(var msg:TMessage); message WM_HOTKEY;
end;
var
Form1: TForm1;
id,id2:Integer;
implementation
{$R *.dfm}
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: Cardinal;
MSG: Integer;
pDoc: IHTMLDocument2;
ObjectFromLresult: TObjectFromLresult;
begin
hInst := LoadLibrary('Oleacc.dll');
@ObjectFromLresult := GetProcAddress(hInst, 'ObjectFromLresult');
if @ObjectFromLresult nil then begin
try
MSG := RegisterWindowMessage('WM_HTML_GETOBJECT');
SendMessageTimeOut(WHandle, MSG, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes);
Result := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc);
if Result = S_OK then
(pDoc.parentWindow as IServiceprovider).QueryService(IWebbrowserApp, IWebbrowser2, IE);
finally
FreeLibrary(hInst);
end;
end;
end;
procedure FillInGMXForms(IE: IWebbrowser2);
var
i: Integer;
m: Integer;
ovElements: OleVariant;
Document: Variant;
begin
Document := IE.Document;
//Poisk vsekh form na strnichke
for m := 0 to Document.forms.Length - 1 do
begin
ovElements := Document.forms.Item(m).elements;
//Perebor vsekh plov v zadannoi forme
for i := ovElements.Length - 1 downto 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);
except
end;
end;
end;
end;
procedure 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;
Web: ShDocVW_TLB.IWebBrowser2;
begin
if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord('Q')) then begin
findActiveWindow();
//ShowMessage('Ctrl + Q wurde gedrückt !');
end;
if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord('R')) then begin
ShowMessage('Ctrl + R wurde gedrückt !');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
id:=GlobalAddAtom('hotkey');
RegisterHotKey(handle,id,mod_control,ord('Q'));
id2:=GlobalAddAtom('hotkey2');
RegisterHotKey(handle,id2,mod_control,ord('R'));
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnRegisterHotKey(handle,id);
UnRegisterHotKey(handle,id2);
end;
end.
Данный пример полно функциональный, но к сожалению он может находить в IE нужное поле с нужным именем и заполнять. Мне же желательно найти сразу ктивное поле
Надеюсь комуто данный пример поможет, вот дополнительные ссылки которые будут интерестны и конечно в любое время можете мылить :-)
http://www.swissdelphicenter.ch/torry/showcode.php?id=1732
http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/children.asp
Delphi5.01 (2006-05-06 09:38:00) [2]
unit Unit1;
interface
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);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure findActiveWindow();
procedure hotykey(var msg:TMessage); message WM_HOTKEY;
end;
var
Form1: TForm1;
id,id2:Integer;
implementation
{$R *.dfm}
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: Cardinal;
MSG: Integer;
pDoc: IHTMLDocument2;
ObjectFromLresult: TObjectFromLresult;
begin
hInst := LoadLibrary('Oleacc.dll');
@ObjectFromLresult := GetProcAddress(hInst, 'ObjectFromLresult');
if @ObjectFromLresult nil then begin
try
MSG := RegisterWindowMessage('WM_HTML_GETOBJECT');
SendMessageTimeOut(WHandle, MSG, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes);
Result := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc);
if Result = S_OK then
(pDoc.parentWindow as IServiceprovider).QueryService(IWebbrowserApp, IWebbrowser2, IE);
finally
FreeLibrary(hInst);
end;
end;
end;
procedure 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;
Web: ShDocVW_TLB.IWebBrowser2;
begin
if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord('Q')) then begin
findActiveWindow();
//ShowMessage('Ctrl + Q wurde gedrückt !');
end;
if (msg.LParamLo=MOD_CONTROL) and (msg.LParamHi=ord('R')) then begin
ShowMessage('Ctrl + R wurde gedrückt !');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
id:=GlobalAddAtom('hotkey');
RegisterHotKey(handle,id,mod_control,ord('Q'));
id2:=GlobalAddAtom('hotkey2');
RegisterHotKey(handle,id2,mod_control,ord('R'));
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnRegisterHotKey(handle,id);
UnRegisterHotKey(handle,id2);
end;
Вот рабочи вариант который перенаправляет активную страничку браузера на адресс google.com, браузер в этот момент должен иметь фокус. Надо заметить что при разработке была использованна утилита SypXX от MS. Теперь осталось малое, найти нужный филд в iwebbrowser2 и сменить значение :-)
Delphi5.01 (2006-05-06 08:26:00) [3]Вот только что сообразил что приме на выше указанной страничке не подходит, так как он работает с компонентом WebBrowser1: TWebBrowser; который находиться на рабочей форме а не на внешней программе :-(
...
FillInGMXForms(Web, iDoc1, Webbrowser1.Document, 'user@gmx.net', 'pswd');
...
Delphi5.01 (2006-05-06 03:42:00) [4]Вот рабочий вариант программы, но как всегда возникли проблемы с продуктами 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 и т.д. Но получаеться что, для простой вставки нужно разбирать довольно обемную документацию :-(
http://www.swissdelphicenter.ch/torry/showcode.php?id=1732
Что вы посоветуюете почитать на счет работы с IE через OLE, только пожалйста не давайте документацию на MSDN или похожую сухую доку. Желательно с примером и в пошагвом режиме :-)
Заранее благодарю :-)
Leonid Troyanovsky (2006-05-06 01:43:00) [5]
> Delphi5.01 © (05.05.06 13:16)
> может не правильно поиск давал? Помню были API функции
> для работы с буфером, типа копирования и вставки но для
Про буфер можно забыть, это для юзера.
Вставлять текст можно, например, путем WM_SETTEXT.
Только, например, для Word это может и не пройти.
Возможно, что для него это EM_SETSEL (который, в отличии
от WM_SETTEXT, должен посылаться из потока, принадлежащего
целевому приложению). И, скорее всего, путем SendMessageW.
Ну, а, вообще-то, с такими монстрами как Word, IE & etc давно уж
положено общаться через COM.
--
Regards, LVT.
Leonid Troyanovsky (2006-05-06 01:32:00) [6]
> доп_инф (05.05.06 21:55) [4]
> в нем среди чайлд виндоу найти активное (должно соответствовать
> окну где находиться курсор).
AttachThreadInput & GetFocus.
Пример я недавно, IMHO, приводил.
--
Regards, LVT.
Leonid Troyanovsky (2006-05-06 01:05:00) [7]
> Delphi5.01 © (05.05.06 23:28) [8]
> GetWindowThreadProcessId(activeHWND, activeThreadID);
activeThreadID := GetWindowThreadProcessId(activeHWND, nil);
> Результат как и ожидалось Failure :-( что делать, кто посоветует?
GetLastError? В смысле, Win32Check.
--
Regards, LVT.
Мефисто (2006-05-06 00:49:00) [8]GetWindowThreadProcessId - получение ID потока некоего процесса, вроде сразу не то.
GetForegroundWindow - возвращает хендл активного окна (конкретно то, что подразумевается под формой).
Delphi5.01 (2006-05-05 23:28:00) [9]
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:-( что делать, кто посоветует?
Delphi5.01 (2006-05-05 23:22:00) [10]
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 to Form1.ComponentCount-1 do begin
if (GUIThreadInfo.hwndActive = (Form1.Components[i] as TWinControl).Handle) then
ShowMessage((Form1.Components[i] as TWinControl).Name);
end;
end;
Выше приведенный пример доказывает что не правильно определяется activeThreadID, так как в противном случае данная функция должна отобразить имя компонента (button-а) на нажатие которого вызывается данная функция (он и является активным)
Delphi5.01 (2006-05-05 23:15:00) [11]Типа думаю надо тему в раздел 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
Что думаешь Мефисто?
Мефисто (2006-05-05 22:03:00) [12]Фиг знает :) А WinSight32 в поставке с дельфей чего говорит? Сделай два простых тестовых приложения, поэксперементируй с ними, поизучай какие сообщения пролетают. Может в теории сколько-то поможет.
доп_инф (2006-05-05 21:55:00) [13]Спасибо но вставку я буду делать на шорткатах, и с помощью хуков, так что мое окно вообще не будет активным а будет работать в фоновом режиме.
Есть подозрения что нужно будет найти активное окно и потом в нем среди чайлд виндоу найти активное (должно соответствовать окну где находиться курсор).
Что вы думаете насчет такого размышления?
VEZ (2006-05-05 18:26:00) [14]Оффтопик, но MS Office и вообще все продукты майкрософт не используют стандартные компоненты винды, интересно почему:).
ANB (2006-05-05 17:27:00) [15]1) Если ты кликнешь по своей кнопке, то активное приложение им быть перестанет
2) keybd_event печатает именно на активном окне. Так же, как на клавиатуре. писать много.
доп_инф (2006-05-05 13:59:00) [16]Хотел бы уточнить что я знаю функцию которая возвращает handle активного окна GetForegroundWindow но как я догадываюсь теперь, продеться проверить все его дочерние окна, так как все компоненты, в том числе все edit, reachedit и т.д. на самом деле являются "окнами".