Windows 10 2004 (2020/06 にリリースされたバージョン) から MSIX パッケージにサービスを含めることが可能になりました。
ドキュメント上は、MSIX Packaging Tool を使う方法が書かれているので、ここでは手動構成をしてみようと思います。
Windows アプリケーション パッケージ プロジェクトを作成
まずは MSIX を作ってくれる Windows アプリケーション パッケージ プロジェクトを Visual Studio から使います。
作るときに対象の Windows 10 のバージョンを聞かれるので Min version と Target version を 2004 にしておきます。
サービスを作ろう
サービスの作り方は正直詳しくないのですが、Windows サービスを作るプロジェクトのひな型を見ながらコンソールアプリとして作っていきます。(今回は必要最低限のサービスを目指したので、コンソールアプリからはじめましたが普通に Windows サービスのプロジェクトテンプレートから作ってもいいです。)
コンソールアプリに System.ServiceProcess の参照を追加します。
そして、こんな感じで必要最低限だけ定義しておきます。
using System.IO;
using System.ServiceProcess;
namespace MyService
{
class Program
{
static void Main(string[] args)
{
ServiceBase.Run(new MyService());
}
}
class MyService : ServiceBase
{
protected override void OnStart(string[] args)
{
using (var sw = new StreamWriter("c:\\temp\\myservice.log", true))
{
sw.WriteLine("OnStart");
}
base.OnStart(args);
}
protected override void OnStop()
{
using (var sw = new StreamWriter("c:\\temp\\myservice.log", true))
{
sw.WriteLine("OnStop");
}
base.OnStop();
}
}
}
プロジェクトのプロパティで出力の種類をコンソール アプリケーションから Windows アプリケーションに変更しておきます。
Windows アプリケーション パッケージ プロジェクトの設定
最初に作った Windows アプリケーション パッケージ プロジェクトのアプリケーションに先ほど作った Windows サービスのプロジェクトを追加します。
ついでに適当な画面をもったプロジェクト(例えばWPFアプリ)もソリューションに追加して、これも Windows アプリケーション パッケージ プロジェクトに追加します。
こんな感じですね。
そして、Package.appxmanifest をコードで開いてサービスの定義のタグを追加します。
まずは xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
を Package タグに追加して IgnorableNamespaces に desktop6 を追加します。
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
IgnorableNamespaces="uap rescap desktop6">
そして、Application タグの下に Extensions タグを追加して、その中にサービスの定義を書きます。注意点としては Capabilities に以下の値を追加(両方、もしくは packagedServices のみ) を設定します。
- packagedServices
- localSystemServices
サービスが動くアカウントを指定する Service タグの StartAccount で localSystem を指定している場合は packagedServices と localSystemServices の両方の定義が必要です。(Capabilities タグが 2 つ必要)
localService か networkService の場合は packagedServices だけでいいです。以下の例では localService を指定しているので、packagedServices だけを指定しています。
Capabilities の詳細については、以下のアプリ機能の宣言のドキュメントの「パッケージ サービス」の項目も参照してください。
dekstop6:Extension タグの Executable 属性でサービスの exe を指定して EntryPoint に Windows.FullTrustApplication を設定します。そしてその下の desktop6:Service タグで表示名や起動のタイプ(auto, manual, diabled のどれか)と StartAccount (localSystem, localService, networkService のどれか)を設定します。
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Service.Package"
Description="Service.Package"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<desktop6:Extension Category="windows.service" Executable="MyService\MyService.exe" EntryPoint="Windows.FullTrustApplication">
<desktop6:Service Name="MyService"
StartupType="auto"
StartAccount="localService">
</desktop6:Service>
</desktop6:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="packagedServices" />
</Capabilities>
デバッグについて
サービスを含む Windows アプリケーション パッケージ プロジェクトは管理者権限で VIsual Studio を起動していないとデバッグ実行が出来ません。注意してください。
管理者権限無しでデバッグ実行をするとパッケージのインストールが出来ずにエラーになります。
サービスのデバッグは、F5 実行だけでは出来なかったので一度デバッグ実行するとサービスが裏で動くようになるので、明示的に自分でサービスの exe のプロセスにアタッチすることでブレークポイントが効くようになりました。
パッケージ化とインストール
パッケージ化は普通の MSIX と同じなので割愛しますが、インストールには管理者権限が必要になります。MSIX のパッケージをダブルクリックすると以下のように機能に「サービスをコンピューターにインストールします」が表示されます。インストールボタンに UAC のマークが出ている点も普通とは違うポイントですね。
まとめ
ということで、今回は Visual Studio でサービスを MSIX に含める方法について書いてみました。MSIX は結構色々機能強化されてるので見ていて楽しいですね。
ソースコードは以下の GitHub リポジトリに置いておきました。
Discussion