C# application (installer created with WIX) doesn&

2019-02-27 21:18发布

问题:

I created WIX installer for a simple solution after several days of hit and trial, and following several tutorials in order to include the options of launching app at the end of installation, app shortcuts with icons on desktop and in Add/Remove Programs list. When it worked fully well, I replicated the same process for my original project that contains 6 projects and SQLite db. But now when i install the installer, clicking on the installed icon on Desktop has no effect. It doesn't launch the designated exe. Kindly help me.

Should i share the wxs code?

Update: Following is most of the code of my .wxs file. Sorry I could not decipher the source of problem so had to include all the code except the standard top tags. Moreover, it could be a reference for other Wix users to benefit from, once the problem is identified.

<!-- Embed cab1 file inside the package -->
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" />

<!-- Specify Installation folders -->
<Directory Id="TARGETDIR" Name="SourceDir">
  <!-- Program Files folder i.e. on HDD -->
  <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLFOLDER" Name="Pihu" />
  </Directory>
  <!-- Program Menu folder i.e. on Start Menu -->
  <Directory Id="ProgramMenuFolder">
    <Directory Id="ProgramMenuDir" Name="Pihu Co." />
  </Directory>
  <!-- Desktop folder-->
  <Directory Id="DesktopFolder"/>
</Directory>

<!-- Add Main App's exe-->
<DirectoryRef Id="INSTALLFOLDER">
  <Component Id="Pihu.exe" Guid="*">
    <File Id="PihuEXE" Source="../Pihu/bin/$(var.BUILD)/Pihu.exe"
          Name="Pihu.exe" KeyPath="yes"/>
  </Component>
</DirectoryRef>

<!-- Icon for Add/Remove Program must be specified separately by following 2 lines -->
<Icon Id="AddRemoveProgIcon" SourceFile="Pihu.ico"/>
<Property Id="ARPPRODUCTICON" Value="AddRemoveProgIcon" />

<!-- Add shortcut for Start Menu-->
<DirectoryRef Id="ProgramMenuDir">
  <Component Id="StartMenuShortcut" Guid="*">
        <Shortcut Id="StartMenuShortcut" Name="Pihu HMI" Description="Pihu HMI"
            Target="[INSTALLFOLDER]Pihu.exe" WorkingDirectory="INSTALLFOLDER">
          <!--Add Icon to the ShortCut-->
          <Icon Id="StartMenuIcon" SourceFile="Pihu.ico"/>
        </Shortcut>
        <RegistryValue Root="HKCU"  Key='Software\[Manufacturer]\[ProductName]'
                       Name="installed" Type="string" Value="[INSTALLFOLDER]" KeyPath="yes"/>
        <!--Remove the StartMenu folder at Uninstall time -->
        <RemoveFolder Id="StartMenuShortcut" On="uninstall"/>
      </Component>
</DirectoryRef>

<!-- Add shortcut for DeskTop-->
<DirectoryRef Id="DesktopFolder">
  <Component Id="DesktopShortcut" Guid="*">
    <Shortcut Id="DesktopShortcut" Name="Pihu HMI" Description="Pihu HMI"
              Target="[INSTALLFOLDER]Pihu.exe" WorkingDirectory="INSTALLFOLDER">
      <Icon Id="DeskTopIcon" SourceFile="Pihu.ico"/>
    </Shortcut>
    <RegistryValue Root="HKCU"  Key='Software\[Manufacturer]\[ProductName]'
                   Name="installed" Type="string" Value="[INSTALLFOLDER]" KeyPath="yes"/>
    <RemoveFolder Id="DesktopFolder" On="uninstall"/>
  </Component>
</DirectoryRef>

<WixVariable Id="WixUILicenseRtf" Value="License.rtf"/>

<!-- Add Component -->
<Feature Id="MainApplication" Title="Pihu HMI" Level="1" ConfigurableDirectory="INSTALLFOLDER">
  <ComponentRef Id="Pihu.exe" />
  <!-- Add feature for Start menu shortcut-->
  <ComponentRef Id="StartMenuShortcut" />
  <!-- Add feature for DeskTop shortcut-->
  <ComponentRef Id="DesktopShortcut" />
</Feature>

<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch Pihu HMI Application now" />
<Property Id="WixShellExecTarget" Value="[#PihuEXE]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />

<UI>
  <UIRef Id="WixUI_FeatureTree"/>
  <Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="LaunchApplication">
    WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed
  </Publish>
</UI>

Pihu.exe runs fine when run from the Debug or Release folder. First screen is independent of the DB so that cannot be a problem. I think the only problem is the solution being multi-project (although dlls of all the dependent projects are also present in Debug as well as Release folders)

回答1:

I will "evolve" this answer once you add more details to your question. I want to avoid too many comments. And yes, please share the core of your WiX source in your question, or even the compiled MSI itself if it is public and not too large and you got a place to upload it - link to it.

A quick note on posting WiX-sources online:

Please eliminate any passwords, database connection strings, user names, share names, IP-addresses, or other sensitive data from your WiX source before posting. A good package shouldn't hard-code any of this (they should be parameters set by the end user at install time), but as we know, sometimes hard-coded stuff (often from your dev-box) sneaks into the source during development - give it a once-over. Please also eliminate hard coded-GUIDs in the source - replace them with PUT-GUID-HERE (not that critical, we will help you do that if you are unsure how).

Some questions for starters:

  • Did you use new GUIDs for product code, package code, component GUIDs etc... for your new project? Really strange results can occur if you re-use a package code or component codes. Reusing the same product code is easier to detect, but that can also cause problems.
  • Did you try launching the main EXE directly from the file system? (to check if the problem is with the shortcut).
  • Are there any error messages when you try to launch the application? Did you check the event logs as well (in addition to any GUI errors)? Does the application feature its own custom logging? If so, please check.
  • Did you scan the binary for dependencies after installation? Just throwing in a link to a recent answer I wrote: After creating MSI Installer for WPF app in Visual Studio 2017, EXE does nothing (Dependencies.exe, procmon.exe, visual studio modules view, several options...). You can also try the old Dependency Walker even if it is old now and doesn't deal well with Win32 assembly dependencies or Api-Sets.
  • Did you log the MSI installation? If not, please do so and check for any errors. See section below for how to log an MSI installation.
    • Once you have a log, you can search for "value 3" in the log file as explained by Rob Mensching here, but in your case the install seems to have completed successfully, so you need to look for warnings and suppressed errors as well.
    • This article from Robert Macdonald from the Windows Installer Team is highly recommended as a practical look at MSI logging: How to Interpret Windows Installer Logs.
    • The full range of msiexec.exe command line options. Here is the technet version.

Logging your MSI-Install

Here is how to log your install:

msiexec.exe /I "C:\Installer.msi" /QN /L*V "C:\msilog.log"

Quick Parameter Explanation:

/I = run regular installation sequence
/QN = run completely silently
/L*V "C:\My.log" = verbose logging at specified path

If this is confusing try installsite.org's logging FAQ - how to create a log file for your installation.

Deploying all required files (dealing with dependencies)

Wix does not feature "automagic" - out of the box - in the sense that all dependent files are automatically included at build time (unless there is a new feature I am not aware of).

You have to manually specify what files are to be installed with your MSI, and frankly this is expected behavior in my opinion - what WiX gives you is control and flexibility of your installer - at the cost of being somewhat fiddly to deal with at times. However, if you do it as easy as possible you will appreciate the flexibility and clarity of a WiX source for your MSI.

So, how do you deal with this as simple as possible? I would just set your build type to "Release" in Visual Studio, and then go Debug => Start Debugging to run your project interactively. Now go to Debug => Windows => Modules and make a note of all the files (modules) that are loaded. Then include the files loaded by your solution in your WiX source for deployment to the target system, and identify shared files (system files) that are loaded from elsewhere on the machine (GAC for example) and determine if they require a runtime to be installed on the system. You must not include such shared (or system) files directly in your WiX source, but via a merge module (a mechanism for installing shared runtimes) or a separate setup.exe that does the job of installing the runtime.

In order to include these files in your WiX source, you simply add them to the appropriate directory in your WiX source. In its simplest form:

<Component>
   <File Source="C:\Users\Acer\SourceControl\MyProject\CoreApp.exe" />
</Component>

The above component contains a single file, and the element takes advantage of WiX's ability to default most attributes based on the file name itself. The Component Id and GUID is auto-generated - as is the File Id and Name as well. I wrote briefly about this before in this answer - maybe have a quick skim: Syntax for guids in WIX?.

Inline in your source, adding a file would look something like this (using these minimal component elements as described in the linked answer directly above):

<DirectoryRef Id="INSTALLFOLDER">

  <Component Id="Pihu.exe" Guid="*">
    <File Id="PihuEXE" Source="../Pihu/bin/$(var.BUILD)/Pihu.exe"
          Name="Pihu.exe" KeyPath="yes"/>
  </Component>

  <Component>
     <File Source="C:\Users\Acer\SourceControl\MyProject\CoreApp.exe" />
  </Component>

  <Component>
     <File Source="C:\Users\Acer\SourceControl\MyProject\CoreApp.dll" />
  </Component>

  <Component>
     <File Source="C:\Users\Acer\SourceControl\MyProject\CoreApp2.dll" />
  </Component>

</DirectoryRef>

That's just the simplest mock-up I can think of. The source attribute is the only mandatory one you need to specify. I have set it to an absolute path to ensure the file compiles, but you should make use of WiX project variables, as you do in your source above. See Using Project References and Variables. While you are at it you should also have a quick look at the Preprocessor features.

If you follow the instructions properly for the project references and variables, you should be able to get a source that look something like this (but maybe get the WiX source to compile with absolute paths before you delve into this - note that ConsoleApplication is obviously the name of your Visual Studio project that compiles your application binaries):

<DirectoryRef Id="INSTALLFOLDER">

  <Component Id="Pihu.exe" Guid="*">
    <File Id="PihuEXE" Source="../Pihu/bin/$(var.BUILD)/Pihu.exe"
          Name="Pihu.exe" KeyPath="yes"/>
  </Component>

  <Component>
     <File Source="$(var.ConsoleApplication.TargetDir)\SupportFile1.dll" />
  </Component>

  <Component>
     <File Source="$(var.ConsoleApplication.TargetDir)\SupportFile2.dll" />
  </Component>

  <Component>
     <File Source="$(var.ConsoleApplication.TargetDir)\SupportFile3.dll" />
  </Component>

</DirectoryRef>

Please give this a go. I don't have time to test compile this right now, and I use a different scheme myself (I use the preprocessor and <?define?> statements to specify a release folder where I have copied all output files - I don't reference files directly from the Visual Studio output folders).

It does look like you are already doing this with your BUILD variable, but I generally use a base build output path such as this:

<?define RELEASEFOLDER= "R:\Releases\ProductName\5.0.2\"?>

and then my source elements become something like this:

  <Component>
     <File Source="$(var.RELEASEFOLDER)\MyApp.exe" />
  </Component>

A lot more detail and probably opinions than you need I think, but I hope it helps you solve your problem. Once set up WiX sources are fantastic to tweak when you need it. The flexibility is outstanding.

Using heat.exe to "harvest" folders

If you just have a few files to add, the above method should be fine. However, if you have lots of files to add you should use the WiX tool heat.exe. It allows you to "harvest" directories and generate WiX XML with the required component and file elements to install the files in question. Here is the official documentation for heat.exe.

In its simplest form you could use something like this:

  1. Open a command prompt and navigate to the folder structure you want to include in your MSI.
  2. Try something like heat.exe dir . -sfrag -out HeatTest.wxs to generate the WiX XML file HeatTest.wxs. It will now contain the required XML to install the files in question from the folder you navigated to and below (. means current folder).
  3. I prefer to search for and replace Guid="PUT-GUID-HERE" with an empty string since the GUID can be auto-generated. I don't see a switch to allow the creation of "Minimal WiX XML" - in other words with only required attributes. I think you can leave out the Directory Ids as well.
  4. I also like to replace the source attribute default path with a defined value such as RELEASEFOLDER. Something like this: heat.exe dir . -sfrag -var var.RELEASEFOLDER -out HeatTest.wxs. Try it out. Now the Source attribute becomes something like: Source="$(var.RELEASEFOLDER)\src\Burn\Frost\Frost.sln" instead of Source="SourceDir\src\Burn\Frost\Frost.sln".

With some practice it becomes really quick to create the basic install structure for your MSI using this heat.exe tool with some manual cleanup of the generated source. I like it a lot for creating tedious "file intensive" packages such as IIS installers that may contain thousands of files that would be hopeless to try to create WiX XML for manually.