【C#】アクティブウィンドウ切り替えツール


この記事はプロモーションを含みます。

C#

C#で、指定した2つのアプリを交互にアクティブにするツールを作成したので公開します。

ツールについて

本ツールについて簡単に説明します。
まず、以下がツールの実行イメージです。

簡単に使い方を説明します。

1.「アプリケーション情報取得」ボタンをクリック
 切り替える事が出来るアプリの一覧を取得します。

2.リストから切り替えるアプリを選択
 本ツール(Form1)が自動で選択されるので、もう1つのアプリを選択します。
 本ツール以外を選択しても構いません。

リストに表示されるアプリ名ですが、これは、ウィンドウ名を取ってきているだけなので、同じ名前のものが複数表示される場合があります。

3.「待機中」ボタンをクリック
 ボタンが「実行中」に変われば、処理が開始されており、
 切り替え間隔(秒)ごとにアクティブウィンドウが切り替わります。

切り替え対象のアプリが最小化されていると、最小化された状態でアプリを切り替えてしまうので、デスクトップに表示した状態で実行することで、正しく切り替えが行われます。

4.切り替えの停止
 「実行中」ボタンをクリックすると、切り替えが停止します。
 停止処理ですが、停止後に1回切り替えが行われる場合があります。
 これは、停止処理が次回以降のループを処理しないようにしているだけで、
 直ちに処理を停止するような作りになっていないためです。

ソースコード

以下が、本ツールのソースコードです。
.NET Framework 4.8 環境で実装しました。

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SwitchWindows
{
    public partial class Form1 : Form
    {
        // user32.dllからSetForegroundWindowをインポート
        [DllImport("user32.dll")]
        public static extern IntPtr SetForegroundWindow(IntPtr hWnd);

        private Process process1 = null;
        private Process process2 = null;
        private CancellationTokenSource cancellationTokenSource;

        private bool isRunning = false;

        public Form1()
        {
            InitializeComponent();
        }

        // プロセスの一覧を取得
        private void btnGetApplication_Click(object sender, EventArgs e)
        {
            // メインウィンドウのタイトルが空でないプロセスの一覧を取得
            List<Process> processes = Process.GetProcesses()
                .Where(p => !string.IsNullOrEmpty(p.MainWindowTitle))
                .OrderBy(p => p.MainWindowTitle)
                .ToList();

            cbxApp1.Items.Clear();
            cbxApp2.Items.Clear();

            // リストボックスにウィンドウタイトルを表示
            foreach (Process process in processes)
            {
                cbxApp1.Items.Add(process.MainWindowTitle);
                cbxApp2.Items.Add(process.MainWindowTitle);
            }

            // 本アプリのプロセス情報を初期値として設定
            cbxApp1.SelectedIndex = cbxApp1.Items.IndexOf(this.Text);
        }

        // 選択されたアプリのアクティブウィンドウを交互に切り替える
        private void btnSwitchWindows_Click(object sender, EventArgs e)
        {
            // 実行中か待機中かの状態をトグルする
            if (isRunning)
            {
                // キャンセルリクエストを送信して、スレッドを停止する
                cancellationTokenSource?.Cancel();

                // 待機中に切り替え
                btnSwitchWindows.Text = "待機中";
                btnSwitchWindows.BackColor = System.Drawing.Color.LightGray;
                isRunning = false;
            }
            else
            {
                if (cbxApp1.SelectedItem != null && cbxApp2.SelectedItem != null)
                {
                    string selectedTitle1 = cbxApp1.SelectedItem.ToString();
                    string selectedTitle2 = cbxApp2.SelectedItem.ToString();

                    process1 = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle == selectedTitle1);
                    process2 = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle == selectedTitle2);

                    if (process1 != null && process2 != null)
                    {
                        // キャンセルトークンソースを生成
                        cancellationTokenSource = new CancellationTokenSource();
                        CancellationToken token = cancellationTokenSource.Token;

                        // 新しいスレッドでウィンドウ切り替えを開始
                        Task.Run(() => SwitchWindowsAlternately(token));

                        // 実行中に切り替え
                        btnSwitchWindows.Text = "実行中";
                        btnSwitchWindows.BackColor = System.Drawing.Color.Red;
                        isRunning = true;
                    }
                    else
                    {
                        MessageBox.Show("選択されたアプリケーションが見つかりません。");
                    }
                }
                else
                {
                    MessageBox.Show("両方のアプリケーションを選択してください。");
                }
            }
        }

        // 交互にウィンドウを切り替える
        private void SwitchWindowsAlternately(CancellationToken token)
        {
            int interval = int.Parse(tbxInterval.Text) * 1000;

            // 指定した間隔ごとに交互にウィンドウを切り替える
            while (!token.IsCancellationRequested)
            {
                // process1のウィンドウをアクティブにする
                if (process1 != null && !process1.HasExited)
                {
                    SetForegroundWindow(process1.MainWindowHandle);
                }
                Thread.Sleep(interval);

                // process2のウィンドウをアクティブにする
                if (process2 != null && !process2.HasExited)
                {
                    SetForegroundWindow(process2.MainWindowHandle);
                }
                Thread.Sleep(interval);   
            }
        }
    }
}

ソースコード(デザイン)

こちらは、フォームアプリのデザインコードです。

namespace SwitchWindows
{
    partial class Form1
    {
        /// <summary>
        /// 必要なデザイナー変数です。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージド リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows フォーム デザイナーで生成されたコード

        /// <summary>
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.btnGetApplication = new System.Windows.Forms.Button();
            this.btnSwitchWindows = new System.Windows.Forms.Button();
            this.cbxApp1 = new System.Windows.Forms.ComboBox();
            this.cbxApp2 = new System.Windows.Forms.ComboBox();
            this.tbxInterval = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // btnGetApplication
            // 
            this.btnGetApplication.Location = new System.Drawing.Point(12, 12);
            this.btnGetApplication.Name = "btnGetApplication";
            this.btnGetApplication.Size = new System.Drawing.Size(183, 19);
            this.btnGetApplication.TabIndex = 0;
            this.btnGetApplication.Text = "アプリケーション情報取得";
            this.btnGetApplication.UseVisualStyleBackColor = true;
            this.btnGetApplication.Click += new System.EventHandler(this.btnGetApplication_Click);
            // 
            // btnSwitchWindows
            // 
            this.btnSwitchWindows.Location = new System.Drawing.Point(227, 12);
            this.btnSwitchWindows.Name = "btnSwitchWindows";
            this.btnSwitchWindows.Size = new System.Drawing.Size(135, 56);
            this.btnSwitchWindows.TabIndex = 1;
            this.btnSwitchWindows.Text = "待機中";
            this.btnSwitchWindows.UseVisualStyleBackColor = true;
            this.btnSwitchWindows.Click += new System.EventHandler(this.btnSwitchWindows_Click);
            // 
            // cbxApp1
            // 
            this.cbxApp1.FormattingEnabled = true;
            this.cbxApp1.Location = new System.Drawing.Point(14, 83);
            this.cbxApp1.Name = "cbxApp1";
            this.cbxApp1.Size = new System.Drawing.Size(348, 20);
            this.cbxApp1.TabIndex = 4;
            // 
            // cbxApp2
            // 
            this.cbxApp2.FormattingEnabled = true;
            this.cbxApp2.Location = new System.Drawing.Point(14, 120);
            this.cbxApp2.Name = "cbxApp2";
            this.cbxApp2.Size = new System.Drawing.Size(348, 20);
            this.cbxApp2.TabIndex = 5;
            // 
            // tbxInterval
            // 
            this.tbxInterval.Location = new System.Drawing.Point(118, 49);
            this.tbxInterval.Name = "tbxInterval";
            this.tbxInterval.Size = new System.Drawing.Size(77, 19);
            this.tbxInterval.TabIndex = 6;
            this.tbxInterval.Text = "10";
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(12, 53);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(100, 12);
            this.label1.TabIndex = 7;
            this.label1.Text = "切り替え間隔(秒):";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(378, 153);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.tbxInterval);
            this.Controls.Add(this.cbxApp2);
            this.Controls.Add(this.cbxApp1);
            this.Controls.Add(this.btnSwitchWindows);
            this.Controls.Add(this.btnGetApplication);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button btnGetApplication;
        private System.Windows.Forms.Button btnSwitchWindows;
        private System.Windows.Forms.ComboBox cbxApp1;
        private System.Windows.Forms.ComboBox cbxApp2;
        private System.Windows.Forms.TextBox tbxInterval;
        private System.Windows.Forms.Label label1;
    }
}

コメント

タイトルとURLをコピーしました