DOBON.NET DOBON.NETプログラミング掲示板過去ログ

直前のウィンドウをアクティブにする

環境/言語:[Windows2000, XP]
分類:[.NET]

直前のウィンドウをアクティブにして、そこに文字列を書き込もうとしていますが、
目的のウィンドウは最前面に来るのですがアクティブになりません。

Win98/2000移行では、切り替え可能なプロセスは、
システムにより制限されるようになった
というところまでは行き着いたのですが、
それではいったいどうすれば良いのかがさっぱり分かりません。

どなたか教えて頂けないでしょうか?

APIを使って、以下の処理で以前はうまくいっていたのですが
アクティブにならない為に文字列が書き込まれなくなりました。

=================================================

'直前のウィンドウをアクティブにする
Dim lngHwnd As Integer = GetForegroundWindow
lngHwnd = GetNextWindow(lngHwnd, 2)
Call SetForegroundWindow(lngHwnd)

'クリップボードにコピー
Clipboard.SetDataObject("あいうえお", True)
'Ctrl+V を送信
SendKeys.Send("^v")

=================================================

よろしくお願いいたします。
> Win98/2000移行では、切り替え可能なプロセスは、
> システムにより制限されるようになった
> というところまでは行き着いたのですが、
> それではいったいどうすれば良いのかがさっぱり分かりません。

その部分だけに答えるなら、たとえばこんな感じ。
http://yaplog.jp/orator/archive/48

# VB.NET ではなく、VB6 向けのコードですけど…。m(_ _)m
早速のご教授、ありがとうございます。

> その部分だけに答えるなら、たとえばこんな感じ。
> http://yaplog.jp/orator/archive/48
>
> # VB.NET ではなく、VB6 向けのコードですけど…。m(_ _)m

自動変換できるので VB6 で問題ないですが、
ご教授頂いたコードでもうまくいきません。

やっていることは、メモ帳を開いてアクティブにし、
そのままの状態でフォーム上のボタンを押下すると
メモ帳にアクティブが移るというテストをしているのですが
はじめに書いたコードを .NET で動かすとメモ帳が全面に移動するのですが
作成したフォームがアクティブのままです。

ご教授頂いたコードを VB6 で動かすとメモ帳が全面に移動しません。
もちろん、作成したフォームがアクティブのままです。

上記の
Call SetForegroundWindow(lngHwnd)
部分を
Call SetForceForegroundWindow(lngHwnd)
に変更し

lngHwnd = GetForegroundWindow
lngHwnd = GetNextWindow(lngHwnd, 2)
Call SetForceForegroundWindow(lngHwnd)

としたのですが、根本的にやっていることが間違っているのでしょうか?
ド素人なもので、何やってんだと思われるかもしれませんが
よろしくお願いいたします。

私の方もいろいろテストやら調査やらをもう少しやってみます。
カナブンさん,こんばんは。

> lngHwnd = GetForegroundWindow
> lngHwnd = GetNextWindow(lngHwnd, 2)

で得られるウィンドウハンドルは私の環境ではIMEのパレットのウィンドウハンドルの様です。
おそらくメモ帳のウィンドウハンドルをきちんと得られていないのでは?
ただ,メモ帳のウィンドウを前にもってくるだけなら次のコードでできました。

Dim p As Process() = Process.GetProcessesByName("notepad")
Dim PId As Integer = p(0).Id
AppActivate(PId)
Clipboard.SetDataObject("あいうえお", True)
SendKeys.Send("^v")

フォアグラウンドウィンドウの次のウィンドウを取得しようと

GetNextWindow(GetWindow)
EnumWindows

を試してみたのですが,なぜか子ウィンドウも列挙されてしまいうまく
いきませんでした。(VB2005,WindowsXP)
2006/03/12(Sun) 14:39:35 編集(投稿者)

> GetNextWindow(GetWindow)
> EnumWindows
>
> を試してみたのですが,なぜか子ウィンドウも列挙されてしまいうまく
> いきませんでした。(VB2005,WindowsXP)

間違いでした。子ウィンドウではなくて表示されていないウィンドウも
列挙されているのでした。
ですから,表示されていないウィンドウを除外すれば「直前のウィンドウ」
が取得できそうです。(でも処理中にウィンドウのZ-オーダーが変更に
なったらどうなってしまうんでしょう? ちょっと心配な処理です。)

<DllImport("user32")> _
Private Shared Function IsWindowVisible( _
ByVal hWnd As IntPtr) _
As Integer
End Function

Dim hWnd As IntPtr = GetForegroundWindow()
hWnd = GetWindow(hWnd, GW.HWNDNEXT)
Do While hWnd <> IntPtr.Zero
If IsWindowVisible(hWnd) Then
SetForegroundWindow(hWnd)
Clipboard.SetDataObject("あいうえお", True)
SendKeys.Send("^v")
Exit Do
End If
hWnd = GetWindow(hWnd, GW.HWNDNEXT)
Loop
YASさん、情報ありがとうございます。
返信が遅くなって申し訳ありませんでした。

> ただ,メモ帳のウィンドウを前にもってくるだけなら次のコードでできました。
メモ帳は例であって、目的は表題の通り直前のウィンドウです。

YASさんの情報も含め、もう少し研究してみます。
(現在いるところは環境がないので)
ウィンドウの列挙の「ウィンドウ」はフォームのことではありません。
ですので、可視、最小化、キャプションが""ではない、などウィンドウ(ハンドル)が
目的のものかどうかを適切に判断する必要があります。
まずは、列挙した一覧をListBoxなどに表示させて選択されたものに対して件名の処理をする
といったものを作成されていろいろ試してみるとよいでしょう。
まどかさん
助言ありがとうございます。

現在私が困っている内容を整理すると

Dim lngHwnd As Integer = GetForegroundWindow
lngHwnd = GetNextWindow(lngHwnd, 2)
Call SetForegroundWindow(lngHwnd)

これで、直前にアクティブになっていたアプリがちゃんと最前面に来ます。
しかしアクティブにならないのです。
魔界の仮面弁士さんのソースを .NET に変換して動かしても
最前面に来るがアクティブにならないという、同じ現象です。
(Re[2]で「メモ帳が全面に移動しません」と書いたのは、テストした私のソースに間違いがありました)

つまり、最前面に来てもアクティブになっていないので
SendKeys.Send("^v")
で文字列を貼り付けようとしても張り付きません。

目的は最前面にすることではなく、文字列をペーストすることです。
それが出来れば極端な話、全面に来なくても良いのです。

皆さんの助言を基に、もう少し研究してみます。
> Dim lngHwnd As Integer = GetForegroundWindow
> lngHwnd = GetNextWindow(lngHwnd, 2)
> Call SetForegroundWindow(lngHwnd)

前回にも書きましたが,たぶん,lngHwndに入っている値が前にもってきたい
ウィンドウのウィンドウハンドルではないのです。
debug.print(lngHwnd)で値を確認してみてください。

ところで私が14816で示したコードは動作しませんか?
「直前のウィンドウ」が前に来るはずです。
一応動作を確認したコードなのですが...
> 目的は最前面にすることではなく、文字列をペーストすることです。
> それが出来れば極端な話、全面に来なくても良いのです。

であれば、入力カーソルを持つウィンドウハンドルを求めて、WM_SETTEXTするとか。
これも相手を見つけるのが難しいですけど。。。
#やったことが無いので聞かないで。(汗

結局話が戻りますが、アクティブになったからといって
Editウィンドウが入力フォーカスを持っているとは限りません。
「直前のフォアグラウンドウィンドウに文字列を送る」という点が
スクリーンキーボードと似ているのですが,私がスクリーンキーボードを作った
ときには,100ms間隔くらいでフォアグラウンドウィンドウをポーリングして
自分がフォアグラウンドになったら直前のフォアグラウンドウィンドウを
アクティブにするという方法にしました。

下のアドレスに制作過程がまとめてありますので,よろしければ参考にしてください。
http://homepage1.nifty.com/yasunari/VB/VB2005/ScreenKeyBoardMaking.htm
YASさん

> 前回にも書きましたが,たぶん,lngHwndに入っている値が前にもってきたい
> ウィンドウのウィンドウハンドルではないのです。

最前面には来ているのですが・・・

> ところで私が14816で示したコードは動作しませんか?
> 「直前のウィンドウ」が前に来るはずです。
> 一応動作を確認したコードなのですが...

14821に書いたのですが、現在 VB も .NET もない環境に居るので確認していません。
(VB2005 も持っていませんし)
申し訳ありません。
親切にコメントして頂いているのに、返事を書かないと無視しているようで失礼かと思いコメントだけ書いていました。
これからは確認してからコメントを書くようにします。
申し訳ありませんでした。

> 下のアドレスに制作過程がまとめてありますので,よろしければ参考にしてください。
> http://homepage1.nifty.com/yasunari/VB/VB2005/ScreenKeyBoardMaking.htm

ご親切にありがとうございます。
参考にさせて頂きます。
このやり方でうまくいきそうですが、VB2005は初めて目にしますので
うまく .NET 用に変換し確認できるかあまり自信がありませんが、頑張ってみます。
(全ておんぶにだっこだと勉強にならないので)
少しお時間を下さい。

まどかさんも、おばかな私につきあって頂き、感謝しております。
現在、YASさんのコードを参考に四苦八苦しています。

VB2005 は持っていないし(VB6 と .NET しか持っていない)
VB2005 から .NET へ自動変換できないし、
サンプルのスクリーンキーボードを実行してみようとすると「.NET Framework v2.0.50727 をインストールする必要がある」とメッセージが出るし
(私の環境は .NET Framework 1.1)
取りあえず手書きで移植してみようとしたのですが、IntPtr型変数の If文のところで
「演算子'<>'は、型'System.IntPtr'および'System.IntPtr'に対して定義されていません。」
というエラーになるし・・・
IntPtr という型は VB6 を使っていた頃には見たことがないし・・・

ということで、14816で示して頂いたコードもスクリーンキーボードのサンプルも未だに動かせていません。
もう少し頑張ってみますが、今の私の実力では VB2005 から .NET への移行は難しそうです。
( T ^ T ) グッスン
> IntPtr という型は VB6 を使っていた頃には見たことがないし・・・
ポインタや Win32 のハンドルなどは、IntPtr 型として表現されます。
VB6 には該当する型はありませんが、内部的には 32bitの整数型なので、
強いて言えば、「As OLE_HANDLE」や「As Long」に相当する物です。

# Win64 環境では 64bit ですけれども。


> 「演算子'<>'は、型'System.IntPtr'および'System.IntPtr'に対して定義されていません。」
Equals メソッドで比較するか、ToInt32 メソッドで数値化してから比較します。


> 今の私の実力では VB2005 から .NET への移行は難しそうです。
# VB2005 も .NET です。

ならば、Visual Basic 2005 Expression Edition をダウンロードして、
そちらで開発してみて、それでうまく行ってから 2003 に逆移植するとか。
最終的な目的がわからないのでなんともいえませんが、
マイクロソフトの
http://www.microsoft.com/japan/msdn/vbasic/migration/tips/windowsapp.aspx
は、参考になりませんか。
Formをアクティブにならないようにして、アクティブなウィンドウ(メモ帳など)に
入力ができますが。(サンプルコード付。)
2006/03/14(Tue) 23:53:16 編集(投稿者)

■No14837に返信(カナブンさんの記事)
> 現在、YASさんのコードを参考に四苦八苦しています。

参考にしていただき,ありがとうございます。(うれしいです。)
大サービスでVB.NET 2003のソリューションにしておきました。
VB.NET 2003にないクラスはばっさり削り,とりあえず動くという
状態ですが,よろしければ参考になさってください。

http://homepage1.nifty.com/yasunari/VB/VB2005/ScreenKeyboardFor2003.zip
あーでもない、こーでもない、こうすればうまくいきそうだ・・・
なんてやっている内に、思い出したように掲示板を見てみると解決していました。

魔界の仮面弁士さん、解説ありがとうございます。

こどさん、マイクロソフトのサンプルページをご紹介頂きありがとうございます。
大変参考になります。

YASさん、VB.NET 2003のソリューションにして頂きありがとうございます。

こんなに親切な方がいて大変感激、感謝しています。
こどさんの紹介頂いたサンプル、YASさんの作成して頂いたサンプルを丸写しにすれば解決しますので、この掲示板は解決のステータスにします。
但し、それでは私の身になりませんので、これから個人的にソースを解読し、やっていることを理解して身につけるようにします。

本当に皆さんありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板