2

I want to open a PDF file after my WiX installer completes.

The relevant WiX XML I currently have is:

<Property Id="WixShellExecTarget" Value="[#Manual.pdf]" />

<CustomAction Id="ShowManual" 
    Return="ignore" 
    BinaryKey="WixCA"
    DllEntry="WixShellExec" 
    Impersonate="yes" />

<InstallExecuteSequence>
    <Custom Action="ShowManual" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>

This all works fine on machines where a PDF reader is installed. But if not, Windows is flashing up a message saying 'Windows can't open this type of file'.

Is there any way to get WiX to only attempt the call to ShellExecute if there is an application associated with PDF files? Or is it possible to get the call to fail silently without displaying any errors?

Cocowalla
  • 13,822
  • 6
  • 66
  • 112
  • 2
    Couldnèt you do a RegistrySearch to see if the extension is handled and make it a condition for your CustomAction – CheGueVerra Feb 04 '15 at 21:42
  • @CheGueVerra I hadn't thought of that, but I understand that the required registry key can change dependent on the version of Windows. I'd rather avoid the registry if possible – Cocowalla Feb 04 '15 at 21:44
  • You could detect the Version of Windows search the corresponding registry values. Otherwise I don't see how you can check if you can open the PDF – CheGueVerra Feb 04 '15 at 22:05
  • 1
    I don't think the location changes on different version Windows, but I haven't checked. Looking for something under HKCR\.pdf would be a place to start, but you're right in that it might not be reliable. Otherwise you'd need to run code that does a ShellExecute on pdf first before trying to open the pdf. – PhilDW Feb 06 '15 at 21:54
  • The obvious poor man's solution is to create an EXE as part of your build that does this logic and use a simple Type 2 EXE custom action or WiX ShellExecute custom action to call that. Keep the complexity out of the installer. Otherwise the Registry Search / Condition is a good way to go. As much as I like DTF, it's not needed here. – Christopher Painter Feb 06 '15 at 22:14
  • 1
    @PhilDW I've checked, and the HKCR\.pdf value is not set on Windows 8, so there are differences between different versions – Cocowalla Feb 10 '15 at 20:49

1 Answers1

-1

I solved this by creating an 'immediate' managed custom action that runs after InstallFinalize and uses FindExecutable to check if an application is associated with PDF files before trying to open it:

[DllImport("shell32.dll", EntryPoint = "FindExecutable")]
private static extern long FindExecutable(string lpFile, string lpDirectory, StringBuilder lpResult);

[CustomAction]
public static ActionResult ShowPdf(Session session)
{
    var installDir = session["INSTALLDIR"];
    var pdfPath = Path.Combine(installDir, @"My Dir\My.pdf");

    var pdfReaderPath = new StringBuilder(1024);
    long lngResult = FindExecutable(pdfPath, String.Empty, pdfReaderPath);

    if ((lngResult >= 32) && (!String.IsNullOrWhiteSpace(pdfReaderPath.ToString())))
    {
        Process.Start(pdfPath);
    }

    return ActionResult.Success;
}
Cocowalla
  • 13,822
  • 6
  • 66
  • 112
  • Unneeded code. Increases dependencies and fragility. There is a simpler more elegant way to accomplish the requirement. – Christopher Painter Feb 10 '15 at 19:30
  • @ChristopherPainter fair enough, but I'm not convinced building and bundling a separate executable is much simpler. I've also confirmed that the registry method is more complex than you would guess, since the HKCR\.pdf value is not set in Windows 8. I'd rather use a well defined API that is consistent across all Windows versions – Cocowalla Feb 10 '15 at 20:49