How to use relative path from Custom Action of wix

2019-05-13 17:07发布

问题:

I am making a custom installer. Where I added Utility.CA.dll to perform my custom action. In this case I want to access local file with relative to setup.msi file path. The custom action method can use the direct path e:\utility\myfile.txt but I can not find the path '..\utility\myfile.txt'. After some experiment I got that Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) Shows C:\Users\current_username\AppData\Local\Temp\MSIF384.tmp- folder.

What can I do? need wix code example.

回答1:

First, I should mention it is very challenging to reference a file relative to the source of a .MSI because later (repair, patch, uninstall) the .MSI file will be executed out of the installer cache and the loose files (like myfile.txt) will not be available. You need to write your custom action very carefully to handle that fact.

What you are looking for is the Directory with identifier SourceDir. You can get the value of SourceDir by calling:

 string sourceDir = session["SourceDir"];

Note: I'm assuming you're using DTF where the session object is provided to your managed custom action.

Now, the complexity is that the SourceDir property is only set when the Windows Installer has done ResolveSource. On initial install, where the .MSI file is double-clicked the source will be resolved (because it is the initial install and will need files). Subsequent installs may not need the source (e.g. uninstall should not need you to put the CD back in the drive to succeed). Therefore, you'll either have to call ResolveSource action in your .MSI install sequence (which would prompt the user to provide the original .MSI file again) or write the custom action code such that it does not require SourceDir in all cases.

You can read up a little more about SourceDir here: http://robmensching.com/blog/posts/2010/1/26/stackoverflow-what-does-namesourcedir-refer-to



回答2:

If you need to get the path to the folder in which the msi file resides, you can use this snippet to retrieve it:

Path.GetDirectoryName(session["OriginalDatabase"])

The OriginalDatabase property can be used in the InstallUISequence and the InstallExecuteSequence.

To access a file relative to your msi you would use

Path.Combine(Path.GetDirectoryName(session["OriginalDatabase"]), "myfile.txt")


回答3:

This works for me; in Product.wxs:

<Binary 
    Id="WixMyCustomActions"         
    SourceFile="..\WixMyCustomActions\bin\WixMyCustomActions.CA.dll" />

<CustomAction 
    Id="MyMethod" 
    BinaryKey="WixMyCustomActions" 
    DllEntry="MyMethod" 
    Execute="immediate" 
    Return="check" />

WixMyCustomActions.CA.dll is a C# class library in the same solution as the Wix project. In the WixMyCustomActions.CA.dll project properties, Build Events, I have a post build event to copy the WixMyCustomActions.CA.dll and WixMyCustomActions.CA.pdb from bin\Debug or bin\Release to bin:

copy "$(TargetDir)*.dll" "$(ProjectDir)bin" /Y
copy "$(TargetDir)*.pdb" "$(ProjectDir)bin" /Y

By copying the dll, my Product.wxs will reference whichever configuration (Debug or Release) was built last.

Edit: to get a file relative to your CA dll, use this to find the directory of the CA assembly:

using System.IO;
using System.Reflection;

// etc

string assemblyDirectory = 
    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

You can now find files relative to this directory.



回答4:

There is a property that can be read from MSI - SourceDir.

You can refer this property in your c# code by string sourceDir = session["SourceDir"];

However, you will have to resolve the source before trying to get the source. That is your MSI does not know where it is being run from. So add the following standard action in your InstallExecuteSequence.

<ResolveSource After="CostInitialize"/>

Note that, you should put this before CostFinalize and after CostInitialize, otherwise it will give error ICE27: 'ResolveSource' Action in InstallExecuteSequence table in wrong place. Current: Selection, Correct: Costing.

Your custom action should be referred after the ResolveSource element.

<InstallExecuteSequence>
      <ResolveSource After="CostInitialize"/>
      <Custom Action="CustomActionThatNeedsRelativePath" After="CostFinalize"/>
</InstallExecuteSequence>