[wix-users] Fwd: WiX Error Handling

Todd Hoatson todd.hoatson at gmail.com
Wed Jan 16 09:37:56 PST 2019


OK, new idea:

Scrap the FatalErrorDlg…  Instead, write an error message method in C#.
This method would obtain the message to be displayed from a property.  As a
C# method, it could be called via custom action during either the
InstallUISequence or InstallExecuteSequence, but it could also be called
directly from other C# custom actions.  The only thing I'm unsure of is the
proper way to set up the custom action for calling this method...

Clearly I would need something like:

<CustomAction Id="ReportError"
  Return="check"
  Execute="immediate"
  BinaryKey="CustomActions.CA.dll"
  DllEntry="ReportErrMsg"  />

Then, I would change this:

<InstallUISequence>
    <Show Dialog="FatalErrorDlg" OnExit="error" />
    …

to this(?):

<InstallUISequence>
    <Custom Action="ReportError" OnExit="error"></Custom>
    …

Could this approach work...?  Or would I need to set it up differently?

thanks,
Todd Hoatson

On Tue, Jan 15, 2019 at 4:49 PM Rob Mensching <rob at firegiant.com> wrote:

> 7. Sorry, I should have been clearer. Properties don’t travel from server
> side to client side in all installations, not just per-user installations.
> I’ve never read Nick’s book.
>
>
>
> 9. I don’t know where Microsoft takes feedback these days. Others might
> have a better idea.
>
>
>
> 10. I don’t really know how to answer this: “It was never my desire /
> intention to learn anything at all about MSI”. That’s like saying, “It was
> never my desire to learn anything at all about the .NET Framework - I just
> wanted to learn how to make fairly-straightforward programs with C#...”
>
>
>
>
>
> PS: CustomActions are one of the hardest things to do correctly with the
> Windows Installer. Only patching is harder, IMHO.
>
>
>
> _____________________________________________________________
>
> Short replies here. Complete answers over there: http://www.firegiant.com/
>
>
>
> *From:* Todd Hoatson <todd.hoatson at gmail.com>
> *Sent:* Tuesday, January 15, 2019 1:53 PM
> *To:* Rob Mensching <rob at firegiant.com>
> *Cc:* WiX Toolset Users Mailing List <wix-users at lists.wixtoolset.org>
> *Subject:* Re: [wix-users] Fwd: WiX Error Handling
>
>
>
> Hi Rob,
>
>   in response...
>
>
>
> > 7.  Not true (based on my understanding).
>
>
>
> Could you please elaborate?  Do you feel Nick Ramirez' book is in error
> about this?  Or has something changed since then?
>
>
>
> > Seems like a totally reasonable feature request. You could go ask the
> Windows Installer team to implement server
>
> > side to client side property passing.
>
>
>
> Where might one make such a request...?  Please understand, I'm fairly new
> to installation, as this is only the 2nd installer I've worked on.  It was
> never my desire / intention to learn anything at all about MSI - I just
> wanted to learn how to make fairly-straightforward installers with WiX...
>
>
>
> thanks,
>
> Todd
>
>
>
>
>
>
>
> On Tue, Jan 15, 2019 at 12:36 AM Rob Mensching <rob at firegiant.com> wrote:
>
> 1.  Yep, client side properties can be changed on the client side.
>
> 2.  Yep, server side properties can be changed on the server side.
>
> 3.  Yep, fatal error dialog lives on the client side.
>
> 4.  Yep, fatal error dialog lives on the client side.
>
> 5.  Yep. ::MsiProcessMessage() (what session.Message calls), can pump
> messages from the server side to the client side to be displayed in a
> message box.
>
> 6.  Normally the fatal error dialog doesn’t include specifics for an error
> message (much due to the Windows Installer design)
>
> 7.  Not true (based on my understanding).
>
> 8.  The Windows Installer team decided that sending properties “back” from
> the server side to the client side was not important (but you can send
> secure properties from the client side to the server side, thank goodness).
> Seems like a totally reasonable feature request. You could go ask the
> Windows Installer team to implement server side to client side property
> passing.
>
>
>
> _____________________________________________________________
>
> Short replies here. Complete answers over there: http://www.firegiant.com/
>
>
>
> *From:* Todd Hoatson <todd.hoatson at gmail.com>
> *Sent:* Monday, January 14, 2019 8:10 PM
> *To:* Rob Mensching <rob at firegiant.com>
> *Subject:* Re: [wix-users] Fwd: WiX Error Handling
>
>
>
> >  I think you've confirmed Properties (even secure ones) don't come back
> from server.
>
>
>
> Not exactly...  and I apologize in advance for a very long response
> here...  (if you like, you can skip the details and go straight to my
> summary observations below)
>
>
>
> It seems I have confirmed that properties don't come back from the server
> *when installing PER_USER*.
>
>
>
> And even this doesn't seem to fully explain my results...
>
>
>
> I have other properties which are set in C# custom actions, and those seem
> to be picked up by the rest of the installer.
>
>
>
> Example 1 - Font installation:
>
>                 <Property Id="SBLHEB_INSTALLED" Value='False'/>
>
>                 <Property Id="APPARATUS_INSTALLED" Value='False'/>
>
>
>
>                 <CustomAction Id="SetFontValues"
>
>                                 Return="check"
>
>                                 Execute="immediate"
>
>                                 BinaryKey="CustomActions.CA.dll"
>
>                                 DllEntry="LookForInstalledFonts"  />
>
>                 ...
>
>                 <InstallExecuteSequence>
>
>                   <Custom Action="CloseApplications"
> Before="AppSearch"></Custom>
>
>                   <Custom Action="SetFontValues"
> After="AppSearch"></Custom>
>
>                   ...
>
>                 </InstallUISequence>
>
>                 ...
>
>                 <DirectoryRef Id='FontsFolder'>
>
>                   <Component Id='Font1' Guid='*' Permanent='yes'>
>
>
> <Condition>SBLHEB_INSTALLED="False"</Condition>
>
>                                 <File Id='HebrewFont'
> Source='resources\SBL_Hbrw.ttf' TrueType='yes'/>
>
>                   </Component>
>
>                   <Component Id='Font2' Guid='*' Permanent='yes'>
>
>
> <Condition>APPARATUS_INSTALLED="False"</Condition>
>
>                                 <File Id='ApparatusFont'
> Source='resources\AppSILR.ttf' TrueType='yes'/>
>
>                   </Component>
>
>                   <Component Id='Font3' Guid='*' Permanent='yes'>
>
>
> <Condition>APPARATUS_INSTALLED="False"</Condition>
>
>                                 <File Id='ApparatusBoldFont'
> Source='resources\AppSILB.TTF' TrueType='yes'/>
>
>                   </Component>
>
>                   <Component Id='Font4' Guid='*' Permanent='yes'>
>
>
> <Condition>APPARATUS_INSTALLED="False"</Condition>
>
>                                 <File Id='ApparatusItalicFont'
> Source='resources\AppSILI.TTF' TrueType='yes'/>
>
>                   </Component>
>
>                   <Component Id='Font5' Guid='*' Permanent='yes'>
>
>
> <Condition>APPARATUS_INSTALLED="False"</Condition>
>
>                                 <File Id='ApparatusItalicBoldFont'
> Source='resources\AppSILBI.TTF' TrueType='yes'/>
>
>                   </Component>
>
>                   ...
>
>                 </DirectoryRef>
>
>
>
>                 <Feature Id='Fonts' Title='MyApp 9.0 - Fonts'
> Description='Installing fonts for MyApp 9' Level='1' >
>
>                   <ComponentRef Id='Font1'/>
>
>                   <ComponentRef Id='Font2'/>
>
>                   <ComponentRef Id='Font3'/>
>
>                   <ComponentRef Id='Font4'/>
>
>                   <ComponentRef Id='Font5'/>
>
>                   ...
>
>                 </Feature>
>
>
>
> And here is the C# code for the custom action:
>
>
>
>         [CustomAction]
>
>         public static ActionResult LookForInstalledFonts(Session session)
>
>         {
>
>             session.Log("--->CustomActions.LookForInstalledFonts<---");
>
>
>
>             //Check for each font that we want to install
>
>             session["SBLHEB_INSTALLED"] = DoesFontExist(session, "SBL
> Hebrew", FontStyle.Regular).ToString();
>
>             if (session["SBLHEB_INSTALLED"].Equals("False"))
>
>                 File.Delete(@"C:\\Windows\\Fonts\\SBL_Hbrw.ttf");
>
>
>
>             session["APPARATUS_INSTALLED"] = DoesFontExist(session,
> "Apparatus SIL", FontStyle.Regular).ToString();
>
>             if (session["APPARATUS_INSTALLED"].Equals("False"))
>
>             {
>
>                 session.Log("--->RemoveApparatus");
>
>                 File.Delete(@"C:\\Windows\\Fonts\\AppSILB.TTF");
>
>                 File.Delete(@"C:\\Windows\\Fonts\\AppSILBI.TTF");
>
>                 File.Delete(@"C:\\Windows\\Fonts\\AppSILI.TTF");
>
>                 File.Delete(@"C:\\Windows\\Fonts\\AppSILR.TTF");
>
>             }
>
>
>
>                     ...
>
>
>
>             return ActionResult.Success;
>
>         }
>
>
>
> As you can see from the code above, the properties SBLHEB_INSTALLED and
> APPARATUS_INSTALLED are updated in the C# code.  The updated values are
> referenced in the WiX code.
>
>
>
> When I run the installer, I see this in the log file:
>
>
>
> ...
>
> Return Value for SBL Hebrew : Regular is True
>
> MSI (s) (3C!E4) [14:32:09:690]: PROPERTY CHANGE: Modifying
> SBLHEB_INSTALLED property. Its current value is 'False'. Its new value:
> 'True'.
>
> Return Value for Apparatus SIL : Regular is True
>
> MSI (s) (3C!E4) [14:32:09:690]: PROPERTY CHANGE: Modifying
> APPARATUS_INSTALLED property. Its current value is 'False'. Its new value:
> 'True'.
>
> ...
>
> MSI (s) (3C:08) [14:32:09:721]: Component: Font1; Installed: Absent;
>  Request: Local;   Action: Null
>
> MSI (s) (3C:08) [14:32:09:721]: Component: Font2; Installed: Absent;
>  Request: Local;   Action: Null
>
> MSI (s) (3C:08) [14:32:09:721]: Component: Font3; Installed: Absent;
>  Request: Local;   Action: Null
>
> MSI (s) (3C:08) [14:32:09:721]: Component: Font4; Installed: Absent;
>  Request: Local;   Action: Null
>
> MSI (s) (3C:08) [14:32:09:721]: Component: Font5; Installed: Absent;
>  Request: Local;   Action: Null
>
> ...
>
> Property(S): SBLHEB_INSTALLED = True
>
> Property(S): CHARIS_INSTALLED = True
>
> Property(S): APPARATUS_INSTALLED = True
>
> ...
>
> Property(C): SBLHEB_INSTALLED = False
>
> Property(C): CHARIS_INSTALLED = False
>
> Property(C): APPARATUS_INSTALLED = False
>
>
>
> So I see that the fonts (for some reason) are installed on the server
> side, and for that reason they are able to receive the updated value
> indicating that the font has already been installed, and therefore the
> action is 'Null'.
>
>
>
>
>
> Example 2 - Project folder identification (use default folder location
> unless there is a registry entry indicating a location previously used by a
> prior version of the app):
>
>                 <CustomAction Id='SetDefProjFolder'
> Property='DEFPROJFOLDER' Value='[WindowsVolume]MyApp 9 Projects' />
>
>                 <Property Id="PROJFOLDERFOUND" Value="unset" />
>
>                 <CustomAction Id="VerifyProjectPath"
>
>                                 Return="check"
>
>                                 Execute="immediate"
>
>                                 BinaryKey="CustomActions.CA.dll"
>
>                                 DllEntry="VerifyProjectPath"  />
>
>
>
>                 <CustomAction Id='UseDefProjFolder' Property='PROJFOLDER'
> Value='[DEFPROJFOLDER]' />
>
>                 <CustomAction Id='UseRegProjFolder' Property='PROJFOLDER'
> Value='[REGPROJFOLDER]' />
>
>                 ...
>
>                 <InstallUISequence>
>
>                     <Show Dialog="FatalErrorDlg" OnExit="error" />
>
>                     <Custom Action="SetDefProjFolder"
> After="FindRelatedProducts"></Custom>
>
>                     <Custom Action="VerifyProjectPath"
> After="SetDefProjFolder"></Custom>
>
>                 </InstallUISequence>
>
>                 ...
>
>                 <Property Id='WIXUI_PROJECTSDIR'
> Value='PROJFOLDER'/>
>
>
>
> And here is the C# code for the custom action:
>
>
>
>         [CustomAction]
>
>         public static ActionResult VerifyProjectPath(Session session)
>
>         {
>
>             session.Log("Begin VerifyProjectPath in custom action dll");
>
>             string regProjPath = GetProjectDirFromRegistry();
>
>             if (string.IsNullOrEmpty(regProjPath))
>
>             {
>
>                 session["REGPROJFOLDER"] = null;
>
>                 session["PROJFOLDERFOUND"] = "NotFound";
>
>                 return ActionResult.Success;
>
>             }
>
>
>
>             session["REGPROJFOLDER"] = regProjPath;
>
>
>
>             if (Directory.Exists(regProjPath) &&
> Directory.GetFiles(regProjPath).Length > 0)
>
>                 session["PROJFOLDERFOUND"] = "AlreadyExisting";
>
>             else
>
>             {
>
>                 session["PROJFOLDERFOUND"] = "InvalidRegEntry";
>
>             }
>
>             return ActionResult.Success;
>
>         }
>
>
>
> As you can see from the code above, the properties REGPROJFOLDER and
> PROJFOLDERFOUND are updated in the C# code.  The updated values are
> referenced in the WiX code.
>
>
>
> When I run the installer, I see this in the log file:
>
>
>
> ...
>
> MSI (c) (20:7C) [14:32:02:210]: Doing action: SetDefProjFolder
>
> Action 14:32:02: SetDefProjFolder.
>
> Action start 14:32:02: SetDefProjFolder.
>
> MSI (c) (20:7C) [14:32:02:210]: PROPERTY CHANGE: Adding DEFPROJFOLDER
> property. Its value is 'C:\MyApp 9 Projects'.
>
> Action ended 14:32:02: SetDefProjFolder. Return value 1.
>
> MSI (c) (20:7C) [14:32:02:210]: Doing action: VerifyProjectPath
>
> Action 14:32:02: VerifyProjectPath.
>
> Action start 14:32:02: VerifyProjectPath.
>
> MSI (c) (20:44) [14:32:02:226]: Invoking remote custom action. DLL:
> C:\Users\<Me>\AppData\Local\Temp\MSIC8CA.tmp, Entrypoint: VerifyProjectPath
>
> MSI (c) (20:40) [14:32:02:226]: Cloaking enabled.
>
> MSI (c) (20:40) [14:32:02:226]: Attempting to enable all disabled
> privileges before calling Install on Server
>
> MSI (c) (20:40) [14:32:02:226]: Connected to service for CA interface.
>
> SFXCA: Extracting custom action to temporary directory:
> C:\Users\<Me>\AppData\Local\Temp\MSIC8CA.tmp-\
>
> SFXCA: Binding to CLR version v4.0.30319
>
> Calling custom action
> CustomActions!CustomActions.CustomActions.VerifyProjectPath
>
> Begin VerifyProjectPath in custom action dll
>
> MSI (c) (20!A0) [14:32:02:426]: PROPERTY CHANGE: Adding REGPROJFOLDER
> property. Its value is 'C:\MyApp 8 Projects\'.
>
> MSI (c) (20!A0) [14:32:02:426]: PROPERTY CHANGE: Modifying PROJFOLDERFOUND
> property. Its current value is 'unset'. Its new value: 'AlreadyExisting'.
>
> Action ended 14:32:02: VerifyProjectPath. Return value 1.
>
> ...
>
> MSI (c) (20:7C) [14:32:02:448]: PROPERTY CHANGE: Adding PROJFOLDER
> property. Its value is 'C:\'.
>
> ...
>
> MSI (c) (20:7C) [14:32:02:464]: Dir (target): Key: PROJFOLDER      ,
> Object: C:\
>
> ...
>
> MSI (c) (20:7C) [14:32:08:919]: Switching to server: APPFOLDER="C:\Program
> Files (x86)\MyApp 9\" PROJFOLDER="C:\" DEFPROJFOLDER="C:\ MyApp 9 Projects"
> EXPLANATIONTEXT="Since this is an upgrade of an existing installation, you
> can't change the location of the project folder." TARGETDIR="C:\"
> PROJFOLDERFOUND="AlreadyExisting" MSIFASTINSTALL="7"
> REBOOT="ReallySuppress" CURRENTDIRECTORY="C:\Projects\MyApp9\BuildDir"
> CLIENTUILEVEL="0" MSICLIENTUSESEXTERNALUI="1" CLIENTPROCESSID="13088"
> USERNAME="<me>" SOURCEDIR="C:\ProgramData\Package
> Cache\{24F072F4-5904-4200-87CA-BB068493FF79}v9.0.100.1\" ACTION="INSTALL"
> EXECUTEACTION="INSTALL" REGPROJFOLDER="C:\MyApp 8 Projects\"
> ROOTDRIVE="C:\" INSTALLLEVEL="1" SECONDSEQUENCE="1"
> WIXUI_INSTALLDIR_VALID="1"  ADDLOCAL=Application,Projects,Fonts
>
> ...
>
> MSI (s) (3C:08) [14:32:09:035]: Command Line: APPFOLDER=C:\Program Files
> (x86)\MyApp 9\ PROJFOLDER=C:\ DEFPROJFOLDER=C:\ MyApp 9 Projects
> EXPLANATIONTEXT=Since this is an upgrade of an existing installation, you
> can't change the location of the project folder. TARGETDIR=C:\
> PROJFOLDERFOUND=AlreadyExisting MSIFASTINSTALL=7 REBOOT=ReallySuppress
> CURRENTDIRECTORY=C:\Projects\MyApp9\BuildDir CLIENTUILEVEL=0
> MSICLIENTUSESEXTERNALUI=1 CLIENTPROCESSID=13088 USERNAME=<me>
> SOURCEDIR=C:\ProgramData\Package
> Cache\{24F072F4-5904-4200-87CA-BB068493FF79}v9.0.100.1\ ACTION=INSTALL
> EXECUTEACTION=INSTALL REGPROJFOLDER=C:\MyApp 8 Projects\ ROOTDRIVE=C:\
> INSTALLLEVEL=1 SECONDSEQUENCE=1 WIXUI_INSTALLDIR_VALID=1
> ADDLOCAL=Application,Projects,Fonts ACTION=INSTALL
>
> ...
>
> MSI (s) (3C:08) [14:32:09:035]: PROPERTY CHANGE: Adding PROJFOLDER
> property. Its value is 'C:\'.
>
> MSI (s) (3C:08) [14:32:09:035]: PROPERTY CHANGE: Adding DEFPROJFOLDER
> property. Its value is 'C:\MyApp 9 Projects'.
>
> MSI (s) (3C:08) [14:32:09:035]: PROPERTY CHANGE: Adding EXPLANATIONTEXT
> property. Its value is 'Since this is an upgrade of an existing
> installation, you can't change the location of the project folder.'.
>
> ...
>
> MSI (s) (3C:08) [14:32:09:035]: PROPERTY CHANGE: Modifying PROJFOLDERFOUND
> property. Its current value is 'unset'. Its new value: 'AlreadyExisting'.
>
> ...
>
> MSI (s) (3C:08) [14:32:09:035]: PROPERTY CHANGE: Adding REGPROJFOLDER
> property. Its value is 'C:\MyApp 8 Projects\'.
>
> ...
>
> MSI (s) (3C:08) [14:32:09:706]: Dir (target): Key: PROJFOLDER      ,
> Object: C:\
>
> ...
>
> Property(S): PROJFOLDER = C:\
>
> Property(S): WIXUI_PROJECTSDIR = PROJFOLDER
>
> Property(S): DEFPROJFOLDER = C:\MyApp 9 Projects
>
> Property(S): EXPLANATIONTEXT = Since this is an upgrade of an existing
> installation, you can't change the location of the project folder.
>
> Property(S): PROJFOLDERFOUND = AlreadyExisting
>
> Property(S): REGPROJFOLDER = C:\MyApp 8 Projects\
>
> ...
>
> Property(C): PROJFOLDER = C:\
>
> Property(C): WIXUI_PROJECTSDIR = PROJFOLDER
>
> Property(C): DEFPROJFOLDER = C:\MyApp 9 Projects
>
> Property(C): EXPLANATIONTEXT = Since this is an upgrade of an existing
> installation, you can't change the location of the project folder.
>
> Property(C): PROJFOLDERFOUND = AlreadyExisting
>
> Property(C): REGPROJFOLDER = C:\MyApp 8 Projects\
>
>
>
> So I see from this that VerifyProjectPath is executed (for some reason) on
> the client side, and for that reason it is able to pass the updated values
> indicating the appropriate project folder location.
>
>
>
> Observations:
>
> 1.  Custom code that is executed as part of InstallUISequence can set
> properties and have the updated values be visible to WiX code that is also
> executed (implicitly or explicitly) as part of InstallUISequence.
>
> 2.  Custom code that is executed as part of InstallExecuteSequence can set
> properties and have the updated values be visible to installation actions.
>
> 3.  It is possible to create a 'fatal error' dialog which is shown within
> the InstallUISequence (but it can only access values of properties that
> were also set within the InstallUISequence???)
>
> 4.  It is NOT possible to create a 'fatal error' dialog which is shown
> within the InstallExecuteSequence, which means it is not possible to use
> such a dialog to report errors which occur in the InstallExecuteSequence.
>
> 5.  As a result of #4, errors which occur in custom code that is executed
> as part of InstallExecuteSequence must be reported by a call
> to session.Message().
>
> 6.  However, the installer will still want to deal with the installation
> failure, and show the fatal error dialog (with the non-updated, i.e.
> default, value), which unfortunately produces 2 error dialogs for the same
> error, the second one having wrong information.
>
> 7.  This inability for custom actions in one sequence to communicate via
> properties to other parts of the installation in the other sequence only
> exists for PER_USER installations.
>
> 8.  This rather odd situation is, inexplicably, 'by design'.
>
>
>
> Can someone please help me understand why preventing free communication
> via properties among parts of the installation is somehow more secure and /
> or why PER_USER installations are inherently less secure and needing such
> restrictions?
>
>
>
> More importantly, can anyone suggest a way for our installer to avoid the
> problem in #6 (above)?
>
>
>
> thanks,
>
> Todd Hoatson
>
>

-- 
Todd Hoatson
Mobile: 763-291-3312
Email:   todd.hoatson at gmail.com
www.linkedin.com/in/toddhoatson



More information about the wix-users mailing list