TWebBrowser.HWNDを取得する方法 (メモ: その1)
執筆: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でいいようです。
構造
ページを表示するとコンテンツに応じて 上の3つが、階層構造で多様につながる。
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系の他のブラウザでは反応します。
テキストボックスに文字列をいれるだけなら、
普通にgetElementsByNameやgetElementByIdなどで
要素にアクセスして代入した方が安全に入力できます。
普通にテキストボックスに入力する方法
( 応用例:ログインIDなどの自動入力 )
例
v_elems.Item(0).innerText := 'abc';
|
|
.innerText |
|
.innerHTML |
コンボボックス
(selectタグのoption要素)
|
e.options[e.selectedIndex].text
e.options[e.selectedIndex].value
|
使い方は、基本的にJavaScriptと同じ。
【一番上の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);
で回避することができる。
「1時間以内なら、電源を切るよりスタンバイが節電になる」はウソ!!
執筆:2011.9.30
編集:2011.9.30
TVでよく、
1時間以内に再使用するなら、電源を切るよりスタンバイが節電になる
といっているが
前々から 非常に うそくさい と思っていたので 検証してみました。
デスクトップPCで
電力計を使って検証してみました。
ノートPCは、携帯性・移動性などの面から省電力に特化されているので今回は比較しません。
【まとめ : デスクトップPC】
- スタンバイを使うときは慎重に
周辺機器、ソフトウェア エラーなどの問題がないかの検討・検証が必要です。
- スタンバイよりモニターの省電力機能を使うだけのほうが安全です。
- 数時間使用しない場合は、待機電力自体を節電タップで落としたほうがよい。
※スタンバイになっている時に節電タップで電源を落とす事故のないようにお気を付けください。
- 運用時間に節電しても1日数十円と1台あたりの費用効果が非常に低いので、
使用時間・頻度・保有台数・節電による遅延、作業不履行損失など慎重に検討したうえで、節電計画をたてよう。
- 筆者PCでは、5~6分が「電源を切る」と「スタンバイ」の損益分岐点である
- システム構成と電源の供給方法で大きく電力消費が変わるので
おおよその節電になる正確な時間を知るには、電力計(ワットメーター)が必要になります。
モニターの制御は、
画面のプロパティ - モニタ電源 - 電源オプションのプロパティ
で、簡単に設定することができます。
マザーボード説明書では、2種類のスタンバイモードに対応で、設定を変えても電力は同じ値でした。
もともと低電力CPUのためか、メインボードがアホなのか、非対応周辺機器への配慮のためなのかはわかりませんが、
スタンバイになってもPC本体の電力変化が期待するほどありませんでした。
※普段使用する実環境で、計測しないと意味がないと思いますし、
取り外しが面倒なので、スタンバイ非対応のUSB PCIボードは接続したままです。
今回の調査で、筆者のPCは、
「スタンバイ時」と「モニターだけ電源を切った状態」との電力差が7W未満とあまり差がないので
スタンバイ使用自体に意味がないことがわかりました。
筆者のPCは、5分が分岐点なので、
トイレくらいならモニターを切って対処し
それ以外で、席を離れる際は、今まで通り 電源を切ることにしました。
コンセントに1日中つなぎっぱなしの場合は、
半日使用しないとすると節電タップの費用は半年~1年で回収できるので節電タップの購入をお勧めします。
なお 節電を極めるには、ノートPCのほうが効率がいいでしょう
【内容 デスクトップ PC】
パソコン(モニターを含む)
CPU:1900MHz 45W
(2.5インチHDD)
|
消費電力
|
1日あたり
|
30日間
|
1年間
|
待機時
|
3.5W
|
3.4円/日
|
102円
|
1241円
|
On直後
|
90.7W
|
|
|
|
OS起動
|
92.7W
|
|
|
|
ロゴ中
|
77.6~82W
Max 94W
|
|
|
|
ユーザー
選択画面
|
73-82W
しばらく待つと
72.3-78W |
|
|
|
選択クリック
|
73.9-87-93W
の間で変動
|
|
|
|
このページの編集中
|
72.1W
|
36.3円/日 |
|
|
このページの編集中
+モニター電源切断
|
52.5W
|
26.8円/日 |
|
|
スタンバイ時
|
45.9W
|
|
|
|
スタンバイ時
+モニター電源切断
|
44.6~44.7W
|
|
|
|
上の表をみても、スタンバイでMAXの半分程度なので
電源を切るより、スタンバイのほうが、1時間以内では節電なんていうことは 明らかにウソ。
では、計算で、分岐点を調べて見ましょう
起動中は 平均80W程度なのですが、大きめに見積もって90Wで計算します。
再起動をクリックして、起動後のデスクトップの砂時計が消えるまでの時間:2分30秒間(150秒)
終了+起動に2分30秒間(150秒)かかるという計算で
150秒×90W = t 秒×45.9W
t = 150秒×90W ÷ 45.9W = 294秒 ≒ 約5分
(安定までに180秒で大きめに見積もっても、6分弱が分岐点。)
単純に5分以上使わないときは、PCを丸ごと切った方がいいということになります。
いくつかのソフトを起動して作業環境を構築する時間を考慮すると1~3分は加味した方がいいかもしれないです。
※ |
即座に利用しないといけないような環境の場合は、電源を切ると不都 合があるので注意が必要です。 |
|
|
※ |
スタンバイにすることによって、スタンバイ非対応の周辺機器やアプ リケーションが不安定やエラーになることがあるので
スタンバイを安易に使うのは避けたほうがいいでしょう。
スタンバイ・休止機能を使う際は、問題が発生しないか十分検証しましょう。 |
|
|
スタンバイにすることによって、スタンバイ非対応の周辺機器やアプリケーションが不安定やエラーになることがあるので
5分以内ならモニターの電源を切るだけがもっとも安定性のいい節電といえる。
※ |
節電タップを使わなくても
電源オプションのプロパティのモニターの設 定で、未使用時間に応じて自動でモニターの電源を切ることができる。 |
|
|
では、待機電力が1起動分の電力になる時間を計算してみよう。
電源Pushから起動までに約130秒
130秒×90W = t 秒×3.5W
t = 130秒×90W ÷ 3.5W ≒ 約55.7分
60分間使わない場合は、1起動分の電力になるので、待機電力自体を節電タップで落としたほうがよさそうです。
スタンバイは、CPUとメモリに最低限の通電をしている状態なので、どんなにがんばっても待機電力より大きい値となります。
仮にBIOSの設定をいじって、 スタンバイが待機電力に近い値になると想定し、
+1W : t = 150秒×90W ÷ (3.5W+1W) ≒ 約50分
+2W : t = 150秒×90W ÷ (3.5W+2W) ≒ 約41分
+5W : t = 150秒×90W ÷ (3.5W+5W) ≒ 約26.5分
で計算しても
百歩譲っても 分岐点は 50分以上に設定することは困難です。
以上より
本PCでは
「1時間以内なら、電源を切るよりスタンバイが節電になる」
というのは、当てはまりません。
なお、何度も言っていますが、本PCでは、デフォルト状態では、5~6分が分岐点です!!
【内容 ノートPC Windows 7】
参考までに、ノートPCでも計測しました。
バッテリーがフル充電になるのを待ってから 計測。
※スタンバイモードがないので未計測。
|
消費電力
|
1日あたり
|
30日間
|
1年間
|
待機時
|
W
|
-円/日
|
-円
|
-円
|
スタンバイ時
|
W
|
|
|
|
OS起動
|
W
|
|
|
|
ロゴ中
|
~W
|
|
|
|
ユーザー
選択画面
|
-W
しばらく待つと
-W |
|
|
|
選択クリック
|
-W
の間で変動
|
|
|
|
このページの編集中
|
22.5W
|
11.4円/日 |
|
|
t = 起動時間×起動電力 ÷ スタンバイ電力
= 60秒×0W ÷ .W ≒ 約.分
【資料】
今回使用した道具
ワットメーター(TAP-TST8)
商品はこれ
TAP-TST8
|
SANWA SUPPLY ワットモニター TAP-TST8
サンワサプライ
|
買ったときは発売開始直後だったので、 送料込みで、3445円で買いました。
先日値段をみたときは、3000円を下回ってしました。
購入しても元を取り戻せるような商品ではありませんが
もっていると壊れるまで、いろいろ計測できて楽しめる商品です。
待機電力は、家電の寿命、電気代に影響し、不幸な家電事故の原因になる可能性がありますので、
待機が不要な電気製品の不要な待機電力の削減をおすすめします。
ワット計の購入よりも
節電タップを持っていない場合は、節電タップの購入を優先した方がいいと思います。
節電タップは、ホームセンターや電気屋さんで600円前後くらいで売っていると思います。
ブレーカーや雷サージ付きの節電タップは1000~2000円くらいすると思います。
付近への落雷で電気製品がよく壊れるっていうかたは、
破損を防いでくれる場合があるそうなので
雷サージ付きのタップの購入をお勧めします。