C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

他のアプリのウインドウ位置を制御

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■95758 / inTopicNo.1)  他のアプリのウインドウ位置を制御
  
□投稿者/ ドフトエフスキー (1回)-(2020/09/19(Sat) 05:42:39)

分類:[.NET 全般] 

お世話になります

VB.NETで他のアプリのウインドウ位置を制御するプログラムを作りたいです

1.マルチモニターの座標取得
2.現在表示中のウインドウのハンドル取得
3.現在表示中のウインドウのアプリ名取得
4.ハンドルからエクスプローラか否かの判定
5.他のアプリのハンドルを取得して、指定の座標へ移動
6.他のアプリのハンドルを取得して、指定の大きさに変更


上記1〜6を実行すれば
ボタン一つで毎回自分好みのウインドウ状態にできるように思います

vb.netで実現可能か否かを教えていただけませんでしょうか
なるべくvb.netだけで処理して
無理なものだけapiを使いたいと思っています

いろいろぐぐりながら作ろうと思いますが

上記を実現できるスキルのある方からのアドバイス
もしくは
そもそも不可能でしたら、どの部分が不可能かを教えていただきたいです

よろしくお願いします

引用返信 編集キー/
■95759 / inTopicNo.2)  Re[1]: 他のアプリのウインドウ位置を制御
□投稿者/ Hongliang (1088回)-(2020/09/19(Sat) 09:27:39)
以下、可能かどうかは.NET Frameworkの標準ライブラリにあるかどうかという基準です。

> 1.マルチモニターの座標取得
System.Windows.Forms.Screenでできます。

> 2.現在表示中のウインドウのハンドル取得
自分自身のウィンドウハンドルならForm.Handleとかで取得できます。
他プロセスのウィンドウハンドルは、Process.MainWindowHandleでプロセスごとに1つだけは取得できます。
ウィンドウを2つ以上表示しているプロセスの2つ目以降のウィンドウハンドルは無理です。

> 3.現在表示中のウインドウのアプリ名取得
アプリ名って何を指しているのでしょう?
まあそもそもウィンドウを列挙できないので、不可能です。
ところでアプリケーションを識別したいだけなら、アプリ名ではなく例えば実行ファイル名とかで識別することも考えた方がプログラミングは楽かもしれません。

> 4.ハンドルからエクスプローラか否かの判定
ハンドルってウィンドウハンドルのことでいいでしょうか?
不可能ですね。

> 5.他のアプリのハンドルを取得して、指定の座標へ移動
ハンドルってウィンドウハンドルのことでいいでしょうか?
不可能ですね。

> 6.他のアプリのハンドルを取得して、指定の大きさに変更
ハンドルってウィンドウハンドルのことでいいでしょうか?
不可能ですね。
引用返信 編集キー/
■95760 / inTopicNo.3)  Re[1]: 他のアプリのウインドウ位置を制御
□投稿者/ 魔界の仮面弁士 (2837回)-(2020/09/19(Sat) 14:30:28)
No95758 (ドフトエフスキー さん) に返信
> 1.マルチモニターの座標取得
仮想デスクトップをどうするべきか…。
https://www.softel.co.jp/blogs/tech/archives/5317


> 上記1〜6を実行すれば
> ボタン一つで毎回自分好みのウインドウ状態にできるように思います

手抜き実装なので、ウィンドウの状態(最小化など)の確認や
ウィンドウの位置を覚えさせる処理などは作りこんでいませんが、参考までに。

System.Windows.Forms.Form に、Button を 2 つと
ListBox / ListView を 1 つずつ貼り、参照設定に
 [System.Windows]
 [UIAutomationClient]
 [UIAutomationTypes]
 [WindowsBase]
を加えておいてください。


Option Strict On
Option Explicit On
Public Class Form1
  Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
    Button2.Enabled = ListView1.SelectedItems.Count > 0
  End Sub

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Button1.Text = "列挙"
    Button2.Text = "移動"
    Button2.Enabled = False
    ListView1.View = View.Details
    ListView1.FullRowSelect = True
    ListView1.GridLines = True
    ListView1.Columns.Clear()
    ListView1.Columns.Add("PID")
    ListView1.Columns.Add("Process")
    ListView1.Columns.Add("Name")
    ListView1.Columns.Add("HWND")
    ListView1.Columns.Add("Bounds")
    ListView1.Columns.Add("FrameworkId")
    ListView1.Columns.Add("ClassName")
  End Sub

  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ListBox1.DataSource = System.Windows.Forms.Screen.AllScreens.Select(Function(scr) scr.DeviceName & " - " & scr.Bounds.ToString() & If(scr.Primary, "(メインモニタ)", "")).ToList()

    Dim rawView = System.Windows.Automation.TreeWalker.RawViewWalker
    Dim aeForm = System.Windows.Automation.AutomationElement.FromHandle(Me.Handle)
    Dim sibling = rawView.GetNextSibling(aeForm)

    ListView1.BeginUpdate()
    ListView1.Items.Clear()
    Dim procs As New Dictionary(Of Integer, String)()
    Do Until sibling Is Nothing
      With sibling.Current
        Dim pid = .ProcessId
        If Not procs.ContainsKey(pid) Then
          Using p = Process.GetProcessById(pid)
            procs.Add(pid, p.ProcessName)
          End Using
        End If
        Dim item = ListView1.Items.Add(pid.ToString())
        item.Tag = sibling
        item.SubItems.Add(procs(pid))
        item.SubItems.Add(.Name)
        item.SubItems.Add("&H" & .NativeWindowHandle.ToString("X8"))
        item.SubItems.Add(.BoundingRectangle.ToString())
        item.SubItems.Add(.FrameworkId)
        item.SubItems.Add(.ClassName)
      End With
      sibling = rawView.GetNextSibling(sibling)
    Loop
    ListView1.EndUpdate()
  End Sub

  Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim element = TryCast(ListView1.SelectedItems(0).Tag, System.Windows.Automation.AutomationElement)
    If element Is Nothing Then
      MessageBox.Show("UI 要素が未選択です。", "要素なし", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
      Return
    End If
    Dim currentName As String = Nothing
    Try
      currentName = element.Current.Name
    Catch
      MessageBox.Show("この要素には現在アクセスできません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
      Return
    End Try

    Dim obj As Object = Nothing
    If element.TryGetCurrentPattern(System.Windows.Automation.TransformPattern.Pattern, obj) Then
      Dim result = MessageBox.Show(currentName & vbCrLf & "(100, 80)-(300, 230) に移動させます。よろしいですか?", "確認", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
      If result = System.Windows.Forms.DialogResult.Cancel Then
        Return
      End If

      Dim transPattern = DirectCast(obj, System.Windows.Automation.TransformPattern)
      Try
        transPattern.Move(100, 80)
        transPattern.Resize(300 - 100, 230 - 80)
      Catch ex As InvalidOperationException
        MessageBox.Show("この要素は現在移動できません。", "移動失敗", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
      End Try
    Else
      MessageBox.Show("この要素の移動はサポートされていません。", "移動失敗", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
    End If
  End Sub
End Class
引用返信 編集キー/
■95761 / inTopicNo.4)  Re[2]: 他のアプリのウインドウ位置を制御
□投稿者/ ドフトエフスキー (2回)-(2020/09/20(Sun) 13:34:34)
No95759 (Hongliang さん) に返信
> 以下、可能かどうかは.NET Frameworkの標準ライブラリにあるかどうかという基準です。

.NET Frameworkの標準ライブラリだけで作ろうとしているわけではないのですが
質問でうまく説明できていませんでした

いろいろ試してみようと思います
ありがとうございました
引用返信 編集キー/
■95762 / inTopicNo.5)  Re[2]: 他のアプリのウインドウ位置を制御
□投稿者/ ドフトエフスキー (3回)-(2020/09/20(Sun) 13:37:06)
No95760 (魔界の仮面弁士 さん) に返信

日本語で検索しても到底出てこないようなご回答ありがとうございます
自分で調べても到達できない内容でした

今からひとつづつコードを試してみます

引用返信 編集キー/
■95848 / inTopicNo.6)  Re[3]: 他のアプリのウインドウ位置を制御
□投稿者/ ドフトエフスキー (4回)-(2020/10/03(Sat) 09:23:35)
No95762 (ドフトエフスキー さん) に返信
> ■No95760 (魔界の仮面弁士 さん) に返信
>
> 日本語で検索しても到底出てこないようなご回答ありがとうございます
> 自分で調べても到達できない内容でした
>
> 今からひとつづつコードを試してみます
>


ウイルス判定されそうで怖いですが
ご教授いただきました、コードを試してみましたところ
ほぼ希望の動作を実現することができました

Do Until sibling Is Nothing の動きが制御しづらかったので

動作の直前に、一旦 hwnd をリストで保持して
リストを使って下記のコードを回すようにしました

dim IDOUSAKI as new rectangle(0,0,100,100)
Dim element As System.Windows.Automation.AutomationElement = System.Windows.Automation.AutomationElement.FromHandle(hWnd)

If element.TryGetCurrentPattern(System.Windows.Automation.TransformPattern.Pattern, obj) Then
Dim transPattern As System.Windows.Automation.TransformPattern = DirectCast(obj, System.Windows.Automation.TransformPattern)
Try
transPattern.Move(IDOUSAKI.Left, IDOUSAKI.Top)
transPattern.Resize(IDOUSAKI.Width, IDOUSAKI.Height)
Catch ex As InvalidOperationException

End Try
Else

End If


実際に処理されたことを確認するために
下記のように処置されなくなるまでリストを何度も回してフラグで判定するようにしましたが
そんな必要はないものでしょうか?

dim 処理されました as boolean=false

do

処理されました =false
for each hwnd in リスト
dim 判定 as boolean=処理されたらtrueになるコード
if 判定=true then
  処理されました=true
end if
next

loop While 処置されました



ちなみにいろいろ調べているうちに Windowsボタン+tab でやりたいことができることがわかりました
知らないけど便利な機能がたくさんあるもんですね


引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ