Windowsの後方互換性への愛の知識マップ(知識グラフ)
この随筆は、Windowsアプリ開発につきまとう「環境ごとに壊れるかもしれない」という不安の正体を、Windowsが積み重ねてきた後方互換性という性質から説明します。32bitアプリを64bit Windows上で動かすWOW64、レジストリ登録とビット一致が必要なCOMコンポーネント、今も現場に残る.NET Frameworkアプリ、高DPIや長いパスへの対応、配布方法の選定など、心配の種の多くは古い資産を切り捨てずに動かし続けてきた結果として生まれています。筆者は、その心配をなくすのではなく、Application VerifierやWinDbg、Get-WinEventによる観察とテストという設計に変えることを提案し、そこにWindowsを愛する理由を見出しています。
Windowsの後方互換性
古いAPI・ランタイム・アプリを切り捨てず、世代を超えて動かし続けられるようにするWindowsの性質。
後方互換性
レガシー資産の互換性維持
COM(コンポーネントオブジェクトモデル)
公開インターフェース、レジストリ登録、Apartment Modelなどを土台にした、Windowsのバイナリ互換コンポーネントモデル。
bitness一致要件
ネイティブモジュール(in-procのCOMコンポーネント、P/Invokeで呼ぶDLL、ベンダー提供SDKのDLLなど)を読み込むホストプロセスと、そのモジュールのビット構成(32bit/64bit)が一致していなければならないという制約。
32bit/64bitの一致
regsvr32
DLLやOCXなどのCOMコンポーネントをレジストリへ登録・登録解除するコマンドラインツール。
WOW64
64bit Windows上で32bitアプリケーションを動作させる互換環境のこと。
32bit互換環境
.NET Framework
Windowsのコンポーネントとして扱われ、インストールされているOSのライフサイクルに沿ってサポートされるランタイム。System.Messagingの対象範囲。
.NET(Core以降)
.NET Frameworkの後継となる、クロスプラットフォーム対応の.NETランタイム(.NET 5以降)。
モダンな.NET
高DPI対応
アプリケーションがディスプレイの拡大率に応じて正しくレイアウト・描画されるようにする、DPI対応モードの明示を含む設計・実装。
高DPI
DPI対応
高解像度ディスプレイ対応
Windows Forms
デスクトップGUIアプリケーションを構築するための.NET/.NET FrameworkのUIフレームワーク。
長いパス・UNCパス・日本語パスへの対応
長いフォルダー名、UNCパス、日本語を含むパスでもファイル操作が失敗しないようにする対応。
長いパス対応
日本語パス対応
アプリの配布方法
exeの直渡し、MSI、ClickOnce、MSIX、wingetなど、アプリをインストール・更新・アンインストールさせる方法の選択。
配布方法
Application Verifier
Windowsのuser-modeアプリに対するランタイム検証ツールで、OS API利用や資源の扱い方を監視し誤用の検出や意図的な失敗の注入を行う。
WinDbg
クラッシュダンプやハングしたプロセスの状態をカーネル/ユーザーモードで解析するためのMicrosoft製デバッガー。SOS拡張によるマネージドヒープ解析や、Application Verifierの検出結果の解析にも使われる。
Get-WinEvent
イベントログをフィルターして取得するPowerShellコマンドレット。FilterHashtableでの絞り込みに対応し、NTLM監査ログなど大量のイベントの集計に使う。
現場で長く使われてきたCOMコンポーネントやExcel連携が今も動くのは、Windowsがそれらを動かし続けられるようにしているからである
in-procのCOMコンポーネントは、ホストプロセスと32bit/64bitのビット構成が一致していないと読み込めない。
COMコンポーネントは配置しただけでは動かず、regsvr32でレジストリに登録する必要がある。32bit版と64bit版のregsvr32を取り違えると登録に失敗する。
32bitアプリを64bit Windows上でも動かし続けるために、WOW64という互換レイヤーが用意されている。
32bitと64bit双方のアプリ資産を動かし続けようとする場合に限り、32bit DLLを64bitプロセスから読み込もうとして失敗するといった問題が、ビット構成の一致という前提から生じる。
現場には.NET Framework 4.xで書かれた業務アプリが今も残っており、長年業務を支えてきたそれらを動かし続ける必要がある。
.NET(Core以降、.NET 8/9など)は.NET Frameworkの後継となる新しいランタイムである。
高DPI環境やマルチモニターで画面が崩れないよう、時代の異なるUI技術にもDPI対応をさせる必要がある。
高DPI環境やマルチモニターで画面が崩れないようにしたい場合、WinForms、WPF、WinUIはそれぞれDPI対応の考え方が違うため、画面技術ごとにDPI awarenessの設定を確認する必要がある。DPI awarenessを設定しなくてもアプリ自体は起動するが、拡大縮小やぼやけといった表示崩れが生じる。
日本語パス、長いフォルダー名、UNCパスといった現場特有の環境でもファイル操作が壊れないようにする必要がある。
お客様の環境に応じて、exe直渡し・MSI・ClickOnce・MSIX・wingetなど適切な配布方法を選ぶ必要がある。
メモリやハンドルの扱いに不安があるとき、Application Verifierでランタイムの誤用を検出する方法が、古い資産を動かし続ける作業では有効である
クラッシュの原因を調べる際、WinDbgでダンプやイベントを解析する方法が、古い資産を動かし続ける作業では有効である
アプリが異常終了した原因をGet-WinEventでイベントログから追跡する方法が、古い資産を動かし続ける作業では有効である