LoginSignup
2
0

More than 1 year has passed since last update.

MSIXでパッケージ化する場合はレジストリアクセスに気を付ける

Last updated at Posted at 2021-06-05

はじめに

ClickOnceに変わる新しいアプリケーション配布の仕組みとして、MSIXがあります。
既存の.NET Frameworkで作成したアプリケーションでも、Windows アプリケーション パッケージ プロジェクトをソリューションに追加するだけで、容易にMSIXでパッケージ化することができます。
(具体的なやり方はDocsを参照)
https://docs.microsoft.com/ja-jp/windows/msix/desktop/desktop-to-uwp-packaging-dot-net

今回は、MSIXでパッケージングした結果、レジストリアクセスにハマってしまった事例について紹介します。

MSIXでパッケージ化したらレジストリが他のアプリと共有できなくなった

既存のアプリでレジストリに書き込みを行ない、他のアプリで同じキーを読み取るケースを想定して下さい。

例えば、以下の2つのアプリがあるとします。

アプリA・・・今回MSIXでパッケージ化したアプリ
アプリB・・・その他のアプリ

以下の流れで同じレジストリキーの値に対して読み書きを行ないます。

  1. レジストリキーHKCU\SOFTWARE\HOGEVAL値に「0」が設定されているとする
  2. アプリAでVAL値を読み込む
  3. アプリBでVAL値を読み込む
  4. アプリAでVAL値を「1」に書き替える
  5. アプリAでVAL値を読み込む
  6. アプリBでVAL値を読み込む

単体のEXEとして動作させた場合、
 2.・・・「0」
 3.・・・「0」
 5.・・・「1」
 6.・・・「1」
という結果になります。当然の結果です。

ところが、この アプリA をMSIXでパッケージングして配布・動作させると、
 2.・・・「0」
 3.・・・「0」
 5.・・・「1」
 6.・・・ 「0」
という結果になります。
4.でアプリAが書き換えた「1」の値が、アプリBから読み取れていません。

MSIXでパッケージ化されたアプリからのレジストリ アクセスは仮想化される

MSに問い合わせた結果、

MSIXでパッケージ化されたアプリからのレジストリ アクセスは仮想化されており、システムや他のアプリケーションから分離された【ユーザーごと・アプリごとのプライベートな場所】にリダイレクトされる。
そのため、パッケージ化されたアプリケーションから直接他のアプリケーションで読み書きされるレジストリに書き込むことはできない。

ということでした。以下に詳細な説明があります。
https://docs.microsoft.com/ja-jp/windows/msix/desktop/desktop-to-uwp-behind-the-scenes#registry

即ち、MSIXでパッケージ化したアプリからHKLM\SoftwareHKCU以下への書き込みを行なうと、インストール後初回の書き込み時に【ユーザーごと・アプリごとのプライベートな場所】にコピーされ、それ以降はその場所に対する読み書きとなる、という事です。

上記の例で言うと、

4.アプリAで上記のレジストリキーの値を「1」に書き替える

の時点で、書き込みを行なったレジストリキーの値がアプリA専用のプライベートな場所にコピーされ、そちらに対する書き込み・読み込みとなっていたため、他のアプリBから読み取った値と異なってしまった、という事です。
(MSの回答では、HKCU全体ではなく、書き込みを行なった「値」単位でコピーされるとのこと)

なお、値の読み込みに関しては、システムレジストリの値と、【ユーザーごと・アプリごとのプライベートな場所】の値がマージされて読み取られるそうです。

回避策

.NETのコードでレジストリの書き込みを行なうと上記の現象になりますが、reg.exeを起動して別プロセスから値を書き込むと、システムレジストリに対する書き込みとなる事がわかりました。

元々、C#のRegistryKey.SetValueメソッドで書き込みを行なっていましたが、以下のようにプロセスを起動する事で、【ユーザーごと・アプリごとのプライベートな場所】が作られることなく、レジストリへの書き込みが行なえました。

var argument = @"ADD ""HKEY_CURRENT_USER\SOFTWARE\HOGE"" /v ""VAL"" /t REG_DWORD /d ""1"" /f";
Process.Start("reg.exe", argument);

なお、読み込みに関しては、書き込みを全てreg.exeで行なう前提であれば、RegistryKey.GetValueメソッドで行なっても問題ありません。
(【ユーザーごと・アプリごとのプライベートな場所】ができていない、という前提)

注意点

既にMSIXで配布し、レジストリへの書き込みを行なってしまい、【ユーザーごと・アプリごとのプライベートな場所】が作成されてしまったものについては、MSIXアプリをアンインストールするしかこれを削除する方法はありません。

2
0
0

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
2
0