Signing an Uninstaller

Especially under Windows Vista, installer/uninstaller binaries need to be signed to avoid alarming looking dialog boxes with dire warnings about "unknown publishers" etc.

This presents a difficulty in that the uninstaller binary would normally never be present on your development/packaging machine, only being written onto the target machine at install time. So how can you sign it?

The answer is to run the installer on the development machine in a special mode which only writes the uninstaller to some known location, then sign that binary in the usual way, and finally package the signed uninstaller using a normal `File` command rather than `WriteUninstaller`.

```!ifdef INNER
!echo "Inner invocation"                  ; just to see what's going on
OutFile "\$%TEMP%\tempinstaller.exe"       ; not really important where this is
SetCompress off                           ; for speed
!else
!echo "Outer invocation"

; Call makensis again against current file, defining INNER.  This writes an installer for us which, when
; it is invoked, will just write the uninstaller to some location, and then exit.

!makensis '/DINNER "\${__FILE__}"' = 0

; So now run that installer we just created as %TEMP%\tempinstaller.exe.  Since it
; calls quit the return value isn't zero.

!system "\$%TEMP%\tempinstaller.exe" = 2

; That will have written an uninstaller binary for us.  Now we sign it with your
; favorite code signing tool.

!system "SIGNCODE <signing options> \$%TEMP%\uninstaller.exe" = 0

; Good.  Now we can carry on writing the real installer.

OutFile "my_real_installer.exe"
SetCompressor /SOLID lzma
!endif

...

Function .onInit
!ifdef INNER

; If INNER is defined, then we aren't supposed to do anything except write out
; the installer.  This is better than processing a command line option as it means
; this entire code path is not present in the final (real) installer.

WriteUninstaller "\$%TEMP%\uninstaller.exe"
Quit  ; just bail out quickly when running the "inner" installer
!endif

...[the rest of your normal .onInit]...
FunctionEnd

...

Section "Files" ; or whatever

...

; where you would normally put WriteUninstaller \${INSTDIR}\uninstaller.exe put instead:

!ifndef INNER
SetOutPath \$INSTDIR

; this packages the signed uninstaller

File \$%TEMP%\uninstaller.exe
!endif

...
SectionEnd

!ifdef INNER
Section "Uninstall"

; your normal uninstaller section or sections (they're not needed in the "outer"
; installer and will just cause warnings because there is no WriteInstaller command)

SectionEnd
!endif```

This script should just be compiled in the usual way. It will invoke makensis a second time with the additional symbol INNER defined to generate a slightly unusual installer that does nothing except write the uninstaller binary to a specified location (%TEMP%/uninstaller.exe). Next it actually invokes the generated installer and sure enough it writes %TEMP%/uninstaller.exe with no user interaction needed. Now we can sign the binary with our usual tools (I use SIGNCODE because I have a rather arcane development environment, but SIGNTOOL would be more usual I guess). Once that is done, we run through the rest of the normal stuff, except instead of calling `WriteUninstaller` again we just package the already-created, signed uninstaller instead. Job done.

Davida 07:26, 3 December 2009 (UTC): If you are using the Modern UI, you also need to add the conditionals as follows:

```!ifdef INNER
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!endif```

This prevents yet another warning message.
{"extraction_info": {"found_math": false, "script_math_tex": 0, "script_math_asciimath": 0, "math_annotations": 0, "math_alttext": 0, "mathml": 0, "mathjax_tag": 0, "mathjax_inline_tex": 0, "mathjax_display_tex": 0, "mathjax_asciimath": 0, "img_math": 0, "codecogs_latex": 0, "wp_latex": 0, "mimetex.cgi": 0, "/images/math/codecogs": 0, "mathtex.cgi": 0, "katex": 0, "math-container": 0, "wp-katex-eq": 0, "align": 0, "equation": 0, "x-ck12": 0, "texerror": 0, "math_score": 0.8149681091308594, "perplexity": 2559.336858984162}, "config": {"markdown_headings": false, "markdown_code": true, "boilerplate_config": {"ratio_threshold": 0.18, "absolute_threshold": 10, "end_threshold": 15, "enable": true}, "remove_buttons": true, "remove_image_figures": true, "remove_link_clusters": true, "table_config": {"min_rows": 2, "min_cols": 3, "format": "plain"}, "remove_chinese": true, "remove_edit_buttons": true, "extract_latex": true}, "warc_path": "s3://commoncrawl/crawl-data/CC-MAIN-2018-17/segments/1524125947759.42/warc/CC-MAIN-20180425080837-20180425100837-00441.warc.gz"}