I'm trying to embed a .dll into a wix installer that is used by other dlls during the install but will not be installed onto the customer's systems.
I've currently got
<Binary Id="AutomationUtils" SourceFile="AutomationUtils\bin\Release\AutomationUtils.dll" />
...
<CustomAction Id="Install" BinaryKey="InstallUILib" DllEntry="AutomationUtils;RunInstallerDLL" Return="check" Execute="deferred" />
but even if I take the other .dll out - WiX refuses to acknowledge the existance of the AutomationUtils .. even though it builds ok (but falls over when you try and run it).
The BinaryKey='InstallUILib' will refer to a Binary element with Id='InstallUILib'. The CustomAction/#DllEntry attribute is the name of the function entry point into the custom action .dll in the Binary element. That name needs that ::GetProcAddress() can access. I'm pretty sure a function named AutomationUtils;RunInstallerDLL is not valid.
If you're looking to do managed code custom action (where you probably need multiple .dlls) this article is okay. Otherwise, if you're creating a native custom action, I recommend creating a single .dll.
Related
I got 3 projects in Install solution:
Custom Action dll written in c#
Custom Action dll written in c++
Util dll written in c++ also (c# and c++ uses it, as
interoop)
The question is how to add Util.dll into wix installer,
When I copy/paste this dll into C:\ProgramFiles\SystemWOW64\ (the msiexec.exe directory) all works fine, but its a bad workaround which I would to avoid.
What I've tried:
1) Add as reference to the MSI project and include as:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Binary Id="CPlusPlusAction" SourceFile="$(var.CPlusPlusAction.TargetDir)$(var.CPlusPlusAction.TargetName).CA.dll"/>
<Binary Id="CSharpAction" SourceFile="$(var.CSharpAction.TargetPath)"/>
<Binary Id="Utils" SourceFile="$(var.SolutionDir)/$(var.Utils.Configuration)/Utils.dll"/>
<CustomAction Id="FunctionOne" Impersonate="no" Return="ignore" Execute="commit" BinaryKey="CPlusPlusAction" DllEntry="FunctionOne" />
<CustomAction Id="FunctionTwo" Impersonate="no" Return="ignore" Execute="commit" BinaryKey="CSharpAction" DllEntry="FunctionTwo"/>
</Fragment>
</Wix>
2) Add as reference to both projects with CopyLocal = true
I've googled a lot but still can't find the solution (Wix Doc, StackOverflow, msdn etc)
Thanks in advance
For C# managed custom actions I don't think you can add the native dll as a reference. So instead add it as content with action copy and I'm pretty sure DTF will package it up and make it available in the temp directory (current directory of the process) at custom action execution time.
For C++, I use the ISSetup.dll / ISSetupFile pattern from InstallShield or statically link the library if you can.
Thanks for answer guys, but finally I figured it out.
First of all you need to add this Util.dll to Msi binary table:
<Binary Id="Utils" SourceFile="$(var.SolutionDir)/$(var.Utils.Configuration)/Utils.dll"/>
If you are not sure use Orca for seeing it inside .msi file
Second as Christopher said for c# its enaught to RightClick -> Add Existing project -> Utill.dll, then DFS extract it during installation into C:/windows/installation/"CustomActionId" and everything works, but...
problem is with c++ side, the Wix isn't for this language, so you need to care of everything during installation, for example write code which will read the BinaryTable for installer, read data and clean all msdn it's a lot of code
so I prefer to write CLR wrapper for util,
Build Util as lib, so on c++ side its build inside CA.dll, and add as lib to wrapper, so now you can use wrapper.dll in c#
I have created an MSI file, but I want a specific C# method in the file to be used in a Custom Action that takes place prior to the ExecuteAction action in the InstallExecuteSequence table. Is there any way for me to update the Binary table in Orca so that it references a particular method in the MSI file?
For more information, my MSI file uses three separate C# class library projects. The method I want to use in the Custom Action is called InitialAction and is in a CS file called Initialise.cs in the Initialise project.
No you can't. Windows Installer doesn't natively support managed code custom actions. The Dll type referred to here:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa372048(v=vs.85).aspx
in a Win32 Dll with a standard required entrypoint signature. Managed code custom actions are typically implemented using a shim C++ Dll (Visual Studio) that calls into managed code, or C++ that calls out to an external process (WiX DTF). If you are using Visual Studio or WiX both offer support for managed code custom actions.
Having said that, what does your code do that it is required to be a direct call? Running an external executable is supported, whether managed code or not. The executable can call into the class libraries.
It's often useful to describe your ultimate goal. In effect you have decided that the solution to a problem is to edit the MSI, but there's no description of that actual problem. It appears that you want to modify an existing MSI to call code, but you don't want to rebuild it with the available tools.
First, some background. I'm working on an application that uses the WiX Toolset to create the installer. We frequently use WiX to control setting up our client's directories and place the needed DLLs where they need to go.
Now, on to the problem: I added a new DLL to my application, lets call it "NewCode.dll." NewCode.DLL has a dependency on "Dependency-1.DLL." So in order to make my program work, I need to also include Dependency-1.DLL in the installer. And this is where I get stuck. Because of the "-1" in the name of Dependency-1.DLL, Visual Studio doesn't seem to allow me to add it as a reference to the project. Without adding it as a reference, I don't believe WiX can find it, and so NewCode.DLL will fail at run time. Simply removing the hyphen is not an option because NewCode.DLL won't be able to reference Dependency-1.DLL anymore.
I have verified that if I manually place the Dependency-1.DLL into the required folder, everything will start working. So I suppose doing some "batch file post-build-action magic" to copy files around is a valid option, but its not ideal. I'd really prefer to continue to rely on the WiX Toolset.
Working answer:
The accepted solution did fix my problem. But I thought I'd add on to my post in case anyone else falls into the same trap I did. The first DLL is a direct reference, while the second is a transitive reference that the first depends on. I set the default location for the component group for where to look for the DLLs to be the TargetDir. With my old set up, this was assuming that VS would handle copying the DLL to the TargetDir for me via "Copy Local = true". Now, however, if you look at the second DLL that I'm adding, I set the source explicitly and WiX is moving the DLL for me.
Since WiX moves the DLL for me now, this gets me around the issue of VS not allowing the hyphenated DLL name as a reference.
<ComponentGroup Id="AForge" Directory="INSTALL_ROOT" Source="$(var.Pslf.TargetDir)">
<Component Guid="{FA5BEE4F-0D54-4B76-BAEF-DC8E31F6605F}">
<File Name="AForge.Video.FFMPEG.dll" KeyPath="yes"/>
</Component>
<Component Guid="{1FB3EFEA-1BF3-4416-8AE3-026F2E4EECFC}">
<File Name="avcodec-53.dll" KeyPath="yes" Source="$(var.SolutionDir)pslf\lib\AForge\avcodec-53.dll"/>
</Component>
</ComponentGroup>
You don't need a WiX reference to pre-built DLLs. Just put the direct path to it in the Source attribute:
<File Id="file_Dependency_1.DLL" Name="Dependency-1.DLL" KeyPath="yes"
DiskId="1" Source="$(var.SolutionDir)path\to\dlls\Dependency-1.DLL" />
I am having a tough time with this. There are a lot of SO articles about these settings but I'm still stuck.
My goal is to perform two steps:
Read a file that will be physically shipped with the msi. In other words, there will be three files setup.exe, test.msi, specialFile.txt
During the install, I want to create a new file in the install path. C:\Program Files\MyCompany\MyApplication\newFile.txt
The file in step 2 is created by reading something out of specialFile.txt from step 1.
My problem is navigating the murky combinations of WiX settings to enable me to read session variables and have high enough privs to write the file out. This has not been easy.
Here is what I've been doing:
<Binary Id="MyCustomAction.CA.dll" SourceFile="path\to\MyCustomAction.CA.dll" />
<CustomAction Id="MyActionsName"
Return="check"
Execute="deferred"
BinaryKey="MyCustomAction.CA.dll"
DllEntry="MyCustomAction"
Impersonate="no"/>
<CustomAction Id="CustomAction1"
Property="LookupUnattendedXML"
Value="INSTALLFOLDER=[I_Can_Get_This_From_The_Directory_Tags];SOURCEDIR=How_To_Get_This???"/>
<InstallExecuteSequence>
<Custom Action="CustomAction1" Before="MyActionsName" />
<Custom Action="MyActionsName" Before="InstallFinalize">NOT Installed AND NOT PATCH</Custom>
</InstallExecuteSequence>
impersonate="no" in order to have enough privs to write the file
Execute is "deferred" in order to have enough privs to write the file (I don't understand how this works)
The Custom tag is set to Before="InstallFinalize". I tried other settings for this. Before="InstallFinalize" seems to fire after the files have been installed.
Then in the C# code, I appear to need to access session to get what I need. I ask for session["sourceDir"] to figure out where the .msi was launched from and then search for specialFile.txt This won't work with "deferred" turned on. I also access a Directory ID called INSTALLFOLDER which is supposed to refer to the path where the application is installed. It appears to do that. session["INSTALLFOLDER"]
The last wrinkle is that when I execute the .msi directly (no bootstrapper) and with deferred changed to immediate, I am able to read the session["sourceDir"] and it's really the location of the .msi as I wanted. When I use the setup.exe bootstrapper, this same variable points to an internal System directory where it appears that the MSI was copied to. I would like to let the user have both methods of execution (with and without the setup.exe bootstrapper) and somehow be able to access these paths.
UPDATE:
This article and this article about custom properties in deferred actions have enabled me to read the install folder in the custom action (now I know where to write the file to). A remaining challenge is figuring out the location of the MSI so I can read the file without using session["SourceDir"] because the Custom Action is deferred.
This would have solved the issue:
<Binary Id="MyCustomAction.CA.dll" SourceFile="path\to\MyCustomAction.CA.dll" />
<CustomAction Id="MyActionsName"
Return="check"
Execute="deferred"
BinaryKey="MyCustomAction.CA.dll"
DllEntry="MyCustomAction"
Impersonate="no"/>
<CustomAction Id="MyActionsName.CustomActionData"
Property="MyActionsName" <!-- this is important -->
Value="INSTALLFOLDER=[I_Can_Get_This_From_The_Directory_Tags];SOURCEDIR=[SOURCEDIR];ORIGINALDATABASE=[OriginalDatabase]"/>
<InstallExecuteSequence>
<Custom Action="MyActionsName.CustomActionData" Before="MyActionsName" />
<Custom Action="MyActionsName" Before="InstallFinalize">NOT Installed AND NOT PATCH</Custom>
</InstallExecuteSequence>
In the custom action you can access the data set in MyActionsName.CustomActionData via session.CustomActionData["propertyname"]
In general you have to pass each variable/property you want to use of the 'normal' installation explicitly to the deferred custom action to show up in CustomActionData.
I've just seen that I'm very late. But maybe someone else will find this helpful.
I am new to Wix so forgive me for any terms I may use incorrectly.
I have a large solution with many projects some of which become installable services, executables and what not. In the post build events of projects that will have an installer I run the following to generate a fragment containing all the files the installer will need.
"C:\Program Files (x86)\WiX Toolset v3.8\bin\heat.exe" dir $(TargetDir) -ag -cg harvestedComponents -out $(TargetDir)$(ProjectName).wxs
I want to create one single Wix setup project that has a component reference placeholder that I can then link to the fragment. This way I can reuse the functionality of the one setup project and not need a setup project for each installable item I have. From there I would have a second build event that would link/compile the fragment and project along with passing in flags to the generic installer project that could turn on/off install features, such as adding event source, different custom actions and such.
So my question is how do I link/compile a fragment with a generic Wix project from a post build event of the executable project. I am guessing it would look something like:
Candle/Light.exe fragment.wxs generic.wxs -eventLog true -customAction1 true -msiName MyInstaller.msi
Where I would use the values of eventLog customAction1 inside the generic file to enable/disable install features.
Sorry for the confusion and hope this is possible.
If I understood it correctly you want to reference the fragment created by heat ($(TargetDir)$(ProjectName).wxs) in your generic WiX source file?
If this is the case you just have to add a ComponentGroupRef-tag below your Feature-element (instead of a ComponentRef-element you would use normally). As Id for the elemenet you have to use the name of the ComponentGroup that you used in the heat-commandline, harvestedComponents in your example. E.g.
<Feature Id="MyFeature" ...>
...
<ComponentRef Id="aNormalComponentFromTheCurrentFile" ... />
...
<ComponentGroupRef Id="harvestedComponents" />
</Feature>
Or did I miss the point?