Problems calling function from C++ custom action dll WIX - dll

Im using wix at the moment and have developed an installer. This installer calls a C++ custom action DLL. Both the DLL and the setup are building successfully but when i go to install it the installation ends with "The Installer Wizard ended Prematurely because of an error" Anyone know a possible answer?
This is the C++ Dll function:
extern "C" UINT __stdcall StopOrcService(MSIHANDLE hInstall)
Then i continue in under it with the code for the function. I then exported it using the def file.
<CustomAction Id='StopOrcService' BinaryKey='StopOrcService' DllEntry='StopOrcService' Execute='immediate' Return='check'/>
<InstallExecuteSequence>
<Custom Action='StopOrcService' After='ProcessComponents' />
</InstallExecuteSequence>
<Binary Id='StopOrcService' SourceFile='SetupDLL.dll' />
That is my wix code.

There are dozens of possible answers and it's hard to say without seeing your C++ and your WiX code.
Things to consider:
Was the C++ dll purposefully built as a custom action? ( Does it export a Type1 stdcall MsiCustom Action? )
What's the name of that function?
Is that function name correct in your WiX code?
Have you put any logging in your function to see if it got executed?
Update: You shouldn't be using a custom action to do something that the installer can do natively. Also when creating CA's that require elevation and/or change the state of the machine, they should always be scheduled as deferred with no impersonation not immediate. You have a bunch of reading to do on installer best practices to fix your strategic problems rather than bandied your tactical problem.

I have realized that i forgot to add the following line which made my code work perfectly. Hopefully this helps others.:)
#pragma comment(linker, "/EXPORT:StopOrcService=_StopOrcService#4")

Related

How to extract MSVC rutime libraries from merged `Microsoft_VC141_CRT_x64.msm` during setup verification

Background
I have complex C++ application which is installed using msi installer (defined with wix).
My application need MSVC run time libraries so Microsoft_VC141_CRT_x64.msm is merged to my installer.
<DirectoryRef Id="APPDIR">
<Merge Id="M.visualStudioRuntime" Language="0" SourceFile="$(var.DependenciesPath)/Microsoft_VC141_CRT_x64.msm"
DiskId="1" />
</DirectoryRef>
....
<FeatureRef Id="F.SomeComponent">
....
<MergeRef Id="M.visualStudioRuntime" />
</FeatureRef>
Now during installation process some data on remote server have to be verified. For that task, I'm extracting my application dll to temporary folder, loading library and execute some function with required parameters. Depending on outcome installation setup is allowed to continue or not.
This dll depends on third party (ok not fully third party it comes from other team) C++ library which also uses MSVC run-time so static linking is not acceptable solution.
Problem
When I'm loading my application dll from temporary folder it needs those MSVC run time libraries. To do that I need exact those dlls to this temporary folder.
Problem is observed only on Windows 2012, other supported Windows versions have this run time preinstalled.
Question
What is best way to extract those MSVC runtime libraries to temporary folder?
Notes
I've inherited this installer and current implementation manually embeds those dll (as duplicates) in installer extract them based on predefined id. This is bad solution and I wish need to fix it properly.
C++: Are you running a C++ custom action that needs those runtimes? Try to statically link as explained here - then there is no need for the VCRuntime files. If you are not running C++, please let us know.
Inlined Essence: Project settings => C/C++ => Code Generation => Change the runtime library setting to multithreaded instead of multithreaded dll.
Custom Action Tips: Here is an answer on common C++ custom action problems: Interrupt installation when custom action returns error.
Secondary Answer: To extract files from a merge module, the easier approach is to add it to a project, build an MSI and then run administrative installation on the MSI - which is a glorified file extraction from the MSI: What is the purpose of administrative installation initiated using msiexec /a?
Basic Command:
msiexec.exe /A MySetup.msi

Wix write port to etc/services file

I am replacing an old installer with a new one using Wix 3.8.
The old installer inserts a line in the file %SYS32%\Drivers\Etc\Services and that seems simple. However I have not found any easy way to add new information to a text file using WiX. So I am thinking that maybe there is some other way to do this - i.e. not to use the services file, but to register the port using some other setting in Windows, for example to Write to the Registry which is simple with WiX.
Anyone know how to do this?
Otherwise, any tip on any Custom "FileWriter" for Wix? The only one I have found can only write using a template file and that is not what I want. I could of course write my own, but this feels like reinventing the wheel...
Thanks!
/Tomas
For writing to a file, you can create a dynamic-link library that includes the method which will do the things you want to be done (editing files...etc.). And then you can create a Type 1 custom action which calls a method from a dll file. Technically, a Type 1 action means authoring an unmanaged C/C++ dll (Windows Installer does not natively support .NET actions), but you can use C# Custom Action project (that comes with WiX extension) which creates a C/C++ dll from managed C# code.
aCustomAction.cs
using System;
using Microsoft.Deployment.WindowsInstaller;
namespace someLibrary
{
public class CustomActions
{
[CustomAction]
public static ActionResult MyFunction(Session session)
{
// do something
return ActionResult.Success;
}
}
}
ActionResult return type notifies the installer whether the action succeeded or failed. Please note that you can use 128 custom actions per CustomAction project (16 before Wix 3.6).
When the project is compiled, you will have a .dll and a .CA.dll file. You should reference the second one (which includes unmanaged code) in your wix project by adding the following lines to Product.wxs:
<Binary Id="aCustomActionDLL" SourceFile=".\aCustomAction.CA.dll" />
or you can directly reference from the project using $var.
Finally, you can use CustomAction element's BinaryKey and DllEntry attributes to specify method to call:
<CustomAction Id="CA_aCustomAction"
BinaryKey="aCustomActionDLL"
DllEntry="MyFunction"
Execute="deferred"
Return="Check" />
Then you schedule it to run:
<InstallUISequence>
<Custom Action="CA_aCustomAction" After="CostFinalize" />
</InstallUISequence>
The dll files will not be installed to user's computer; they perform their duty yet they stay inside the MSI package.
As an alternative you can create a full executable, then run it as a custom action (Type 2, Type 18 or Type 34). I recommend type 2 since it embeds the exe file into MSI:
<Binary Id="yourProgramEXE" SourceFile="source.exe" />
<CustomAction Id=""CA_ProgramExe"
BinaryKey= "yourProgramEXE"
Impersonate="yes"
Execute="deferred"
ExeCommand=""
Return=""check />
Impersonate tells the installer whether to impersonate the user who launched the installer or not. If it is no, you action will run as LocalUser. Immediate actions do not need impersonation and you will get an ICE68 warning if you set it to no in an immediate action. However, I strongly suggest to set them deferred so that if the installation fails. they can be rolled back.
Another alternative for very simple actions is a little embedded vbscript. Just the "CustomAction" and "InstallSequence" nodes needed, with the CustomAction looking like this:
<CustomAction Id="RestoreBackupDbFile" Script="vbscript" >
<![CDATA[
Set fso = CreateObject("Scripting.FileSystemObject")
path = fso.BuildPath(Session.Property("DATAFOLDER"), "Default")
if fso.FolderExists(path) then
dbp = fso.BuildPath(path, "TEST.db.bak")
if fso.FileExists(dbp) then
fso.CopyFile dbp, fso.BuildPath(path, "TEST.db"), true
fso.DeleteFile dbp
end if
end if
]]>
</CustomAction>
Note the use of Session.Property to get values from the executing MSI.

Can WiX run custom actions from the installed binaries just like Visual Studio Setup project does?

Since I migrated to WiX I only can run custom actions from binaries that are inserted in the Binary table
<Binary Id="SetupActions.CA.dll"
src="..\SetupActions\bin\Release\SetupActions.CA.dll" />
But Visual Studio Setup Project used to use the installed binaries as the container of custom actions.
Is there any way to use the old way in WiX?
You mean that you want to run a custom action that references a function within a dll that is installed with the package? In this case use the custom action type 17. Or in WiX:
<CustomAction Id="myCAfromInstalledDLL" FileKey="IdOfFile.dll" ExeCommand="EntryPointInDll" />
I suppose you could try the following:
Create a custom action binary that you embed in your installer.
Your custom action binary can act as a wrapper and determine the location of the installed binaries and call the appropriate methods \ custom actions. A benefit is that you can check for the existence of the files and take appropriate action if they are missing.
Something like this:
CustomAction Id='FooAction' BinaryKey='FooBinary' DllEntry='FooEntryPoint' Execute='immediate'
Return='check'/
Binary Id='FooBinary' SourceFile='foo.dll'
with the Xml angle brackets edited out for SO.
It's that binarykey that means it gets extracted from the Binary table to be called.

How do I detect my software is running in my Wix MSI?

I have an MSI which is going to install/update a driver. However I want to detect if the driver is running and shut it down before starting the install. I need to do this silently as the customers are using active directory to deploy to computers.
Using the WIX install scripts, how do I do this?
Not sure if I am missing something here but if you need to shut down a driver before installing, then a custom action would be the best approach, in my opinion.
You can write custom actions either by using VB scripts or calling into managed assemblies. I like the latter more (personal preference of C# instead of VB). The custom action in WiX source file would look like that:
Declare the binary element which represents the assembly to be called into:
<Binary Id="BIN_DriverManagement" SourceFile=".\DriverManagement.CA.dll />
Then define the custom action, calling the method of the assembly:
<CustomAction Id="CACT_ShutDownDriverAction" BinaryKey="BIN_DriverManagement" DllEntry="ShutDownDriver" />
The last step would be schedulling the custom action into the installation sequence:
<InstallExecuteSequence>
<Custom Action="CACT_ShutDownDriverAction" After="LaunchConditions" />
</InstallexecuteSequence>
Actually, I am not sure when such custom action should be scheduled, it depends on the requirements.
The custom action function, implemented in C# should be prepended with [CustomAction] attribute from the Microsoft.Deployment.WindowsInstaller namespace, so it might look like this:
[Microsoft.Deployment.WindowsInstaller.CustomAction]
public static ActionResult ShutDownDriver(Session session)
{
// Shut down the driver here.
}

Wix Bind Substring or Split

I'm trying to get a Wix installer written that does some TypeLib registration.
I'm already pulling the FileVersion off a registered file elsewhere using
!(bind.FileVersion.#InteropDll)
but I want to do the same thing for the TypeLib, which only has separate MajorVersion and MinorVersion attributes. Ideally, I'd like to do
<TypeLib ...
MajorVersion="!(bind.FileVersion.InteropDll).Split('.')[0]"
MinorVersion="!(bind.FileVersion.InteropDll).Split('.')[1]">
How can I accomplish this (or the like)? ...Or should I just not bother with all this and invoke regasm on the dll file at install time?
Thanks.
The WiX toolset doesn't support doing that today. It's an interesting feature request. I would never call regasm during an install. It's way to hard to get rollback and patching and all that working correctly by shelling out to an external executable.