[C#] Windows11でProcess.WaitForInputIdle()が使えない

C#
  • 2022/12/21

Windows11のOSで、アプリを複数並べて表示させる要件の対応をしています。
↓こんな感じ(本来は業務で使うアプリを起動しますが、今回はメモ帳で代用しています。)

MultiMemo.png

Windows10の時にこれをC#で自動化したのですが、Windows10で動いていたプログラムがWindows11で動かなくなってしまったので、備忘録を残します。

Windows10では下記の記事を参考に画像アプリをプログラム起動させ、画像のサイズと位置を変更させていました。
外部アプリケーションを起動して、ウィンドウの位置とサイズを変更する

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MultiImagePlayer
{
    class ProgramFor
    {
        [DllImport("user32.dll")]
        private static extern int MoveWindow(IntPtr hwnd, int x, int y,
            int nWidth, int nHeight, int bRepaint);

        static void Main(string[] args)
        {
            //ディスプレイの高さ
            int h = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
            //ディスプレイの幅
            int w = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;

            // 表示する画像アプリの幅と高さ
            int width = w / 4;
            int height = h / 4;

            for (int i = 0; i < 4; i++)
            {
                Process p = new Process();
                p.StartInfo.FileName = "notepad.exe";

                p.Start();

                p.WaitForInputIdle();

                MoveWindow(p.MainWindowHandle, width * (i % 4), height * (int)(i / 4), width, height, 1);
            }
        }
    }
}

ところが、これをWindows11にアップグレードした後に実行すると、うまく動かなくなってしまいました。

本来であれば、WaitForInputIdle()を入れることによって、これを実行するプロセスがアイドル状態になるのを待ってくれるはずです。
プロセスはアイドル状態になると、メインウィンドウを作成します。
メインウィンドウの値は、Process.MainWindowHandleを使って取得することができます。
メインウィンドウは作成されていない場合はMainWindowHandleは0を返します。

参考URL
Process.MainWindowHandle プロパティ
Process.WaitForInputIdle メソッド

原因を調べるために、WaitForInputIdle()を実行直後のMainWindowHandleの値を確認してみました。

p.WaitForInputeIdle();
Console.WriteLine(p.MainWindowHandle);

するとMainWindowHandleが0を返していることがわかりました。
つまり、メインウィンドウが生成されるのを待たずにWaitForInputIdle()の実行が終了してしまっているわけです。

試しにwhile文でWaitForInputIdle()がTrueになるのを待ってみましたが、こちらも結果は変わりませんでした。

#p.WaitForInputeIdle();
while(!p.WaitForInputIdle()){}

なぜWindows11でWaitForInputIdle()が使えないのか、原因は不明です。
ですが、下記のようにタイマーを入れることで回避することができました。
これでWindows10と同じ結果が得られます。

p.WaitForInputeIdle();
Thread.Sleep(5000);

ある程度時間を置くことで、メインウィンドウが生成されるのを待つことができるようでした。

最終的に、Windows11で動くコードは下記のようになりました。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MultiImagePlayer
{
    class ProgramFor
    {
        [DllImport("user32.dll")]
        private static extern int MoveWindow(IntPtr hwnd, int x, int y,
            int nWidth, int nHeight, int bRepaint);

        static void Main(string[] args)
        {
            //ディスプレイの高さ
            int h = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
            //ディスプレイの幅
            int w = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;

            // 表示する画像アプリの幅と高さ
            int width = w / 4;
            int height = h / 4;

            for (int i = 0; i < 4; i++)
            {
                Process p = new Process();
                p.StartInfo.FileName = "notepad.exe";

                p.Start();

                p.WaitForInputIdle();
                Thread.Sleep(5000);

                MoveWindow(p.MainWindowHandle, width * (i % 4), height * (int)(i / 4), width, height, 1);
            }
        }
    }
}

同じ問題で困っている、どなたかの参考になれば幸いです。

Profile

Hotaru

メーカーで組み込み系のソフトウェアやファームウェアの開発をしています。

仕事では主にC言語、Python、C#を使っています。 ...もっと見る