中堅プログラマーの備忘録

忘れっぽくなってきたので備忘録として・・・

【C#.net】アクティブウィンドウの状態を切り替え、監視制御を行う。

1.概要

運用上、常にアクティブ状態である必要があるアプリケーションウィンドウがあります。
これが何かしらの原因で、フォーカスが失われアクティブ状態から抜けてしまうことがあります。
例えば、エラーポップアップなどがこれにあたるのではないでしょうか?
今回はこの問題を解決してみたいと思います。

2.アクティブなウィンドウ名を取得する

まずは現在アクティブな状態のウィンドウ名を取得します。
ここで重要なのはアプリケーション名ではなくウィンドウ名になります。
例えば【Chrome】で【YAHOO】のページを開いているウィンドウがアクティブな場合は
【Yahoo! JAPAN - Google Chrome】
となります。

ではどのようにして取得するのかというと
【GetForegroundWindow】でアクティブ状態のウィンドウハンドルを取得し
それをもとに【GetWindowText】でウィンドウのタイトルを取得します。

3.外部アプリをアクティブにする

方法ですが実行されているすべてのプロセスを取得し
その中から指定の文字列(アクティブにしたいウィンドウ名)を探し
一致するものがあったら
【SetForegroundWindow】にウィンドウハンドルを渡し
アクティブ状態にします。

4.スクリプト

【Form】に【Label】と【Button】を貼り付けています。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace moveFront
{
    public partial class Form1 : Form
    {
        [DllImport("USER32.DLL")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("USER32.DLL",CharSet = CharSet.Auto)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int length);

        [DllImport("USER32.DLL")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string activeAppName;
            StringBuilder sb = new StringBuilder(256);
            IntPtr hWnd = GetForegroundWindow();
            // hWndはMainWindowが存在する(0ではない)
            if (!IntPtr.Zero.Equals(hWnd))
            {
                int ret = GetWindowText(hWnd, sb, 256);
                string windowName = "メモ帳";
                if (sb.ToString(0, ret) != windowName)
                {
                    activeAppName = sb.ToString(0, ret);
                    foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
                    {
                        if (0 <= p.MainWindowTitle.IndexOf(windowName))
                        {
                            SetForegroundWindow(p.MainWindowHandle);
                            label1.Text = activeAppName + "から" + windowName + "をアクティブにしました。";
                            return;
                        }
                    }
                    label1.Text = windowName + "は存在しません。";
                }
                else
                {
                    label1.Text = windowName + "はアクティブ状態です。";
                }
            }
        }
    }
}

5.結果

今回は【メモ帳】をターゲットにしました。
結果は下図のとおりです。
f:id:tsu--kun:20190926101521p:plain


Form上にあるボタンをクリックしてから処理が走るので
【Form1からメモ帳をアクティブにしました】
となってしまいますが、やりたいことは実現出来ました。
また、
【メモ帳】が起動していない時:【メモ帳は存在しません。】
【メモ帳】がアクティブ状態 :【メモ帳はアクティブ状態です。】
となります。