たびとの旅路 ~電脳砂漠の冒険譚~

フロッピー頼りに歩き、クラウドの地平を見つめる今日まで。見つけたオアシス、迷い込んだ砂の迷宮、全てこの羊皮紙に。

古の魔法を、現代に蘇らせよ ~.NETとWin32APIで、世界の解像度を操る~

どうやら一筋縄ではいかない砂の迷宮に迷い込んだらしい。 この顛末を書き残しておくか。

仕事でディスプレイの解像度(画面の精細さ)を自在に操る魔法が必要になった。 しかし、その魔法は、Win32 API(Windows基本機能群)という、古の時代に記された難解な魔導書にしか記されていない。 私は、.NET 6(最新開発フレームワーク)という現代の魔法体系を使いながら、この失われし古の魔法を再現するという禁断の錬金術に挑むことにした。

旅の舞台は、コンソールアプリという簡素な祭壇。 しかし、マルチディスプレイという複数の世界を認識するためには、WinFormsという、かつて栄華を誇った神殿の力の一部を借りる必要がある。 これは、新旧の魔法を融合させ、世界の理(ことわり)そのものを書き換える、一人の魔法使いの冒険の記録である。

この羊皮紙のあらまし

この羊皮紙が導く者

  • ディスプレイの解像度を、プログラムという名の呪文で操りたいと願う者
  • Win32 APIという古の魔法を、現代の言葉で詠唱することに興味がある探求者
  • .NET 6という新たな大地で、失われた魔法を蘇らせる術を知りたい冒険者
  • コンソールアプリとWinFormsの融合という、禁断の錬金術に挑む開発者

砂漠の道標

  • 解像度 - ディスプレイの画面精細さ。幅×高さのピクセル数で表現する(例:3840×2160)。
  • Win32 API - Windowsの基本機能群。C言語時代から存在する古典的なプログラミングインターフェース。
  • .NET 6 - マイクロソフトの最新開発フレームワーク。クロスプラットフォーム対応の現代的な技術。
  • DllImport - C#から外部のDLL関数を呼び出すための宣言。Win32 APIを使うために必須。
  • コンソールアプリ - 文字ベースの対話型アプリケーション。GUIを持たないシンプルなプログラム。
  • WinForms - Windows Formsの略。.NETのGUIアプリケーション構築技術の一つ。
  • StructLayout - 構造体のメモリ配置を制御する属性。Win32 API連携で重要。
  • マルチディスプレイ - 複数のモニターを接続して使用する環境。作業領域を拡張できる。
  • WSL2 - Windows Subsystem for Linux 2。Windows上でLinuxを動かす仮想環境。

第一の儀式:古の魔法との契約(Win32 APIの定義)

我々が呼び覚ますのはEnumDisplayDevices(ディスプレイ列挙)とChangeDisplaySettingsEx(解像度変更)という二つの古の魔法だ。 これをC#(プログラミング言語)という現代の言葉で詠唱できるようDllImport(外部関数宣言)という契約の呪文でその存在を定義する。

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern int EnumDisplayDevices(...);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern int ChangeDisplaySettingsEx(...);

同時に魔法に必要なDISPLAY_DEVICE(ディスプレイ情報)とDEVMODE(画面設定)という二つの神器の構造もStructLayout(構造体配置指定)の呪文で正確に再現せねばならない。

第二の儀式:禁断の融合(コンソールアプリでWinFormsを呼ぶ)

通常、簡素な祭壇(コンソールアプリ)では、豪華な神殿(WinForms)の力は使えない。 しかし、プロジェクトファイル(.csprojファイル)という名の「世界の設計図」を直接書き換えることでこの禁忌を破ることができる。

プロジェクトのアンロード

世界の理を書き換えるため、一度プロジェクトの魂を眠らせる

設計図に<UseWindowsForms>true</UseWindowsForms>という一文を刻み込み、魂を再び呼び覚ます。 すると、依存関係という名の祭壇にWinFormsの力が宿っているのがわかるだろう。

WinFoms が追加された

簡素な祭壇に神殿の力が宿った瞬間

最終儀式:魔法の詠唱と、世界の書き換え(ソースコード)

全ての準備は整った。 いよいよ世界の理を書き換える究極の呪文を詠唱する。

// ...(DllImportと構造体の定義は前述の通り)...

// 神殿の力で、全てのディスプレイ(世界)を認識する
var screens = Screen.AllScreens...;

// ...(ディスプレイ情報を取得する処理)...

// 新たな世界の理(解像度)を定義する
var pDevMode = new DEVMODE();
pDevMode.dmSize = (UInt16)Marshal.SizeOf(pDevMode);
pDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
pDevMode.dmPelsWidth = 3840;   // 横
pDevMode.dmPelsHeight = 2160;  // 縦

// まずは、テストモードで、この理が受け入れられるか神託を仰ぐ
if (0 != ChangeDisplaySettingsEx(name, ref pDevMode, ..., CDS_TEST, ...))
{
    Console.Error.WriteLine("神託は下りなかった。変更は不可能だ。");
    return;
}

// 神託が下りたなら、ついに世界の理を書き換える
if (0 != ChangeDisplaySettingsEx(name, ref pDevMode, ..., CDS_UPDATEREGISTRY | CDS_FULLSCREEN, ...))
{
    Console.Error.WriteLine("世界の書き換えに失敗した!");
    return;
}

Console.WriteLine("世界の理は、正常に書き換えられた。");

羊皮紙を巻く前に

.NET 6という現代の魔法体系の中で、Win32 APIという古の魔法を詠唱する旅は、想像以上にスリリングなものだった。 コンソールアプリにWinFormsの力を宿らせるという禁断の儀式は、我々の世界の可能性を大きく広げてくれるだろう。

解像度操作の核心

  1. Win32 APIの呼び出し - DllImportによる古の魔法との契約が全ての起点となる。
  2. 構造体の正確な定義 - DISPLAY_DEVICEとDEVMODEを、StructLayoutで厳密に再現することが成功の鍵。
  3. WinFormsの活用 - マルチディスプレイ環境では、Screen.AllScreensによる認識が不可欠。
  4. テストモードの実行 - CDS_TESTフラグで事前検証することで、安全な変更が可能になる。

注意すべき点

この融合魔法は、WSL2 Ubuntuという異世界では通用しない。 古の魔法は、やはりそれが生まれた大地(Windows)でしか、真の力を発揮しないようだ。

まとめ

新旧の魔法体系を融合させることで、現代の開発環境でも失われた力を取り戻せる。 この羊皮紙が、同じようにWindowsという世界の深淵を覗き込み、その理を書き換えようと挑む未来の冒険者の助けとなることを願う。

東の空が白んできた。次のオアシスへ向けて、そろそろ荷造りを始めるとしよう。

砂漠で見つけた魔法のランプ

ラクダの独り言

ご主人が「せかいのかいぞうどをかきかえる!」とか言って、また黒い画面に呪文を打ち込んでいる。 俺に言わせりゃ、世界の解像度なんて、自分の目が良けりゃそれで済む話だろうに。 まったく、人間ってのは、道具に頼ってばかりだな。 おっと、また腹が鳴っちまった。