TWebBrowser.HWNDを取得する方法 (メモ: その1)
カテゴリー: General
2011-10-19
TWebBrowser.HWNDを取得する方法 (メモ: その1)
今日は、
C#へレッツゴー
さぁ Delphiなんか捨てて みんなドットネットへ Go !!
それいけ ドットネット推進派 の 禁断のDelphiネタです。
次期Windows8 の 「Windows Developer Preview版」が無償公開 されていますが
もう みなさんは、お使いですか?
※OSのアンインストール機能がないそうなので、インス トールは気をつけてください
Visual Studio 11 Expressの同梱版もあり すごいお試し版OSです。
“Win RunTime(WinRT)”と呼ばれる新しいAPIが追加され
新しいデスクトップ“Metro”では、新しい“Metro”対応のアプリケーション(“Metro style apps”)
なんていうものが必要になるそうです。
キット古い開発環境とアプリを市場から強制排除したいのでしょうね。
もう、Visual Studio意外に開発環境の選択の余地がないって感じになってきましたね。
ということで、 ほらほら、 みんなドットネットへ Go !!
では、本題です。
TWebBrowser.HWNDへのアクセスは不正なエラーに なります。
WebBrowser1.Handleでいいようです。
構造
ページを表示するとコンテンツに応じて 上の3つが、階層構造で多様につながる。
iframeなどの要素があると多重構造になるようです。
※ コードを参考にする場合は、自己責任で参考にされてください。
※ 十分なテストが必要です。
※ 将来的に、仕様などの変更で利用できなくなることも考えられます。
【TWebBrowser.HWNDは、無効なプロパティ】
(MSDN 文書番号: 244310):
※要約 子WindowをたどっていくとHandleを取得することができます。
【HTML要素からhandleを取得する方法。】
擬似キー入力を送るコード:Function Key
擬似キー入力を送るコード:通常文字
ALT+F4(終了)を呼びたい場合は
WM_SYSKEYDOWN を使います
VK_F1
テキストボックスに文字列をいれるだけなら、
普通にgetElementsByNameやgetElementByIdなどで
要素にアクセスして代入した方が安全に入力できます。
普通にテキストボックスに入力する方法
( 応用例:ログインIDなどの自動入力 )
使い方は、基本的にJavaScriptと同じ。
【一番上のShell DocObject View の HWND 取得方法】
GetWindow(WebBrowser1.Handle, GW_CHILD )
※ ClassNameで、確認した方がいい 、 GW_HWNDNEXT
Navigateでフォルダを指定した場合、エクスプローラーが内蔵されるので注意。 SysListView32などが現れる。
【場所から取得する方法】
・ ChildWindowFromPoint関数を使用します。
ついでに、それいけみんなドットネットなので
C#で、ハンドルにメッセージを送る方法は
知らないので
[System.Runtime.InteropServices.DllImport("user32.dll")]
private extern static System.Boolean PostMessage(
System.IntPtr hWnd,
System.UInt32 Msg,
System.Int32 wParam,
System.Int32 lParam);
で回避することができる。
執筆:2011.10.17
編集:2011.10.17
編集:2011.10.17
今日は、
C#へレッツゴー
さぁ Delphiなんか捨てて みんなドットネットへ Go !!
それいけ ドットネット推進派 の 禁断のDelphiネタです。
次期Windows8 の 「Windows Developer Preview版」が無償公開 されていますが
もう みなさんは、お使いですか?
※OSのアンインストール機能がないそうなので、インス トールは気をつけてください
Visual Studio 11 Expressの同梱版もあり すごいお試し版OSです。
“Win RunTime(WinRT)”と呼ばれる新しいAPIが追加され
新しいデスクトップ“Metro”では、新しい“Metro”対応のアプリケーション(“Metro style apps”)
なんていうものが必要になるそうです。
キット古い開発環境とアプリを市場から強制排除したいのでしょうね。
もう、Visual Studio意外に開発環境の選択の余地がないって感じになってきましたね。
ということで、 ほらほら、 みんなドットネットへ Go !!
では、本題です。
TWebBrowser.HWNDへのアクセスは不正なエラーに なります。
WebBrowser1.Handleでいいようです。
構造
|
ClassName | |
親 |
- Shell Embedding | ← GetClassName(WebBrowser1.Handle) |
子 |
-- Shell DocObject View | 不明 |
孫 |
--- Internet Explorer_Server | ← 操作画面 解説URL |
iframeなどの要素があると多重構造になるようです。
※ コードを参考にする場合は、自己責任で参考にされてください。
※ 十分なテストが必要です。
※ 将来的に、仕様などの変更で利用できなくなることも考えられます。
【TWebBrowser.HWNDは、無効なプロパティ】
(MSDN 文書番号: 244310):
※要約 子WindowをたどっていくとHandleを取得することができます。
※ TWebBrowser.HWND |
Web ブラウザの Window ハンドルへのアクセスを提供します。 |
※ Delphiでは、TWebBrowser.HWNDは使えません。 | |
コード | WebBrowser1.HWND; |
実行結果 | デバッガ例外通知 プロジェクト は例外クラス EOleException (メッセージ 'エラーを特定できません')を送出しました。 |
【HTML要素からhandleを取得する方法。】
ハンドルを 直接要求する方法 |
|
// [エラー] : E2010 'System.TGUID' と 'Ole2.TGUID' には互換性がありません const // From Ole2.pas IID_IOleWindow: TGUID = ( D1:$00000114;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46)); function GetWindowHandleFromIDispatch(disp: IDispatch) : HWND; var h : hwnd; Res : HRESULT; oWin : IOleWindow; // Unit ActiveX.pas begin // example: GetWindowHandleFromIDispatch(WebBrowser1.Document) Result := 0; Res := disp.QueryInterface(IID_IOleWindow, oWin); if Succeeded(Res) then begin Res := OWin.GetWindow(h); if (SUCCEEDED(Res)) then Result := h; end; end; |
|
使 い 方 |
// Class : Internet Explorer_Server h := GetHTMLObjectWindowHandle(WebBrowser1.Document); if (h > 0) then Windows.SetFocus(h); |
(参考)正 規のhtml要素のfocusの使い方 |
|
|
// HtmlElement から直接呼び出す場合 // HtmlElement.focus(); var v : Variant; begin v_Doccument := WebBrowser1.Document; if Not VarIsClear(v_Doccument) then v_Doccument.focus(); |
|
var v_Doccument, v_elems : Variant; begin v_Doccument := WebBrowser1.Document; if VarIsClear(v_Doccument) then exit; v_elems := v_Doccument.getElementsByName('ここにhtml要素の名前'); if Not VarIsClear(v_elems) and (v_elems.length > 0) then v_elems.Item(0).focus(); |
擬似キー入力を送るコード:Function Key
var H : THandle; begin h := GetWindowHandleFromIDispatch(WebBrowser1.Document); Windows.PostMessage(H , WM_KEYDOWN, VK_F1 , 0); |
擬似キー入力を送るコード:通常文字
var H : THandle; begin h := GetWindowHandleFromIDispatch(WebBrowser1.Document); Windows.PostMessage(H , WM_CHAR, Byte('a') , 0); end; |
ALT+F4(終了)を呼びたい場合は
WM_SYSKEYDOWN を使います
Windows.PostMessage(TargetHandle , WM_SYSKEYDOWN , wParam, lParam); |
||
wParam |
lParam |
|
VK_F4 + ALT | VK_F4 |
1 shl 29 |
VK_F1
IEのF1(ヘルプ)の呼び出しは、反応しないのでわかりません。
Firefox系の他のブラウザでは反応します。
Firefox系の他のブラウザでは反応します。
テキストボックスに文字列をいれるだけなら、
普通にgetElementsByNameやgetElementByIdなどで
要素にアクセスして代入した方が安全に入力できます。
普通にテキストボックスに入力する方法
( 応用例:ログインIDなどの自動入力 )
例 v_elems.Item(0).innerText := 'abc'; |
|
.innerText | |
|
.innerHTML |
コンボボックス (selectタグのoption要素) |
e.options[e.selectedIndex].text e.options[e.selectedIndex].value |
【一番上のShell DocObject View の HWND 取得方法】
GetWindow(WebBrowser1.Handle, GW_CHILD )
※ ClassNameで、確認した方がいい 、 GW_HWNDNEXT
Navigateでフォルダを指定した場合、エクスプローラーが内蔵されるので注意。 SysListView32などが現れる。
function GetWebBrowser_Root_ShellDocObject_Handle(AWebBrowser : TWebBrowser) : hwnd; // Shell DocObject View var h : hwnd; begin h := GetWindow(AWebBrowser.Handle, GW_CHILD ); while (h > 0) do begin if (Pos('Shell DocObject View', GetClassNameText(h)) = 1) then begin Result := h; Break; end; h := GetWindow(h, GW_HWNDNEXT ); end; end; |
function GetWebBrowser_Root_IE_Server_Handle(AWebBrowser : TWebBrowser) : hwnd; // Internet Explorer_Server var h : hwnd; h_child : hwnd; begin h := GetWindow(AWebBrowser.Handle, GW_CHILD ); while (h > 0) do begin if (Pos('Shell DocObject View', GetClassNameText(h)) = 1) then begin h_child := GetWindow(h, GW_CHILD ); while (h_child > 0) do begin if (Pos('Internet Explorer_Server', GetClassNameText(h_child)) = 1) then begin Result := h_child; break; end; h_child := GetWindow(h_child, GW_HWNDNEXT ); end; if (Result > 0) then Break; end; h := GetWindow(h, GW_HWNDNEXT ); end; end; |
【場所から取得する方法】
・ ChildWindowFromPoint関数を使用します。
ついでに、それいけみんなドットネットなので
C#で、ハンドルにメッセージを送る方法は
知らないので
[System.Runtime.InteropServices.DllImport("user32.dll")]
private extern static System.Boolean PostMessage(
System.IntPtr hWnd,
System.UInt32 Msg,
System.Int32 wParam,
System.Int32 lParam);
で回避することができる。