メインディスプレイの右下で一瞬だけチラつくダイアログが邪魔なんだけど、なにしろ一瞬過ぎて内容が読めないのでなにをどうすりゃいいのかサッパリわからない。
なんなら、それがWindhawkだったのかはAIにスクリプト作らせるまでわからんかったまである……
# Windows 11: 一瞬だけ表示されるウィンドウの発生元を記録します。 # ログ: デスクトップの WindowShowLog.tsv # 停止: Ctrl+C または PowerShell ウィンドウを閉じます。自動終了: 8時間後。 $log = Join-Path ([Environment]::GetFolderPath('Desktop')) 'WindowShowLog.tsv' $minutes = 480 $source = @' using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Threading; public static class WindowShowLogger { [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate void WinEventProc(IntPtr hook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint eventThread, uint eventTime); [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X, Y; } [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left, Top, Right, Bottom; } [StructLayout(LayoutKind.Sequential)] private struct MSG { public IntPtr hwnd; public uint message; public UIntPtr wParam; public IntPtr lParam; public uint time; public POINT pt; public uint lPrivate; } [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventProc callback, uint idProcess, uint idThread, uint flags); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWinEvent(IntPtr hook); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool PeekMessage(out MSG msg, IntPtr hwnd, uint min, uint max, uint remove); [DllImport("user32.dll")] private static extern IntPtr GetAncestor(IntPtr hwnd, uint flags); [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint pid); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowText(IntPtr hwnd, StringBuilder text, int maxCount); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetClassName(IntPtr hwnd, StringBuilder name, int maxCount); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetWindowRect(IntPtr hwnd, out RECT rect); private static WinEventProc callback; private static StreamWriter writer; private static volatile bool running; private static string Clean(string value) { return (value ?? "").Replace('\t', ' ').Replace('\r', ' ').Replace('\n', ' '); } private static void OnShow(IntPtr hook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint eventThread, uint eventTime) { // OBJID_WINDOW = 0。子コントロールではなく、トップレベルの表示だけを記録します。 if (hwnd == IntPtr.Zero || idObject != 0 || idChild != 0 || GetAncestor(hwnd, 2) != hwnd) return; uint pid; GetWindowThreadProcessId(hwnd, out pid); string processName = "(取得不可)"; try { using (Process p = Process.GetProcessById((int)pid)) processName = p.ProcessName; } catch { } StringBuilder title = new StringBuilder(1024); StringBuilder className = new StringBuilder(256); GetWindowText(hwnd, title, title.Capacity); GetClassName(hwnd, className, className.Capacity); RECT rect; bool hasRect = GetWindowRect(hwnd, out rect); string position = hasRect ? rect.Left + "," + rect.Top + "," + rect.Right + "," + rect.Bottom : "(取得不可)"; writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\t" + pid + "\t" + Clean(processName) + "\t" + Clean(title.ToString()) + "\t" + Clean(className.ToString()) + "\t" + position); } private static void OnCancel(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; running = false; } public static void Run(string logPath, int minutes) { if (minutes < 1) throw new ArgumentOutOfRangeException("minutes"); callback = OnShow; // GCによるデリゲート回収を防止 using (writer = new StreamWriter(logPath, true, new UTF8Encoding(true))) { writer.AutoFlush = true; writer.WriteLine("# Monitoring started: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); writer.WriteLine("Time\tPID\tProcess\tWindow title\tWindow class\tLeft,Top,Right,Bottom"); MSG msg; PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); // メッセージキューを生成 IntPtr winEventHook = SetWinEventHook(0x8002, 0x8002, IntPtr.Zero, callback, 0, 0, 0x0002); // EVENT_OBJECT_SHOW / SKIPOWNPROCESS if (winEventHook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); running = true; Console.CancelKeyPress += OnCancel; try { DateTime deadline = DateTime.UtcNow.AddMinutes(minutes); while (running && DateTime.UtcNow < deadline) { while (PeekMessage(out msg, IntPtr.Zero, 0, 0, 1)) { } Thread.Sleep(10); } } finally { UnhookWinEvent(winEventHook); Console.CancelKeyPress -= OnCancel; writer.WriteLine("# Monitoring stopped: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); } } } } '@ Add-Type -TypeDefinition $source -Language CSharp -ErrorAction Stop Write-Host "ウィンドウ表示の記録を開始します。ログ: $log" Write-Host 'Ctrl+C で停止できます。' [WindowShowLogger]::Run($log, $minutes)
んで、正体がわかったところで、なにをどうすればいいのかよくわからんままだったりする。
とりあえず、MOD初期化ダイアログの遅延を大きくして様子見……









