[wix-users] CustomAction does not seem to be called from the msi

Phill Hogland phill.hogland at rimage.com
Thu Feb 16 06:11:58 PST 2017


So here are my thoughts.  I hope I understood your intent:


<?xml version="1.0"?>
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

<!-- Defines & Variables
====================================================================================
-->
  <?define ProductName = "WXTest"?>
<?define ProductVersion = "0.0.1"?>
<?define ProductUpgradeCode = "015AAC21-8B82-439E-8EF4-39B9D099E7DE"?>
<?define ProductID = "*" ?>
<?define PackageID = "*" ?>
<?define Manufacturer = "My Company" ?>

<Product Id="$(var.ProductID)" Name="$(var.ProductName)" Language="1033"
    Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)"
    UpgradeCode="$(var.ProductUpgradeCode)" >
    <Package Id="$(var.PackageID)" InstallerVersion="400" Compressed="yes"
    InstallScope="perMachine"  Description="$(var.ProductName)"
    Comments="Windows Installer Package" Platform="x64"/>

    <!-- MediaTemplate is prefered and simpler than using Media -->
    <MediaTemplate EmbedCab="yes" CabinetTemplate="ic{0}.cab" />
    <Icon Id="ProductIcon" SourceFile=".\res\WXTest.ico"/>
    <Property Id="ARPPRODUCTICON" Value="ProductIcon"/>
    <Property Id="ARPNOMODIFY" Value="1"/>
    <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />

    <!-- MajorUpgrade is simpler than using Upgrade unless you need more detailed authoring. -->
    <MajorUpgrade DowngradeErrorMessage="A newer version of this software is already installed." Schedule="afterInstallInitialize" />

    <!-- It seems likely that you could eliminate this CA and use Standard Actions with SetProperty, but it is not clear what you are doing.
         I would always try to eliminate a CA.  This is where driving the MSI with a Bundle is really powerful and simple.-->
    <Binary Id="CAICRoot" SourceFile="..\CustomActions\CustomActions\bin\Release\CustomActions.dll" />
    <CustomAction Id="IronCADRootDirectory" BinaryKey="CAICRoot" DllEntry="GetICRootDir" Execute="immediate" HideTarget="no" Return="check"/>

    <InstallExecuteSequence>
        <Custom Action="IronCADRootDirectory" Before="LaunchConditions"/>
    <RemoveExistingProducts Before="InstallInitialize"></RemoveExistingProducts>
    </InstallExecuteSequence>

    <Feature Id="DefaultFeature" Level="1">
        <ComponentRef Id="FileBin1"/>
    </Feature>
</Product>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir" />
  </Fragment>

  <Fragment>
    <DirectoryRef Id="TARGETDIR">
      <Directory Id="ProgramFilesFolder" />
    </DirectoryRef>
  </Fragment>

  <Fragment>
    <DirectoryRef Id="ProgramFiles64Folder">
      <!-- Use a PUBLIC Property (Directory/@Id) so that you can change the path using SetProperty,
      but initially define the Directory relative to one of the predefined MSI root directory Ids, in this case ProgramFiles64Folder
      since your original Component authoring seems to assume a 64 bit file.-->
      <Directory Id="ICROOTDIR" Name="ICrootFolderName" />
    </DirectoryRef>
  </Fragment>

  <Fragment>
    <DirectoryRef Id="ICROOTDIR">
      <Directory Id="WXtestDir" Name="WXtest" />
    </DirectoryRef>
  </Fragment>

  <Fragment>
    <DirectoryRef Id="WXtestDir">
      <Directory Id="binDir" Name="bin" />
    </DirectoryRef>
  </Fragment>

  <Fragment>
    <!-- Generally I find it better to let the wix tools assign the Id and Guid, unless you have a specific reason to manage those details.-->
    <Component Id="FileBin1" Directory="binDir">
        <!-- I would not set File/@Checksum unless you have a specific reason.
        since the file is not a versioned exe, you might consider adding a RegistryValue as the Keypath and setting to the product version or something. -->
        <File Id="BinFile1" Source=".\bin\WXTestDoc.txt" KeyPath="yes" Checksum="no" />
    </Component>
  </Fragment>

</Wix>


________________________________
From: wix-users <wix-users-bounces at lists.wixtoolset.org> on behalf of Urban Olars <urban.olars at gmail.com>
Sent: Thursday, February 16, 2017 6:25:01 AM
To: WiX Toolset Users Mailing List
Subject: Re: [wix-users] CustomAction does not seem to be called from the msi

Sorry for bringing this topic up again. It seems like it should be possible
to get it working even when the execution of the custom action is inside
the <InstallExecuteSequence> element so that is what I have spent a lot of
time on now to accomplish. After studying the log file it seems like it
doesn't matter how early I schedule the execution of the custom action to
happen, since the definition of the directory structure inside the
<Directory Id="TARGETDIR" Name="SourceDir"> element has already happened by
that time. I haven't been able to figure out why it is like that. I tried
the suggestion from Tom Brezinski too but it did not solve the problem. It
could be that I did something wrong of course, I don't know.
Instead I have tried to create a workaround, and eventually I got it
working. I don't feel fully comfortable doing it like this though even if
it works, so that is why I want to post it to this email group to hopefully
get some feedback. This is all code I have in my *.wxs file:

<?xml version="1.0"?>
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

<!-- Defines & Variables
====================================================================================
-->
  <?define ProductName = "WXTest"?>
<?define ProductVersion = "0.0.1"?>
<?define ProductUpgradeCode = "015AAC21-8B82-439E-8EF4-39B9D099E7DE"?>
<?define ProductID = "*" ?>
<?define PackageID = "*" ?>
<?define Manufacturer = "My Company" ?>

<Product Id="$(var.ProductID)" Name="$(var.ProductName)" Language="1033"
Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)"
UpgradeCode="$(var.ProductUpgradeCode)" >
<Package Id="$(var.PackageID)" InstallerVersion="400" Compressed="yes"
InstallScope="perMachine"  Description="$(var.ProductName)"
Comments="Windows Installer Package" Platform="x64"/>

<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
       <Icon Id="ProductIcon" SourceFile=".\res\WXTest.ico"/>
<Property Id="ARPPRODUCTICON" Value="ProductIcon"/>
<Property Id="ARPNOMODIFY" Value="1"/>
<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
<Upgrade Id="$(var.ProductUpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)" OnlyDetect="yes"
Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="0.0.0" Maximum="$(var.ProductVersion)"
Property="OLDERVERSIONBEINGUPGRADED" IncludeMinimum="yes"
IncludeMaximum="no" />
</Upgrade>
<Condition Message="A newer version of this software is already
installed.">NOT NEWERVERSIONDETECTED</Condition>

<Binary Id="CAICRoot"
SourceFile="..\CustomActions\CustomActions\bin\Release\CustomActions.dll" />
<CustomAction Id="IronCADRootDirectory" BinaryKey="CAICRoot"
DllEntry="GetICRootDir" Execute="immediate" HideTarget="no" Return="check"/>
<CustomAction Id='PropertyAssignWXDir' Property='APPLICATIONROOTDIRECTORY'
Value="[ICROOTDIR]\WXtest" />
                <Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="$(var.ProductName)"/>
                        </Directory>
                </Directory>
               <DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Directory Id="Executablesdir" Name="bin">
<Component Id="FileBin1" Guid="4511011C-5D98-4EBD-BEE4-9C3610DE9B49"
Win64="yes">
<File Id="BinFile1" Source=".\bin\WXTestDoc.txt" KeyPath="yes"
Checksum="no"/>
</Component>
</Directory>
               </DirectoryRef>

<InstallExecuteSequence>
<Custom Action="IronCADRootDirectory" Before="LaunchConditions"/>
<Custom Action="PropertyAssignWXDir" After="IronCADRootDirectory"/>
<RemoveExistingProducts Before="InstallInitialize"></RemoveExistingProducts>
</InstallExecuteSequence>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="FileBin1"/>
</Feature>
   </Product>
</Wix>

I use a custom action to assign a value to APPLICATIONROOTDIRECTORY. It
works but it doesn't look pretty. I doesn't look like any of the Wix
samples I have found on internet so I guess that there has to be a better
solution to it.

This is how I build my msi:
"C:\Program Files (x86)\WiX Toolset v3.10\bin\candle" "WXTest.wxs"
"C:\Program Files (x86)\WiX Toolset v3.10\bin\light" "WXTest.wixobj"

I don't use any UI for my installer.


Best regards
Urban Olars

2017-02-10 13:47 GMT+01:00 Tom Brezinski <tom.brezinski at viavisolutions.com>:

> Yes a DLL will be created but it will usually be called
> <projectname>.dll.  I've never seen a *.CA.dll for my C++ custom actions.
>
> If you open the MSI in Orca and look at the Binary table you should see
> your DLL listed there by the ID you gave it.
>
> Also on a side note I prefer to add my custom action DLL as a "reference"
> to the installer project.  Then your SourceFile can be set to
> $(var.CustomActions.TargetPath) where "CustomActions" is the project
> name.  Then you do not have to worry about release / debug or 32-bit vs
> 64-bit paths.
>
> For example:
> <Binary Id="NiwsActionsDLL" SourceFile="$(var.NiwsActions.TargetPath)" />
>
> For logging just run "msiexec /i <msi-file> /l*v C:\log.txt"
>
> Then look through your log file for the action name or anything you log
> using WcaLog in the C++.
>
> I still suspect you have a scope problem though.  Let me give you a
> complete example since you did not say that you tried my suggestion.  Here
> is a complete installer all contained in one WXS file:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"  xmlns:difxapp="
> http://schemas.microsoft.com/wix/DifxAppExtension">
>   <Product Id="48C49ACE-90CF-4161-9C6E-9162115A54DD"
>       Name="WiX Patch Example Product"
>       Language="1033"
>       Version="1.0.0"
>       Manufacturer="Dynamo Corporation"
>       UpgradeCode="48C49ACE-90CF-4161-9C6E-9162115A54DD">
>     <Package Description="Installs a file that will be patched."
>         Comments="This Product does not install any executables"
>         InstallerVersion="400"
>         Compressed="yes" />
>
>     <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
>     <FeatureRef Id="SampleProductFeature"/>
>   </Product>
>
>   <Fragment>
>     <Feature Id="SampleProductFeature" Title="Sample Product Feature"
> Level="1">
>       <ComponentRef Id="SampleComponent" />
>     </Feature>
>   </Fragment>
>
>   <Fragment>
>     <DirectoryRef Id="SampleProductFolder">
>       <Component Id="SampleComponent" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}"
> DiskId="1">
>         <File Id="driverDll" Source=".\$(var.Version)\TestDriver.dll" />
>         <File Id="driverCat" Source=".\$(var.Version)\TestDriver.cat" />
>         <File Id="driverInf" Source=".\$(var.Version)\TestDriver.inf" />
>
>         <difxapp:Driver PlugAndPlayPrompt="no" AddRemovePrograms="no" />
>       </Component>
>     </DirectoryRef>
>   </Fragment>
>
>   <Fragment>
>     <Directory Id="TARGETDIR" Name="SourceDir">
>       <Directory Id="ProgramFilesFolder" Name="PFiles">
>         <Directory Id="SampleProductFolder" Name="Patch Sample Directory">
>         </Directory>
>       </Directory>
>     </Directory>
>   </Fragment>
>
>   <Fragment>
>     <Binary Id="CAICRoot" SourceFile="..\CustomActions\
> CustomActions\bin\Release\CustomActions.dll"/>
>     <CustomAction Id="IronCADRootDirectory" BinaryKey="CAICRoot"
> DllEntry="GetICRootDir" Execute="firstSequence" HideTarget="no" />
>     <InstallExecuteSequence>
>       <Custom Action='IronCADRootDirectory' Before='InstallInitialize'/>
>     </InstallExecuteSequence>
>   </Fragment>
> </Wix>
>
> In this installer the CustomAction will never execute.  Why?  Because
> nothing in it is referenced in any way by the <Product>.  Notice that the
> <Component> gets referenced by the <Feature> which gets referenced by the
> <Product>.  For a <Fragment> to get included something must reference
> something in it.  The solution I take to this problem is what I mentioned
> below.  Add a <Directory> element to the fragment with the <CustomAction>
> and then in the <Fragment> that contains your <Feature> elements add a
> <DirectoryRef>.  You do not have to install anything to that directory and
> thus it will never be created, but defining it and referencing it is enough
> to tie it back to the <Product> and get included in the installer.
>
> -----Original Message-----
> From: wix-users [mailto:wix-users-bounces at lists.wixtoolset.org] On Behalf
> Of Urban Olars
> Sent: Thursday, February 09, 2017 12:15 AM
> To: WiX Toolset Users Mailing List <wix-users at lists.wixtoolset.org>
> Subject: Re: [wix-users] CustomAction does not seem to be called from the
> msi
>
> There is no CustomActions.CA.dll being created. I am using Visual Studio
> 2010 and used the WIX template for C++ Custom Action when creating my
> project. Are you sure that there should be any *.CA.dll created for C++
> custom actions? I am only guessing now but after Googling for this subject,
> it seems like C# custom action projects create a *.CA.dll but not C++
> custom action projects. Could this be the case?
>
> 2017-02-07 16:16 GMT+01:00 Justin Cox <cox.justin.a at gmail.com>:
>
> > You should be targeting the CustomsActions.CA.dll. Is it getting built
> > in your bin\release folder? If not, you need to add it to you assembly
> > and target that.
> >
> > On Tue, Feb 7, 2017, 4:15 AM Tom Brezinski <tom.brezinski at viavisolutions.
> > com>
> > wrote:
> >
> > > I have two ideas for you...
> > >
> > > First is your action might not be getting pulled in.  For WiX to
> > > include
> > a
> > > fragment it has to get tied back into the core <product> somehow.  I
> > > separate out my actions into their own WXS file / fragment which put
> > > them out of scope.
> > >
> > > In order for them to be part of the install I have to put this at
> > > the top of the fragment that has the actions:
> > >         <!-- Bogus folder so we can reference it to pull in this
> > > fragment
> > > -->
> > >         <DirectoryRef Id="INSTALLFOLDER">
> > >             <Directory Id="LegacyUpgradeActionsFolder" />
> > >         </DirectoryRef>
> > >
> > > And then inside the fragment that I specify my features I include a
> > > Ref
> > to
> > > that folder:
> > > <!-- Reference the bogus actions folder so that fragment gets pulled
> in.
> > > -->
> > >         <DirectoryRef Id="LegacyUpgradeActionsFolder"/>
> > >
> > > Second idea is change the CustomAction to Execute="immediate" and
> > schedule
> > > it After="AppSearch" to make sure it happens really early.  I am not
> > > sure when the Condition element will be evaluated but I am sure it
> > > is quite a bit before InstallInitialize.  Also I am not sure when
> > > firstSequence will schedule the action but I know that once the
> > > install elevates it is difficult to use WcaSetProperty.
> > >
> > > If you do not have Orca download it.  Opening your MSI and seeing
> > > exactly what was built, what order actions were sequenced in, etc is
> > > very
> > valuable
> > > for debugging.
> > >
> > > -----Original Message-----
> > > From: wix-users [mailto:wix-users-bounces at lists.wixtoolset.org] On
> > Behalf
> > > Of Urban Olars
> > > Sent: Tuesday, February 07, 2017 2:13 AM
> > > To: WiX Toolset Users Mailing List <wix-users at lists.wixtoolset.org>
> > > Subject: [wix-users] CustomAction does not seem to be called from
> > > the msi
> > >
> > > Hi,
> > >
> > > I am trying to learn how to write custom actions in C++ and how to
> > > use them in my msi installation project. Unfortunately with no luck
> > > so far. I have looked at numerous examples I have found on internet
> > > but still have not found out what I am doing wrong. I kindly ask for
> > > input from someone
> > on
> > > this mailing list. Thank you in advance.
> > >
> > >
> > > This is part of the code in my *.wxs file:
> > > <Binary Id="CAICRoot"
> > > SourceFile="..\CustomActions\CustomActions\bin\Release\
> > CustomActions.dll"
> > > /> <CustomAction Id="IronCADRootDirectory" BinaryKey="CAICRoot"
> > > DllEntry="GetICRootDir" Execute="firstSequence" HideTarget="no" />
> > >
> > > <InstallExecuteSequence>
> > > <Custom Action='IronCADRootDirectory' Before='InstallInitialize'/>
> > > <RemoveExistingProducts Before="InstallInitialize"></
> > RemoveExistingProducts>
> > > </InstallExecuteSequence>
> > >
> > > <Condition Message="IronCAD root directory not found. Installation
> > > aborting"> <![CDATA[ICROOTDIR]]> </Condition> ...
> > > ...
> > >
> > >
> > > This is part of the code in my custom action dll:
> > > UINT __stdcall GetICRootDir(MSIHANDLE hInstall) { MessageBox(NULL ,
> > _T("It
> > > got called!") , _T("Title") , MB_OK); HRESULT hr = S_OK; UINT er =
> > > ERROR_SUCCESS; // Initialize WiX Custom Action hr =
> > WcaInitialize(hInstall,
> > > "GetICRootDir"); ExitOnFailure(hr, "Failed to initialize");
> > > WcaLog(LOGMSG_STANDARD, "Initialized.");
> > >
> > > if (hr == ERROR_SUCCESS)
> > > {
> > > LPWSTR lpwString = L"C:\\Program Files\\IronCAD";           // This is
> > just
> > > for testing. In reality I will look it up in the registry and cut
> > > away part of the string hr = ::WcaSetProperty(TEXT("ICROOTDIR"),
> > > lpwString); ExitOnFailure(hr, "Failed to set property"); } ...
> > > ...
> > >
> > >
> > > My msi project builds without errors but when I run the msi file, it
> > > always stops at the condition message. Obviously, no property called
> > > ICROOTDIR has been set. I added code for a message box in the custom
> > > dll
> > so
> > > I should know that the function at least gets called but this
> > > message box has never showed up so far. My assumption is therefore
> > > that I have missed something fundamental so the custom dll never even
> gets called.
> > >
> > > I have added the entrypoint in the *.def file of my custom dll project:
> > > LIBRARY "CustomActions"
> > >
> > > EXPORTS
> > >
> > > GetICRootDir
> > >
> > >
> > > I haven't learnt yet how to log what is happening but I guess I will
> > > have to unless someone of you can see right away what the problem is.
> > >
> > >
> > >
> > > Regards
> > > Urban Olars
> > >
> > > ____________________________________________________________________
> > > WiX Toolset Users Mailing List provided by FireGiant
> > > http://www.firegiant.com/
> > >
> > > ____________________________________________________________________
> > > WiX Toolset Users Mailing List provided by FireGiant
> > > http://www.firegiant.com/
> > >
> >
> > ____________________________________________________________________
> > WiX Toolset Users Mailing List provided by FireGiant
> > http://www.firegiant.com/
> >
>
>
>
> --
> /Urban Olars
>
> ____________________________________________________________________
> WiX Toolset Users Mailing List provided by FireGiant
> http://www.firegiant.com/
>
> ____________________________________________________________________
> WiX Toolset Users Mailing List provided by FireGiant
> http://www.firegiant.com/
>



--
/Urban Olars

____________________________________________________________________
WiX Toolset Users Mailing List provided by FireGiant http://www.firegiant.com/



More information about the wix-users mailing list