Page MenuHome GnuPG

MSI: Update does not seem to be able to kill gpg-agent anymore
Closed, ResolvedPublic


While I have yet to test the upgrade from 3.1.26 to the current beta (which is the important one) upgrading from one beta to the next does not kill the gpg-agent. This leaves a broken installation behind and then also does not restart the Windows explorer after upgrading. I am very unsure what changed or if we have not tested upgrades as much and this never worked. The solution for this is probably T5012 but I need to test a bit more before I switch over to working on that task. Since I think it worked without this for our last releases. But we need some solution here at least so that future updates from 3.2.0 on work better.

Event Timeline

aheinecke created this task.
aheinecke moved this task from Restricted Project Column to Restricted Project Column on the Restricted Project board.Nov 3 2023, 10:23 AM

So I tested upgrading from to the current beta and it also did not work.

I need to test to I expect it did not work there either. Which is kinda bad :/ But at least no customer has complained yet.

So some research led me to believe that using taskkill from MSI is not uncommon. But most stackoverflow solutions did not work for me. I have one solution that works, though but that opens a terminal window for each process we try to kill. I don't want to use wscript to avoid that, since an installer that executes visual basic is IMO even more evil then an installer that executes taskkill. Both are not really the MSI way, but while we could fix our processes without a WindowMessage loop to die nicely this will not work for an upgrade to vsd32.

But I think we need to fix this before the next release since while our large customers repackage and have their own update workflows the entry customers I expect to be hit hard by this.

Note to self.

Something like this would work:

<Property Id="WixQuietExecCmdLine" Value='"[WindowsFolder]/System32/taskkill.exe" /F /IM kleopatra.exe'/>
<CustomAction Id="TaskKillKleo" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillAgent" Property="WixQuietExecCmdLine" Value="taskkill /F /IM gpg-agent.exe"/>
<CustomAction Id="TaskKillAgent" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

    <Custom Action="TaskKillKleo" Before="InstallValidate">1</Custom>
    <Custom Action="PrepareKillAgent" After="TaskKillKleo">1</Custom>
    <Custom Action="TaskKillAgent" After="PrepareKillAgent">1</Custom>

But I think I am better of now that I use wixutil anyway for quietexec to just use CloseApplication

Ok closeapplication will not work because:

DEBUG: Error 2762:  Unable to schedule operation. The action must be scheduled between InstallInitialize and InstallFinalize.

But the close running apps dialog already comes at the end of InstallValidate it would probably work for a silent installation though or where the installer is not run by the admin user. So back to my first solution:

<!-- We need to set the property accordingly so ICE does not error out -->
<Property Id="TASKKILLFILEPATH" Value="taskkill"/>
<CustomAction Id='SetTASKKILLFILEPATH32' Property='TASKKILLFILEPATH' Value='[SystemFolder]\\taskkill.exe' Return='check' />
<CustomAction Id='SetTASKKILLFILEPATH64' Property='TASKKILLFILEPATH' Value='[System64Folder]\\taskkill.exe' Return='check' />
<Property Id="WixQuietExecCmdLine" Value='foo'/>

<!-- Although Kleopatra responds nicely to being killed by the
MSI installer we need to kill it first so it does not restart
the background processes. We also kill gpg and gpgsm in case
there are some running processes from other users on the system. -->

<!-- Okular is not included here because it handles the window message and might
ask the user to save some open work or modifications when closed through a window
message. -->

<CustomAction Id="PrepareKillKleo" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM kleopatra.exe'/>
<CustomAction Id="TaskKillKleo" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillGPG" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM gpg.exe'/>
<CustomAction Id="TaskKillGPG" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillGPGSM" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM gpgsm.exe'/>
<CustomAction Id="TaskKillGPGSM" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillAgent" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM gpg-agent.exe'/>
<CustomAction Id="TaskKillAgent" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillDirmngr" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM dirmngr.exe'/>
<CustomAction Id="TaskKillDirmngr" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<!-- Well this should have been handled by killing the agents but you never know. -->
<CustomAction Id="PrepareKillScd" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM scdaemon.exe'/>
<CustomAction Id="TaskKillScd" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

<CustomAction Id="PrepareKillKeyboxd" Property="WixQuietExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM keyboxd.exe'/>
<CustomAction Id="TaskKillKeyboxd" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="ignore"/>

    <Custom Action='SetTASKKILLFILEPATH64' After='AppSearch'>VersionNT64</Custom>
    <Custom Action='SetTASKKILLFILEPATH32' After='AppSearch'>Not VersionNT64</Custom>

    <Custom Action="PrepareKillKleo" Before="InstallValidate">1</Custom>
    <Custom Action="TaskKillKleo" After="PrepareKillKleo">1</Custom>
    <!-- Users on the system might have hanging or long running gpg / gpgsm processes -->
    <Custom Action="PrepareKillGPG" After="TaskKillKleo">1</Custom>
    <Custom Action="TaskKillGPG" After="PrepareKillGPG">1</Custom>
    <Custom Action="PrepareKillGPGSM" After="TaskKillGPG">1</Custom>
    <Custom Action="TaskKillGPGSM" After="PrepareKillGPGSM">1</Custom>
    <Custom Action="PrepareKillAgent" After="TaskKillGPGSM">1</Custom>
    <Custom Action="TaskKillAgent" After="PrepareKillAgent">1</Custom>
    <Custom Action="PrepareKillDirmngr" After="TaskKillAgent">1</Custom>
    <Custom Action="TaskKillDirmngr" After="PrepareKillDirmngr">1</Custom>
    <Custom Action="PrepareKillScd" After="TaskKillDirmngr">1</Custom>
    <Custom Action="TaskKillScd" After="PrepareKillScd">1</Custom>
    <Custom Action="PrepareKillKeyboxd" After="TaskKillScd">1</Custom>
    <Custom Action="TaskKillKeyboxd" After="PrepareKillKeyboxd">1</Custom>

This definetely kills all releveant processes, I can se it in the log and so on. But somehow then all the files from the gnupg wixlib are removed, but only a small subset installed. And the subset seems completely random. Not even related to the order of which the files are listed in the wixlib. No errors or anything in the msiexec clog.
It is always these files:

Which seem to have nothing to do with any running or not running processes.

I am a bit loosing my mind over this as this happens regardless of weather or not the processes are running. As soon as my sequence is included in the installer it will only include that "half" GnuPG.

So with verbose logging /l*v inst.log (note the v) I finally saw the issue. My killing code works just fine.


MSI (c) (F4:5C) [12:33:30:149]: Disallowing installation of component: {E211E222-E13B-4015-9103-D99E955E5CBC} since the same component with higher versioned keyfile exists

D99E955E5CBC is gpg-agent.exe

This brought me to:
Which I have bookmarked since it is a very good explanation.

Now I understand while some files are installed and others are not. dirmngr.exe does not have a manifest. gpg-agent.exe has a manifest.

I am a bit confused still.

a) Why it thinks that gpg-agent.exe from an older beta is newer then the current gpg-agent.exe
b) why it considers our upgrade to be minor even though we change the product id.

But I think I can fix this already by changing the reinstallmode property. But I want to understand a and b first.

a) So with my current test upgrading from one beta to another it actually looks in the manifest and if you look there the beta230 of gnupg:

Has a lower Fileversion then the beta235:

So it thinks "I should not update this" but why does it then remove the file? That is confusing, but at least I understand why upgrading from one beta to the next only installs this weird half version of GnuPG.

But since the PRODUCT_CODE changes between our updates why is this code even activated. Especially since we allow downgrade. I think that I will fix this by modifying the reinstallbehavior. We always when we update want all our components to be replaced.

b) Is explained by the following documentation from:

Increment the Version value in your Product element to be higher than any previous versions that you have shipped. Windows Installer only uses the first 3 parts of the version in upgrade scenarios, so make sure to increment your version such that one of the first 3 parts is higher than any previously shipped version. For example, if your version 1 uses Version value, then version 2 should have a Version value of or higher ( will not work here).
Generate a new Id value in the Product element of the new version of the .msi.

Since both versions are 3.1.90.x even though the product id changes it is not considered a major upgrade. So my beta numbering actually introduced this issue. 😂

So I have basically solved this and can commit my very nice taskkilling code which works since about sunday evening.

FWIW, the Fileversion is actually the Git revision in decimal

aheinecke changed the task status from Open to Testing.Nov 15 2023, 2:50 PM

So the actual killing is now done with c5617e9f2426549cba54cb52f9faf9325f8e2929 we are using custom actions instead of CloseApplication to have more fine grained control when the steps are run. CloseApplication would only run in the main install sequence so basically only the Deferred part, but during an interactive upgrade like what one of our Entry users would do it would not avoid the first failure to kill a running gpg-agent this already would break the RestartManager support.

a232233fc914daa013716b8b9b062ad8c688289f Fixes the part where some files might not be updated during a minor upgrade like from one beta to the next by setting a reinstallmode. While this may "waste" some installation time if we only give a customer a config upgrade (e.g. a change from to after a packaging change) it makes the upgrade for us more reliable since we then know what kind of state the installation is in.

ebo moved this task from Restricted Project Column to Restricted Project Column on the Restricted Project board.
ebo added a subscriber: ebo.

works, VS-Desktop-

ebo edited projects, added vsd32 (vsd-3.2.0); removed vsd32.