LoginSignup
9
8

More than 1 year has passed since last update.

Windowsのアプリインストールはどのように実現しているのか?

Posted at

はじめに

Windowsでアプリケーションを使用する方法はざっくり二種類あります。

  • 実行ファイルを何処かに配置して直接起動する
  • インストーラを利用してソフトウェアをインストールする(以下 単にインストール)

Microsoft Store..? ちょっと何言ってるかわからない

このうち後者を利用すると

  • アプリケーションファイルの自動展開
  • スタートメニューへの表示
  • 専用ファイルとの関連付け
  • エクスプローラーのファイル表示、使用に関する変化
  • システムからアンインストール可能
  • アプリケーションのパーミッション管理
  • etc..

といった様々な恩恵を受けられます。素晴らしい。

いやどういう仕組みだよ

という疑問を頭に浮かばせた数年前の自分に今、答えを与えるべく電子の海ならぬレジストリの沼に片足突っ込んで調べてきた内容をまとめました。
自分のこの問題に対する一通りの疑問に加え、いくつか基本的な概念まで説明するつもりで書いているので前半などは周知の内容かもしれませんが後半の内容にはレジストリも絡んできますので、よろしければ読んでいただけると幸いです。

Windowsのアプリインストールはどのように実現しているのか?

この記事ではWindowsのアプリインストールとその恩恵がどのように実現しているのかについて説明します。
あくまでもどの場所にどのようにファイル関連付けなどのデータを格納しているかなどを説明することが主目的なので、インストーラの実際の実装などについてはあまり言及しませんし、その完全な振る舞いを網羅的に説明するものでもありません。ご了承ください。

なお特に断りが無ければ環境は Windows 10 を想定しています。といっても最近のバージョンならどれも大きくは変わらないはずですが。

インストーラとは何者なのか

インストーラは環境にアプリケーションを追加し利用可能にする(インストール)ソフトウェアです。

Windowsにおいては通常.exe.msiなどの拡張子を持ちます。.exe形式のものについては比較的自由に作成可能であり簡単に説明することができないので、この項では.msi形式を主に説明します。

.msiファイル

この拡張子が付与されたファイルは Windows インストーラと呼ばれます。
MicrosoftがWindowsへのアプリケーションインストーラとして提供している形式です。
2018年からは新たに.msixも提供されています。Microsoftは改良版ファイル拡張子に「x」つけたがる気がする1

ファイルのフォーマットについては COM 構造化ストレージ とされていますが、厳密に規定があるわけではない?2ようです。(COMについては後で触れます)
COM 構造化ストレージはデータベースファイルです。つまりWindows インストーラは実は純粋な実行可能形式のファイルではないです。EXEフォーマットじゃない的な意味で
こういった構造であるためか、中身のデータベースを分割して別ファイル(.idtファイル)として扱うみたいなこともできるそうです。...いつ使うんだろうな

そのためこのファイルは実際には Microsoft Standard Installer (msiexec.exe)が展開し、インストールを実行します。
msiexec.exeはインストール失敗時にはロールバック機能によって実行前の状態に復元したり、コマンドラインオプションによりログ出力をしたり、必要に応じてシステムの再起動を要求するといった機能をアプリケーションによらず共通で実施してくれます。

コンソールによる実行でのログ出力の例
installer.msi /l*v msi_log.txt

# msiexec.exeの明示的な呼び出し 上のコマンドはこれと同じことをしている
msiexec /i installer.msi /l*v msi_log.log

既にインストールが行われた後はアプリケーションのアンインストールやアップデートに利用できます。(メンテナンスインストールと呼びます3)

実行時の権限 TrustedInstaller

インストーラは実行時に UAC(ユーザーアカウント制御)によって管理者ユーザーに権限を要求します。
(この時に権限昇格のダイアログが出るのですがこれの表示中 Windows が Secure Desktop というモードになる4らしくスクリーンショットが使えませんでした)
この時に与えた権限によって後述するProgram Filesフォルダやレジストリなどへのアクセス権を得ます。

ところでWindowsには一部の非常に重要なシステムファイルなど、管理者ユーザーにもアクセスできないファイルが存在します。(例えばexplorer.exeは権限Administratorでも書き込みが許可されていません)
一方でUACによって許可されたインストーラの権限はTrustedInstallerになります。これはWindowsにおける最上位の権限であり、もちろん管理者権限より上です。

この権限を持ってすればどれほど重要なファイルでも好き勝手弄れます
まじ?怖すぎん?

信頼できないファイルの権限昇格は止めた方が良いですね。

.msiファイルのキャッシュ

この方法でインストールした場合、%SystemRoot%\Installerフォルダ内 (具体的にはC:\Windows\Installer,隠しフォルダ) にインストーラファイルが保存されます。これらはメンテナンスインストール用として用いられるようです。
C:Windows\Installer
一応ここのファイルを直接実行してアプリケーションをアンインストールすることも可能です、推奨はされませんが。[設定]か[コントロールパネル]からアンインストールしましょう。

このフォルダは通常そこそこ大きくなるとされています(実際に自身の環境で確認しましたが2.5GBにも及んでいました)のでクリーナーソフトやらの削除対象になったり人によってはドライブの容量の関係で手動削除したくなるかもしれませんが、前述した事情があるので消すのはよした方が良いでしょう。

ファイル操作

さてWindowsインストーラ自体の紹介はこの辺にして、ここから実際の振る舞いに触れていきます。まずはファイル操作関係です。「これくらい常識だろ」って方は飛ばしていただいても構いません。

関連ファイルの展開

アプリケーションが動作するには何であれとにかく実行ファイルや必要なリソースファイルが存在しなければいけません。
インストーラはこれらのファイルをフォルダに自動的に展開します。

64bit Windowsの場合、インストールされたファイルは%PROGRAMFILES%(C:\Program Files)や%PROGRAMFILES(x86)%(C:\Program Files (x86))といったフォルダ以下に専用のディレクトリを作成して展開されます。
基本的にはProgram Filesが利用されますが、32bit環境向けにビルドされたソフトウェアはProgram Files (x86)を利用します。
(ちなみに環境変数%PROGRAMFILES%がどちらのフォルダを指すかは環境によって異なる場合があるらしいです。)

C:\Program Files\paint.net
こちらはWindowsにインストール済みのペイントソフト Paint.net のアプリケーションフォルダです。今回の記事ではちょくちょく登場させます。
実行ファイル本体であるpaintdotnet.exeの他にDLLファイルなども展開されています。パスがC:\Program Files\paint.netであることも確認できます。
ちなみにこちらのexeファイルを直接実行してもしっかりアプリケーションは起動します。

通常これらのフォルダはアクセスに相応の権限を要求するので、インストーラの実行時も権限の昇格が必要になります。

スタートメニューへの追加

インストールしたソフトウェアはしばしばスタートメニューに表示されていることがあるかと思います。
スタートメニュー
こちらも実体はインストーラが作成したショートカットファイルです。
これは各アイコンを[右クリック]->[その他]->[ファイルの場所を開く]によってショートカットファイルの場所をエクスプローラーで参照できます。
スタートメニューフォルダ

パスはC:\ProgramData\Microsoft\Windows\Start Menu\Programs およびC:\Users\{User_Name}\AppData\Roaming\Microsoft\Windows\Start Menu\Programsでした。各ファイルへのショートカット (拡張子.lnk) がここに作成されます。前者はマシン全体対象で、後者は特定のユーザーのみに適応されるものです。最終的にはこの二つのディレクトリ内の内容を統合したものが表示されます。
ちなみに手動でここにファイルを作成してもちゃんとスタートメニューに反映されます。

.lnkファイルのフォーマット

せっかくなので少しだけWindowsのショートカットファイルについて調べてみます。
Shell Link Binary File Format というようです。
見た感じリンク先の場所、作成時刻、ファイルサイズなどの情報に加えキーボード入力の組み合わせも保持するらしい。

(うわなにこれめんどくさそう)

まあこれはブラックボックスのままだった方が幸せなやつですね。

レジストリ操作

ここからが本番です。レジストリ操作が絡んできます。ただその前に事前知識の説明を少しさせていただきます。

ちょっと長いので折り畳み ご存知なら読み飛ばしても構いません

レジストリ

Windowsの動作に必要な構成データを格納するデータベースです。
実体のファイルは%SystemRoot%\System32\Config、各ユーザー用に%SystemRoot%\Profiles\{User_Name}に保存されているようです5

拡張子 内容物
{なし} レジストリデータ
.sav バックアップデータ
.alt 非常に重要なバックアップデータ
.log 変更のトランザクションログ

ただし通常はレジストリエディタ(regedit.exe)を経由して書き換えます。(通常はそもそも手で書き換えるものではないけど)

構造

データは複数の根からなる木構造で表現されます。各根をさしてハイブ (Hive)、各ノードをキーと呼び、あるキーの下に存在するキーをサブキーと呼びます。キーには"既定"を含む値名とそれに対応したデータ(文字列や数値)がマップのような形で保存されます。
レジストリの例.jpg

ハイブの種類

ハイブは複数存在します。以下ではこれ以降の説明に登場するハイブの役割を説明します。

名前 役割
HKEY_CURRENT_USER 現在ログイン中のユーザに適応されるレジストリデータ
HEKY_LOCAL_MACHINE そのマシン全体でグローバルに適応されるレジストリデータ
HKEY_CLASSES_ROOT HKEY_LOCAL_MACHINE\SOFTWARE\ClassesHKEY_CURRENT_USER\SOFTWARE\Classesを結合した仮想的なハイブ、現在読み取り専用であり過去のバージョンとの互換性のために提供される

COM

Component Object Modelの略称でMicorosoftが提供するアプリケーションをモジュール化して別プログラムから呼び出せるようにする遺物機能です。現在はその役割では.NET Assemblyの利用が推奨されています。Windowsのクリップボードが文字列もハイパーテキストも画像もExcelのグラフでも何でもかんでも保存できるのもこいつのおかげだったりします(正確にはCOMを利用して実装されている OLE の機能)
プログラムはCOM クラスの定義データを基に.dllファイルなどに保存されたCOMオブジェクトを呼び出せます。

Windows Shell

Microsoft Windows の GUIをWindows Shellと呼びます。(Powershellとかとは関係ない)
アプリケーションが提供するウィンドウではなく、つまりWindowsが提供する機能の"表面"、デスクトップやスタートメニュー、タスクバー等のことです。
現在はexplorer.exeがこれを担当しています。あのエクスプローラーです。(だからタスクマネージャーとかでエクスプローラーを強制停止させるとデスクトップもまとめて落ちたりする)

で、ファイル関連付けなど機能はこのWindows Shellが提供するものです。例えば[プログラムから開く]などですね。そして、エクスプローラーでファイルのサムネイルを表示したりする機能(jpegのサムネが表示されたりするやつ)はアプリケーション開発者が Windows Shell 拡張(Extension) として提供した機能になります

アプリケーションの識別

では実際のレジストリの様子を見ていきます。
Windowsがアプリケーションとそのコンポーネントの管理に用いる識別子(ID)は何種類かあります。
なおこれ以降で[Class_Root]はレジストリ上のHKEY_CLASSES_ROOTハイブ、HKEY_LOCAL_MACHINE\SOFTWARE\ClassesHKEY_CURRENT_USER\SOFTWARE\Classesキーなどを指すこととします。頻繁に登場するからめんどくさいので。

名前 説明 レジストリ内の記録場所
Class ID (ClsID) Windowsに登録された COMクラスオブジェクトの一意の識別子。実体は128bitのGUID。 [Class_Root]\CLSID\{ClsID}
Programmatic ID (ProgID) ProgramのID。MicrosoftによればClass IDの別名らしい、一意であることは保証されない。Class IDよりもユーザーフレンドリーな名前(例:<Word.Document.6>)をしており、一部の場合にClass IDの代用として用いる。実際にはClass ID(≒COMオブジェクト)に紐づけられてないProgIDも多い。 [Class_Root]\{ProgID}
Application ID (AppID) 特定のアプリケーションが利用するCOMオブジェクトのグループに割り当てられる識別子。アプリケーションのセキュリティ設定などの簡略化を目的としている。実体はGUID。 [Class_Root]\AppID\{AppID}
Product Code アプリケーション自体の主要識別子。実体はGUID。.msiのインストーラがアプリケーションを識別する用途にもこれを用いる。 *1(長いため別記)
Package Code Windows Installerが持つ識別子、通常Product Codeと一致させるが更新があった場合にはこちらを変化させる。インストール時、そのPackage Codeが既に登録されていた場合インストールを省略される可能性がある。 (未調査)

*1 : HKEY_LOCLA_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstallのサブキーなど?

そして各ProgIDやAppID、ClsIDなどは各々のサブキーとして格納されることで紐づけがなされます。

つまりこんな感じ

レジストリ構造
HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   ├─Classes
   │  ├─AppID
   │  │  ├─{Application ID 1}
   │  │  ├─{Application ID 2}
   │  │  └─...
   │  ├─CLSID
   │  │  ├─{Class ID 1}
   │  │  │  ├─Appid (Application IDと関連付け)
   │  │  │  └─ProgID (Program IDと関連付け)
   │  │  ├─{Class ID 2}
   │  │  └─...
   │  ├─{Program ID 1}
   │  │  └─CLSID (Class IDと関連付け)
   │  ├─{Program ID 2}
   │  └─...
   └─Microsoft
      └─Windows
         └─CurrentVersion
            └─Uninstall
               ├─{Product Code 1}
               ├─{Product Code 2}
               └─...

これらの識別子を利用してWindowsは各種の情報を紐づけます。

各識別子と実体との関連付け

コンポーネントに名前を付けたので次はそれを実際のexeファイルやdllファイルの呼び出しと紐づけなければなりません。

Program IDと実行可能ファイルの紐づけ

Windows ShellがProgIDへ実行を要求した場合に呼び出される処理は{ProgID}キー直下のshellキーに定義されます。

レジストリ構造
HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      └─{ProgID}
         ├─CLSID (存在する場合)
         └─shell
            ├─edit
            │  └─command
            ├─open
            │  └─command
            └─print
               └─command

それぞれのcommandキーには"既定"の値に実行するコマンドが保持されます。またここに示したopenedit以外にも任意の値を指定できますが、特にopenなどの特定の値に関してはWindows Shellは自動的にローカライズされた名前で表示してくれます。例えばopenはエクスプローラーでファイルを右クリックした際のコンテキストメニューにある「開く」に対応します。
コンテキストメニュー.png

例 Paint.netの場合.jpg
上の場合はProgIDはpaint.net.1でコマンドは"C:\Program Files\paint.net\paintdotnet.exe" "%1"が対応します。なおpaint.net.1にはCOMオブジェクトが紐づけられていないのでCLSIDキーは存在しません。

コマンドには何種類か挿入できる変数が存在します。例えば%1の部分は実行時呼び出しの対象となるファイルのパスが展開されます。つまり例えばWindowsがC:\dogeza.jpgファイルをpaint.net.1に編集するように命令するとき

shell\edit\command
"C:\Program Files\paint.net\paintdotnet.exe" "C:\dogeza.jpg"

というようなコマンドに展開され Paint.net が開きます。

Class IDとCOMオブジェクトの紐づけ

COMとの紐づけにはそのCOMの定義が存在するDLLファイルが必要です。

レジストリ上でのClass IDはこのようになっています

レジストリ構造
HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      └─CLSID
         └─{Class ID}
            └─InprocServer32
InprocServer32の値
InprocServer
├─"既定" = {DLLファイルへのパス}
└─ThreadingModel(任意)

このInprocServer32(またはInprocServer)の"既定"にCOMが定義されているDLLファイルへのパスが保存されています( 誤解を恐れずに言うとCOMが定義されたDLLファイルのことをインプロセスサーバーと呼びます)

これでClass IDからも実体のDLLファイルが参照できるようになりました。

アプリケーション情報の提供

Applications キー

インストーラは[Class_Root]\Applications\{Application_Name}.exeというキーを作成します。これによりWindowsにアプリケーションについてのいくらかの(全てではない)情報を通知できます。エクスプローラーなどでファイルを開くときに出てくるアプリケーション名やアイコンはProgIDに記録したshellの内容に含まれるEXEファイル名を基にここを参照するようです。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      └─Applications
         ├─excel.exe
         ├─notepad.exe
         ├─paintdotnet.exe
         │  ├─shell
         │  └─SupportedTypes
         └─...
含まれるサブキー 説明
shell 前述したshellキーと同じ形でコマンドを指定します。アプリケーション呼び出し時に参照されます。
DefaultIcon 通常アプリケーションはその.exeファイル内に存在する最初のアイコンリソースをアイコンとして利用しますが( exeやdllは内部にアイコンなどのリソースを持つ )、このキーに.exeまたは.dllとそのリソース番号などを指定することで明示的にアイコンを指定できます
SupportedTypes 任意の拡張子をサブキーに列挙します。ここに保存された拡張子については、Windows Shellの[プログラムから開く]の候補としてサジェストされます。ちなみにこの代わりにNoOpenWithを指定すると[プログラムから開く]には表示されなくなります。

またこのキーにはFriendlyAppNameという値が存在し、ローカライズされたユーザー向けのアプリケーション名を指定できます。

このキーは主に実行用の情報を保持する場所でありアプリケーションのメタデータ的な情報(ベンダーやバージョン情報など)は別にあります(後述します)

App Path

Windows アプリケーションの実行ファイル名を実際のEXEファイルにマッピングするためにHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Pathsキー以下の{Application_Name}.exeサブキーに保存します。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Microsoft
      └─Windows
         └─CurrentVersion
            └─App Paths
               ├─excel.exe
               ├─paintdotnet.exe
               └─PowerShell.exe
含まれる値 説明
"既定" EXEファイルへの完全パス
Path EXEファイルのあるディレクトリへの完全パス

ファイル拡張子との関連付け

[既定のプログラム]

次はアプリケーションと拡張子との関連付けです。

まずファイル拡張子自体の登録です。拡張子の情報はまたも[Class_Root]キー以下の.{拡張子}といった形式のキーに保存されます。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      ├─*
      ├─.jpeg
      ├─.png
      └─.xlsx

(*内の内容は全ての拡張子に適応されます)
各拡張子キーの中身は以下のようになっています。

各拡張子の値 説明
"既定" このファイルを扱うProgID。ファイルを普通にダブルクリックなどで開こうとするとこのProgIDからプログラムを呼び出します。[既定のプログラム]を表現する
ContentType ファイルのMIMEタイプ
PerceivedType ファイルがどのようなものとして扱われるか。後述するSystemFileAssociationsで利用されます。
.pngの場合の値
.png
├─"既定" = pngfile
├─ContentType = "image/png"
└─PerceivedType = "image"

ちなみに今回このProgIDはpngfileとなっています。これはpngfileを開くためのProgIDとして実体のプログラムを抽象化するように存在するものであり、このようにファイルを開くためのProgIDを別で定義することで異なった拡張子(.jpg.jpegなど)に対しても同一の形で呼び出し可能になるなどの恩恵を受けています。

SystemFileAssociations

他にファイル関連付けに用いるキーとしてSystemFileAssociationsがあります。このキーには[既定のプログラム]とは別にファイルを開く方法を定義できます。関連付けとしての優先度は低いため呼び出されない場合もありますが、[既定のプログラム]の設定に関わらず安定しているサブの処理設定として使用できます6

SystemFileAssociationsの例
HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      └─SystemFileAssociations
         ├─.jpeg
         ├─.mp3
         ├─image
         └─text

基本的には上述した.{file_extension}キーと同一の形のキーを配置しますが、ここでは上でも示したPerceivedTypeに対応するキーを配置できます(上の例ではimagetextがそれ)。中身は同じですがこの内容は対応するPerceivedTypeが指定されている拡張子全般に適応されます。

[プログラムから開く]の実現

SupportedTypes

エクスプローラーのコンテキストメニューに存在する[プログラムから開く(Open With...)]の選択肢は前述のようにApplications\{App_Name}.exeキーのSupportedTypesという値を参照します。

Applications
 └─paintdotnet.exe
    └─SupportedTypes
       ├─.gif
       ├─.jpeg
       └─...

OpenWithProgids

また各拡張子キー側に存在するOpenWithProgidsサブキーに保存することもできます。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      └─.png
         └─OpenWithProgids
OpenWithProgidsの値
OpenWithProgids
 ├─paint.net.1
 └─pngfile

これの値として対象のProgIDが列挙されます。これによって[プログラムから開く]でサジェストされるプログラムを指定できます。

なおこのような操作の結果として同一のアプリケーションが複数サジェストされる場合、重複は取り除かれるとか。

OpenWithProgidsWindows XPでのみ利用されます7。現在存在するものは互換性維持を目的とするものです。

エクスプローラーでのサムネ表示の登録

画像のサムネイル表示のような処理についてはアプリケーションが専用の実装を提供します。このようなWindows Shellに特殊な処理を加えるものを指してShell Extension8 (シェル拡張)と呼びます。

例えばサムネイル表示を担当するシェル拡張の実体はIThumbnailProviderインタフェース(Win32 APIに存在)を実装したCOMクラスです。

Shell拡張登録例 / paint.netのサムネイル
HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Classes
      ├─CLSID
      │  └─{シェル拡張のClsID}
      └─.pdn
         └─ShellEx
            └─{E357FCCD-A995-4576-B01F-234630154E96} = {シェル拡張のClsID}

シェル拡張の実装はShellEx以下に保存されます。{E357FCCD-A995-4576-B01F-234630154E96}はサムネイルプロバイダーの識別のためにあらかじめ予約されているClassIDです(実際の実装を表すClass IDとは別)。このキーの"既定"にClass IDを指定して実際のシェル拡張の実装と紐づけます。

Windows Shellはサムネ表示の際にここを参照してこの機能を実現します。

インストーラ情報の記録

先ほどWindows インストーラを使用するとそのインストーラがWindowsに保存されると書きましたが、この時のインストーラパスやその他アプリケーションの情報はHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\{?}\Products\{Product Code}に保存されます。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Microsoft
      └─Windows
         └─CurrentVersion
            └─Installer
               └─UserData
                  └─{未調査}
                     └─Products
                        └─{Product Code}
                           ├─Features
                           ├─Patches
                           └─InstallProperties

主な情報はInstallPropertiesに保存されています。

InstallPropertiesの値 説明
DisplayName ユーザーに提示されるアプリケーション名
DisplayVersion ユーザーに提示されるアプリケーションバージョン
Publisher アプリケーションの提供元
InstallDate 最後に更新が実施された時刻
InstallLocation プログラムがインストールされたフォルダのパス
LocalPackage Windowsに保存されたインストーラのパス
UninstallString Windowsインストーラに決定されるアンインストール用のコマンド

一応御覧の通りアンインストールに使える情報もここに含まれますがアンインストール用のキーは別にあります。

アンインストール情報の記録

[設定]や[コントロールパネル]にあるアプリ一覧の話です。
設定のアプリと機能

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall直下の{Product Code}キーに保存されています。

HKEY_LOCAL_MACHINE (or HEKY_CURRENT_USER)
└─SOFTWARE
   └─Windows
      └─CurrentVersion
         └─Uninstall
            ├─{Product Code or AppName}
            ├─{Product Code or AppName}
            └─...

Product Codeでなくて直接アプリケーション名が配置されているケースもありました。

内部の値は直前に示したインストーラ情報と概ね同一です。
アンインストールに用いる情報はここを参照します。

Windows Shellへの更新通知

諸々やった後、最後にプログラムはSHChangeNotify関数を呼び出してWindows Shellにレジストリの変更を通知します。これが無いと変更の内容が反映されません。

以上でインストール終了です。

インストーラも深淵を除けばもっとたくさんのことをやってそうですが概ね自分の知りたかったことは理解できたしいい加減疲れたのでこの辺りにしておきます。お疲れ様でした。

おまけ 手動インストールをやってみる

以下の内容にはレジストリ操作が含まれます。参考にして真似される場合も自己責任でお願いします。

EDGEというソフトウェアがあります。Microsoft Edgeじゃないよ

たかぼー 氏制作のドット絵を描くことに特化したフリーのペイントエディタです。

たまに使わせていただくのですが、このソフトウェアでは作成途中のデータの保存に.edgという拡張子を持つ独自のファイルフォーマットを使用します。
そんでもってこのソフトは配布されているZIPファイルを解凍するだけで済むタイプの、つまりインストーラがないソフトウェアです。

するとどうなるか。
開けない.edgファイル
_人人人人人人人人人人人人人人人人_
> ダブルクリックで直接開けない <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

なので通常はEDGEを起動したうえでソフト側から開くことになるのですが、まあ地味にめんどくさいのです。

そこで今回は手動インストールと称しまして、この.edgファイルをエクスプローラーから直で開くことまでを目標として挑戦してみたいと思います。

ファイルの配置

C:\Program Files\Edgeフォルダを作成し、配布されているZIPファイルをそこに展開します。
ファイルの配置

スタートメニューへの登録

C:\Users\{User_Name}\AppData\Roaming\Microsoft\Windows\Start Menu\Programsにショートカットファイルを作成します。
スタートメニュー
表示されました、いい感じですね

レジストリ操作

復元ポイントの作成

レジストリを弄る前に万が一の場合に備えて復元ポイントを作成します。復元ポイントを作成しておくことで後からシステムファイルをその時点の内容まで復元できます。

[コントロールパネル]>[システム]>[復元ポイントの作成]を開いて、ダイアログ下部の[作成]ボタンを押して名前を決めたら十秒ほど待機すると復元ポイントが作成されます。
システムの復元

アプリケーション 登録

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Applicationsedge.exeキーを作成します。

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Applications
edge.exe
├─shell
│  └─open
│     └─command = ["C:\Program Files\Edge\edge.exe" "%1"]
└─SupportedTypes = [".edge",".png"] <-ついでにpngも登録してみる

ついでにHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Pathsにもキーを作成しておきます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
edge.exe = "C:\Program Files\Edge\edge.exe"

ちなみに一応ここでOS再起動をかけてみましたがまだファイルは開けませんでした。

ProgID 登録

paint.edge.1というProgIDを定義して登録します。

HKEY_LOCAL_MACHINE\SOFTWARE\Classes
Classes
└─paint.edge.1
   └─shell
      └─open
         └─command = ["C:\Program Files\Edge\edge.exe" "%1"]

拡張子 登録

HKEY_LOCAL_MACHINE\SOFTWARE\Classes
Classes
└─.edg = paint.edge.1

結果的にこうなりました。
スクショ

再起動

最後に更新を反映するために再起動をかけます。
さて...。
お..?
お...? (カチカチッ)
Great Work
素晴らしい
見事ダブルクリック一発で開くことに成功しました。

さて、さっきおまけでSupportedTypesに追加していた.pngについてはどうなったかな?
プログラムから開く
しっかりとPNGファイルにもサジェストされていますね。

最後に

つかれた

COMってとっくに死んだ技術だと思ってたんですけどバリバリ現役なんですね...
如何せん資料があまり多くなかったので間違ってる情報書いてたら申し訳ありません。

  1. .docxとか.aspxとか、多分eXtended(拡張された)とかの略だろうな

  2. Stack Overflow - Windows installer MSI format

  3. Learn.Microsoft.Com - メンテナンスのインストール

  4. Wikipedia - User Account Control

  5. Learn.Microsoft.Com - レジストリの説明

  6. Learn.Microsoft.Com - アプリケーションの登録

  7. Learn.Microsoft.Com - ファイルハンドラーを指定する

  8. Learn.Microsoft.Com - シェル拡張機能の操作

9
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8