WindowsFolder property as part of exe address is n

2019-06-05 21:24发布

问题:

Trying to get a wix installer to kill a process, from what I have found online it looks like this is the way to go:

<Directory Id="TARGETDIR" Name="SourceDir">
  <Directory Id="WindowsFolder" Name="WINDOWS"/>

<Property Id="QtExecCmdLine" Value='"[WindowsFolder]System32\taskkill.exe" /F /IM Foo.exe'/>
<CustomAction Id="KillTaskProcess" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="ignore"/>

The problem I have is building the project will throw the following error complaining about the windows property:

The 'QtExecCmdLine' Property contains '[WindowsFolder]' in its value which is an illegal reference to another property.  If this value is a string literal, not a property reference, please ignore this warning.  To set a property with the value of another property, use a CustomAction with Property and Value attributes. 

I have tried [#WindowsFolder] instead, it removes the error but does not solve the issue. Using the full address (C:\Windows\System32\taskkill.exe) instead for the value does work but I would like to avoid that.

回答1:

I don't think you can reference a directory in the way that you are (e.g. "[WindowsFolder]"). This type of annotation is used to reference the values of properties.

WindowsInstaller does already provide a Public property which represents the System Folder on any given system. You can use [SystemFolder] on 32 bit machines to get c:\Windows\System32 (note on 64 bit machines this will give you c:\Windows\SysWow64).
Therefore, on 64 bit machines you can use [System64Folder] which will give you c:\Windows\System32

Your code would then look like

<Property Id="QtExecCmdLine" Value='"[SystemFolder]taskkill.exe" /F /IM Foo.exe'/>

Or

<Property Id="QtExecCmdLine" Value='"[System64Folder]taskkill.exe" /F /IM Foo.exe'/>


I perform a similar operation in an installation package which supports both 32 & 64 bit machines. This complicates matters slightly.
To get around this I would try the following with your code:

<Property Id="TASKKILLFILEPATH"/>
<Property Id="QtExecCmdLine" Value='"[TASKKILLFILEPATH]" /F /IM Foo.exe'/>

Then, add a custom action to properly set the task kill file path

<CustomAction Id='SetTASKKILLFILEPATH32' Property='TASKKILLFILEPATH' Value='[SystemFolder]\taskkill.exe' Return='check' />
<CustomAction Id='SetTASKKILLFILEPATH64' Property='TASKKILLFILEPATH' Value='[System64Folder]\taskkill.exe' Return='check' />

In InstallExecuteSequence you can run the appropriate custom action based on the system type:

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

BTW VersionNT64 is yet another WindowsInstaller provided property.

This might be a bit overkill and I hope there is an easier way of doing this that someone else might share, but I know this to be a working solution. Hope this, at least, leads you in the right direction.



回答2:

Why not use a VBScript to kill the process? Here is a standard script:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = 'Notepad.exe'")
For Each objProcess in colProcessList
    objProcess.Terminate()
Next