がらくた置き場

がらくただけど、心を込めて。

Windhawkのよくわからんダイアログがちらつく

メインディスプレイの右下で一瞬だけチラつくダイアログが邪魔なんだけど、なにしろ一瞬過ぎて内容が読めないのでなにをどうすりゃいいのかサッパリわからない。

なんなら、それが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初期化ダイアログの遅延を大きくして様子見……

Asrockの電源でカスタムケーブルつくりたい

近年はドレスアップパーツを付ける都合、フル尺のケーブルは要らないわけですが、 カスタムケーブルを自作するしか無いことがしばしばある。

しかも、作成にあたって情報が無いパターンが結構ツラかったり……

とても参考にさせて貰ったサイト

pc-mods.com

Asrock電源のピンアサイン、おそらくCorsair Type4のバリエーションかと思われますが、ぼくの調べ間違いの可能性もそこそこあるので要注意……

シリコーン被覆のケーブルで作成したから柔軟性最強!
流行ってくれんかねぇ、シリコーンケーブル……('A`)

Type-C端子を清掃したい!

綿棒突っ込んで清掃したいと思うが、突っ込める綿棒が売ってないんだよね……

要するに0.9mm以下の厚みであれば差し込むこと自体は出来るわけですが、 これがなかなか存在しないっていうね。

んで、入手性が大問題ながら、現状手元で使ってる消耗品についてメモ。
サンハヤトさんが分売してくれてる綿棒がいい感じだったりする。

お試しに一袋だけ頼みたい場合はサンハヤトさんのTBS-4FSがいい感じ。
TBS-4FS 工業用綿棒 TBSシリーズ サンハヤト 片綿タイプ 平型 1袋(25本) 【通販モノタロウ】
www.monotaro.com

まとめて数が欲しいならFS-010SP FS-010SP 3"フラットスワッブ 1セット(25本×4袋) HUBY 【通販モノタロウ】
www.monotaro.com

ほかにいいのあったら教えて欲しいわね。 安く済ませたいならダイソーのスマホのおそうじ棒だけど、なんかゴミが残らないか若干不安……
スマホのおそうじ棒(ツインヘッドタイプ)jp.daisonet.com

【メモ】 よく見るSASコネクタの種類

一々番号が思い出せないので、ざっくり書きだしておく。

オリオスペックさんのサイトでも見とけよって話かもだが。

www.oliospec.com

  • SAS
    • SFF-8482
    • SFF-8484
    • SFF-8639
  • miniSAS
    • SFF-8087
    • SFF-8088
  • miniSAS HD
    • SFF-8643
    • SFF-8644
  • OCuLink
    • SFF-8611
    • SFF-8612
  • SlimSAS
    • SFF-8654 4i
    • SFF-8654 8i
  • SlimSAS LP
    • SFF-TA-1002
続きを読む

【メモ】 PCIeボード周辺の部品高さは何ミリまで許容されうるのか?

M.2ヒートシンクとか、何ミリ厚以上がアウトだかって辺りで毎度毎度困ってるんでメモ。

まず、マザーからPCIeのカード下辺までがおよそ16.15mmらしい。

なので
スタンドオフの高さ+M.2の基板厚み(0.8mm)+実装された諸々

これらが16.15mmを超えるなら要注意、となる。

ASUS ProArt X870E-Creator WiFiの場合はスタンドオフおよそ7mmなので、 SFF-8654レセプタクル(5.25mm)を搭載したM.2デバイスであれば、
7+0.8+5.25=13.05mm
となりセーフ。

SFF-8087レセプタクル(8.47mm)を搭載したM.2デバイスの場合は
7+0.8+8.47=16.27mm
となってギリギリアウト!

となるわけだ。

今回はギリギリ付けられるかも? ということで今回はSFF-8087からSATAを生やすボードを買おうと思ってますが…… 無事に接続できるといいなー。

【メモ】 マルチGPU利用時にハイパフォーマンス側として設定したアプリ

近年はGPUを活用するアプリが当たり前になってきたわけですが、 複数のGPUを一つのマシンに入れてるのに、 それぞれのリソースを上手く活用してくれないパターンが結構あります。

  • ゲーム以外の処理を全部サブ側GPUに寄せてしまいたい
  • たくさんのディスプレイを繋ぎたい
  • AI用のGPUのVRAMを空けたい

こういった考えから実際にディスプレイを繋ぎ替えてみると、

  • 思ってたんと違う側に負荷が集中する
  • ちっとも負荷分散されてくれない
  • 却ってパフォーマンスが落ちる

といった現象に悩まされたりします。

最悪パターンとしては、あらゆる処理をiGPUでやろうとしてモッサリになるって奴ですね。
はい、うちのパターンです。

試行錯誤の途中ではありますが、現状、Windowsに任せっぱなしにせずに、 意図的にパフォーマンスや省電力に寄せた方がよさそうな対象を列挙しておきます。

  • 変え方の参考
  • Microsoft
    • Windows
    • MS Office
    • PowerToys
  • サードパーティー
    • 普段使いのブラウザ
    • 普段使いの動画再生アプリ
    • その他、うちで暴れてた子
  • 変更対象アプリの調べ方
続きを読む

【雑考】 全体主義を隠す建前にリベラルを使うのはダメだろ

リベラルやるならちゃんとリベラルとしての姿勢を取った方が良いと思うし、 いくら全体主義の印象が悪かろうと、全体主義を支持するのであれば、 安易にリベラルを隠れ蓑にするもんでは無いでしょう。

ぼくがかつて日本共産党を支持してたのは、そゆとこちゃんと堂々としてたからなんだよな。
リベラル側の唱えるイデオロギーに共感なり協力出来るところでは協力しつつ、共産主義という全体主義に通じる看板を隠さず掲げてた。
実際、今だって堂々としてるんだよ。

一方で、ぼく自身も完全なリベラルをやれてるかといえば、全然そんなことは無いんだけども。

ただ、不完全であることを認めてもなお、何者かの自由な選択を邪魔しにいくような真似を リベラルとして正当化するのは違うと思うんだよね……
そこはちゃんとポリシーに反することを自ら認められないと見直す機会も得られないわけで。

そもそも、「正しくなければいけない」という前提を必要とするのは全体主義的な志向なんだよね。
皆に同じ道徳を強いる以上は、ある程度の厳密さを要求されてしまうわけだから。

一方で、リベラルをやるにあたって正しさって必須では無いというか、 むしろ科学や学問に倣えば

  • 自らの正しさに疑いを持つこと
  • 自らの間違いを認めうること
  • 自らの感情(合理性と異なりうる情動)が含まれうること

といった認知を持つ方がよほど誠実であると思うのですよね。

左派の信用が傷付いているって話をするとすぐ右からの攻撃だと騒ぐ人が居るけども、 むしろ、自らのスタンスを伏せて好き勝手に他人を悪し様に罵っている姿から、 その人に信を置こうとする人って基本的に居ないわけでして。

なんなら、その矛先がいずれ自分に向くだろうと確信する向きのが多いまであるでしょうよ。
攻撃的な姿勢って敵が増えるばかりで味方を増やさないんですよね。

すぐ党派性に逃げ込んで周りから自分の行いがどう見えるか考えてはどうかと思うわけ。

この本文自体も左派に攻撃的だし受け容れがたいものだという自覚もあるんだけど、 自分らが日常的に右の人やらノンポリさんに同じ真似しておきながら、 自分だけは許されるってのも虫がいい話にも程があるわけで。

いや、これは言い訳だな。
要するに批判しながら融和的な態度を示せない悪癖についてぼく自身もまるでダメなんだな。 どうすりゃいいんだろな、実際……