WiXv3.8を使用してWindowsサービスをインストールおよび開始するためのMSIパッケージを作成しています。次のようなコード:
<Component Id="INSTALLAPSSERVICE" Guid="991D5F82-0E77-4FE3-B1D8-4C941B84C7CD" Win64="yes">
<File Id="ApsService.exe"
Name="ApsService.exe"
Source="Resource\ApsService.exe"
KeyPath="yes"
Vital="yes"
DiskId="1"></File>
<ServiceInstall Id="ApsServiceInstaller"
Name="ApsService"
DisplayName="ApsService"
Type="ownProcess"
Start="auto"
ErrorControl="normal"
Description="A monitor service for windows application."
Account="[SERVICEACCOUNT]"
Password="[SERVICEPASSWORD]"
Vital="yes"
Interactive="no"></ServiceInstall>
<ServiceControl Id="StartService"
Start="install"
Stop="both"
Remove="uninstall"
Name="ApsService"
Wait="yes"/>
</Component>
ただし、インストールは失敗し、ログに次のエラーが記録されます。
Executing op: ServiceControl(,Name=ApsService,Action=1,Wait=1,)
StartServices: Service: ApsService
Error 1920. Service 'ApsService' (ApsService) failed to start. Verify that you have sufficient privileges to start system services.
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 3676 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 1888 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 1764 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 3504 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 2100 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 2752 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 3672 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 3876 could not be cancelled. Error: 1168
MSI (s) (F0:D0) [15:57:28:630]: I/O on thread 1400 could not be cancelled. Error: 1168
MSI (s) (F0:C0) [15:57:28:630]: Product: WinApsSetup64 -- Error 1920. Service 'ApsService' (ApsService) failed to start. Verify that you have sufficient privileges to start system services.
どうすればエラーを修正できますか?
表示されるエラーメッセージは、インストール中にサービスの開始に失敗したときにWindowsインストーラーが送信する一般的なメッセージです。ほとんどの場合、問題は、開始時にサービスに依存関係がないか、完全に構成されていないことです。根本的な問題をデバッグするには、次のことを試してください。
これがマネージコードで記述されたサービスである場合は、GACに配置されているファイルに依存することを確認してくださいnot。ファイルは、インストールプロセスの非常に遅い時間までGACにありません。 GACでファイルを使用する必要がある場合は、組み込みのServiceControl
要素を使用できず、InstallFinalize
の後に実行するカスタムアクションを作成する必要があります。 InstallFinalize
の後、カスタムアクションは昇格されないため、昇格されていないユーザーによる開始をサービスがサポートする必要があることに注意してください。繰り返しますが、GACに依存しないことをお勧めします。
サービスのデバッグを頑張ってください!
OPの例では、ServiceInstallアカウントが難読化されていますが、このエラーは、アカウントの完全修飾を忘れた場合に発生する可能性があります。
<ServiceInstall ... Account="NT AUTHORITY\LocalService" />
次のようにユーザー名(NT権限なし)のみを指定すると、インストーラーは失敗します。
<ServiceInstall ... Account="LocalService" />
[SERVICEACCOUNT]に「サービスとしてログオン」権限を追加することを忘れないでください。
「サービスとしてログオン」権限をローカルコンピューターのアカウントに追加するには
1)ローカルセキュリティポリシーを開きます。
2)コンソールツリーで、ローカルポリシーをダブルクリックし、ユーザー権利の割り当て。
3)詳細ペインで、サービスとしてログオンをダブルクリックします。
4)ユーザーまたはグループの追加をクリックし、ログを持つアカウントのリストに適切なアカウントを追加しますサービスとしてオン権利。
差出人: http://technet.Microsoft.com/en-us/library/cc739424%28v=ws.10%29.aspx 。
そのため、サービスを開始する前にGACする必要のある依存関係がサービスに含まれていたため、今日このエラーが発生しました。結局のところ、依存関係はインストーラーによって最後にGACされ、ある種のブートストラッパー/マルチパートインストーラーを構築せずにこれを回避する良い方法は実際にはありません。
ただし、次の解決策が見つかりました。アセンブリをGACにデプロイし、サービスと同じディレクトリにインストールします。このようにして、サービスはプログラムファイルディレクトリで起動時にDLLを見つけることができ、それらはGACされます(これは他の理由で要件でした)。
これを行うには、2つの個別のコンポーネントグループと「ダミー」ディレクトリを作成する必要がありました。
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="NameOfProgram" />
<Directory Id="GacDlls" Name="libs" />
</Directory>
</Directory>
次に、2つのコンポーネントグループを作成します。1つはexeとすべてのライブラリを持ち、もう1つは同じライブラリを持ちアセンブリ属性が「.net」に設定されています。
<ComponentGroup Id="ServiceLibs" Directory="GACDlls">
<Component Id="log4netGAC"
Guid="a23099ac-5880-4b6e-af3f-fa7cef113226">
<File Id="log4net.dllGAC"
Name="log4net.dll"
Source="..\ProjectDir\bin\$(var.Configuration)\log4net.dll"
KeyPath="yes"
Vital="yes"
DiskId="1"
Assembly=".net"
/>
</Component>
</ComponentGroup>
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
<Component Id="log4net"
Guid="463e05db-e248-44d7-bbde-467358b7310f">
<!-- normally we'd want to GAC this (Assembly=".net"), but that would prevent us from starting the service up during install so we'll just drop it in the program folder -->
<File Id="log4net.dll"
Name="log4net.dll"
Source="..\ProjectName\bin\$(var.Configuration)\log4net.dll"
KeyPath="yes"
Vital="yes"
DiskId="1"
/>
</Component>
... other components ...
</ComponentGroup>
そして今、それは機能します!
サービスの起動の問題をデバッグするときは、インストールディレクトリに特定のファイルが存在するかどうかを確認する単純なif()ステートメントを常に使用します。サービスが失敗した場合、(失敗を示すダイアログを閉じる前に)コマンドプロンプトを開き、「echo> thatfile」を使用して、if()で探しているファイルを作成します。 if()のオブジェクトは、Debugger.Launch()の呼び出しです。
これで、ダイアログを閉じてインストーラーを再実行できます。今回はデバッガーが起動し、何が起こるかを確認できます。私はデバッガーを起動する瞬間として静的クラスinitを使用する傾向がありますが、「OnStart()」でそれを試みることができますが、ロード/バインディングの問題がある場合は、おそらく死ぬ前にそのポイントに到達しません。一方、静的クラスのinit中に実行すると、ほとんどの場合、依存関係として対処する必要があることがわかります。