summaryrefslogtreecommitdiff
path: root/xmake/scripts/xpack/nsis/makensis.nsi
blob: 53cd82e99d41115a29ccfe58fe4c17e9800e6d35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
; this is a NSI spec file,
; it is autogenerated by the xmake build system.
; do not edit by hand.

; includes
!include "MUI2.nsh"
!include "WordFunc.nsh"
!include "WinMessages.nsh"
!include "FileFunc.nsh"
!include "UAC.nsh"

; the version information
!define VERSION      "${PACKAGE_VERSION}"
!if "${PACKAGE_VERSION_BUILD}" != ""
!define VERSION_FULL "${PACKAGE_VERSION}+${PACKAGE_VERSION_BUILD}"
!else
!define VERSION_FULL "${PACKAGE_VERSION}"
!endif

; set the package name
Name "${PACKAGE_NAME} - v${VERSION}"

; set the output file path
OutFile "${PACKAGE_OUTPUTFILE}"

; set the working directory
!cd "${PACKAGE_WORKDIR}"

; use unicode
Unicode true

; use best compressor
SetCompressor /FINAL /SOLID lzma
SetCompressorDictSize 64
SetDatablockOptimize ON

; set the default installation directory
!if "${PACKAGE_ARCH}" == "x64"
  !define PROGRAMFILES $PROGRAMFILES64
  !define HKLM HKLM64
  !define HKCU HKCU64
!else
  !define PROGRAMFILES $PROGRAMFILES
  !define HKLM HKLM
  !define HKCU HKCU
!endif

; request application privileges for Windows Vista
RequestExecutionLevel user

; set DPI aware
ManifestDPIAware true

; set icon
!if "${PACKAGE_ICONFILE}" != ""
  !define MUI_ICON "${PACKAGE_ICONFILE}"
!endif

; UAC
!macro Init thing
  uac_tryagain:
  !insertmacro UAC_RunElevated
  ${Switch} $0
  ${Case} 0
    ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done
    ${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on
    ${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user
      MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0
    ${EndIf}
    ;fall-through and die
  ${Case} 1223
    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, aborting!"
    Quit
  ${Case} 1062
    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!"
    Quit
  ${Default}
    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate, error $0"
    Quit
  ${EndSwitch}

  ; The UAC plugin changes the error level even in the inner process, reset it.
  ; note fix install exit code 1223 to 0 with slient /S
  SetErrorLevel 0
  SetShellVarContext all
!macroend

; add the install Pages
!insertmacro MUI_PAGE_WELCOME
!if "${PACKAGE_LICENSEFILE}" != ""
  !insertmacro MUI_PAGE_LICENSE "${PACKAGE_LICENSEFILE}"
!endif
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

; add uninstall Pages
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

; add languages
!insertmacro MUI_LANGUAGE "English"

; set registry paths
!define RegUninstall "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}"

; set product information
VIProductVersion                         "${VERSION}.0"
VIFileVersion                            "${VERSION}.0"
VIAddVersionKey /LANG=0 ProductName      "${PACKAGE_NAME}"
VIAddVersionKey /LANG=0 Comments         "${PACKAGE_DESCRIPTION}"
VIAddVersionKey /LANG=0 CompanyName      "${PACKAGE_COMPANY}"
VIAddVersionKey /LANG=0 LegalCopyright   "${PACKAGE_COPYRIGHT}"
VIAddVersionKey /LANG=0 FileDescription  "${PACKAGE_NAME} Installer - v${VERSION}"
VIAddVersionKey /LANG=0 OriginalFilename "${PACKAGE_FILENAME}"
VIAddVersionKey /LANG=0 FileVersion      "${VERSION_FULL}"
VIAddVersionKey /LANG=0 ProductVersion   "${VERSION_FULL}"

; helper functions
Function TrimQuote
  Exch $R1 ; Original string
  Push $R2

Loop:
  StrCpy $R2 "$R1" 1
  StrCmp "$R2" "'"   TrimLeft
  StrCmp "$R2" "$\"" TrimLeft
  StrCmp "$R2" "$\r" TrimLeft
  StrCmp "$R2" "$\n" TrimLeft
  StrCmp "$R2" "$\t" TrimLeft
  StrCmp "$R2" " "   TrimLeft
  GoTo Loop2
TrimLeft:
  StrCpy $R1 "$R1" "" 1
  Goto Loop

Loop2:
  StrCpy $R2 "$R1" 1 -1
  StrCmp "$R2" "'"   TrimRight
  StrCmp "$R2" "$\"" TrimRight
  StrCmp "$R2" "$\r" TrimRight
  StrCmp "$R2" "$\n" TrimRight
  StrCmp "$R2" "$\t" TrimRight
  StrCmp "$R2" " "   TrimRight
  GoTo Done
TrimRight:
  StrCpy $R1 "$R1" -1
  Goto Loop2

Done:
  Pop $R2
  Exch $R1
FunctionEnd

; remove directory if it exists
Function RMDirIfExists
!define RMDirIfExists '!insertmacro RMDirIfExistsCall'
!macro RMDirIfExistsCall _PATH
  push '${_PATH}'
 Call RMDirIfExists
!macroend
  Exch $0
  IfFileExists "$0" 0 fileDoesNotExist
  RMDir /r "$0"
  fileDoesNotExist:
FunctionEnd

Function un.RMDirIfExists
!define unRMDirIfExists '!insertmacro unRMDirIfExistsCall'
!macro unRMDirIfExistsCall _PATH
  push '${_PATH}'
  Call un.RMDirIfExists
!macroend
  Exch $0
  IfFileExists "$0" 0 fileDoesNotExist
  RMDir /r "$0"
  fileDoesNotExist:
FunctionEnd

; remove file if it exists
Function RMFileIfExists
!define RMFileIfExists '!insertmacro RMFileIfExistsCall'
!macro RMFileIfExistsCall _PATH
  push '${_PATH}'
  Call RMFileIfExists
!macroend
  Exch $0
  IfFileExists "$0" 0 fileDoesNotExist
  Delete "$0"
  fileDoesNotExist:
FunctionEnd

Function un.RMFileIfExists
!define unRMFileIfExists '!insertmacro unRMFileIfExistsCall'
!macro unRMFileIfExistsCall _PATH
  push '${_PATH}'
  Call un.RMFileIfExists
!macroend
  Exch $0
  IfFileExists "$0" 0 fileDoesNotExist
  Delete "$0"
  fileDoesNotExist:
FunctionEnd

; remove it's parent directories if they are empty
Function RMEmptyParentDirs
!define RMEmptyParentDirs '!insertmacro RMEmptyParentDirsCall'
!macro RMEmptyParentDirsCall _PATH
  push '${_PATH}'
  Call RMEmptyParentDirs
!macroend
  ClearErrors

  Exch $0
  RMDir "$0\.."

  IfErrors Skip
  ${RMEmptyParentDirs} "$0\.."
  Skip:

  Pop $0
FunctionEnd

Function un.RMEmptyParentDirs
!define unRMEmptyParentDirs '!insertmacro unRMEmptyParentDirsCall'
!macro unRMEmptyParentDirsCall _PATH
  push '${_PATH}'
  Call un.RMEmptyParentDirs
!macroend
  ClearErrors

  Exch $0
  RMDir "$0\.."

  IfErrors Skip
  ${unRMEmptyParentDirs} "$0\.."
  Skip:

  Pop $0
FunctionEnd


; setup installer
Var NoAdmin
Function .onInit
  ${GetOptions} $CMDLINE "/NOADMIN" $NoAdmin
  ${If} ${Errors}
    !insertmacro Init "installer"
    StrCpy $NoAdmin "false"
  ${Else}
    StrCpy $NoAdmin "true"
  ${EndIf}

  ; get installation root directory
  ${If} $InstDir == ""
    ${If} $NoAdmin == "false"
      ReadRegStr $R0 ${HKLM} ${RegUninstall} "InstallLocation"
    ${Else}
      ReadRegStr $R0 ${HKCU} ${RegUninstall} "InstallLocation"
    ${EndIf}
    ${If} $R0 != ""
      Push $R0
      Call TrimQuote
      Pop  $R0
      StrCpy $InstDir $R0
    ${EndIf}
  ${EndIf}
  ${If} $InstDir == ""
    StrCpy $InstDir "${PROGRAMFILES}\${PACKAGE_NAME}"
  ${EndIf}
FunctionEnd

Section "${PACKAGE_NAME} (required)" InstallExeutable

  SectionIn RO

  ; set output path to the installation directory.
  SetOutPath $InstDir

  ; add install commands
  ${PACKAGE_INSTALLCMDS}

  ; add uninstaller
  WriteUninstaller "uninstall.exe"
  ; Write the uninstall keys for Windows
  !macro AddReg RootKey
    WriteRegStr   ${RootKey} ${RegUninstall} "NoAdmin"               "$NoAdmin"
    WriteRegStr   ${RootKey} ${RegUninstall} "DisplayName"           "${PACKAGE_TITLE}"
    !if "${PACKAGE_NSIS_DISPLAY_ICON}" != ""
    WriteRegStr   ${RootKey} ${RegUninstall} "DisplayIcon"           '"${PACKAGE_NSIS_DISPLAY_ICON}"'
    !endif
    WriteRegStr   ${RootKey} ${RegUninstall} "Comments"              "${PACKAGE_DESCRIPTION}"
    WriteRegStr   ${RootKey} ${RegUninstall} "Publisher"             "${PACKAGE_COPYRIGHT}"
    WriteRegStr   ${RootKey} ${RegUninstall} "UninstallString"       '"$InstDir\uninstall.exe"'
    WriteRegStr   ${RootKey} ${RegUninstall} "QuiteUninstallString"  '"$InstDir\uninstall.exe" /S'
    WriteRegStr   ${RootKey} ${RegUninstall} "InstallLocation"       $InstDir
    WriteRegStr   ${RootKey} ${RegUninstall} "HelpLink"              "${PACKAGE_HOMEPAGE}"
    WriteRegStr   ${RootKey} ${RegUninstall} "URLInfoAbout"          "${PACKAGE_HOMEPAGE}"
    WriteRegStr   ${RootKey} ${RegUninstall} "URLUpdateInfo"         "${PACKAGE_HOMEPAGE}"
    WriteRegDWORD ${RootKey} ${RegUninstall} "VersionMajor"          ${PACKAGE_VERSION_MAJOR}
    WriteRegDWORD ${RootKey} ${RegUninstall} "VersionMinor"          ${PACKAGE_VERSION_MINOR}
    WriteRegStr   ${RootKey} ${RegUninstall} "DisplayVersion"        ${VERSION_FULL}
    WriteRegDWORD ${RootKey} ${RegUninstall} "NoModify"              1
    WriteRegDWORD ${RootKey} ${RegUninstall} "NoRepair"              1

    ; write size to reg
    ${GetSize} "$InstDir" "/S=0K" $0 $1 $2
    IntFmt $0 "0x%08X" $0
    WriteRegDWORD ${RootKey} ${RegUninstall} "EstimatedSize" "$0"
  !macroend

  ${If} $NoAdmin == "false"
    !insertmacro AddReg ${HKLM}
  ${Else}
    !insertmacro AddReg ${HKCU}
  ${EndIf}
SectionEnd

; add the binary directory to %PATH%
Section "Add to PATH" InstallPath
  ${If} $NoAdmin == "false"
    ReadRegStr $R0 ${HKLM} "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path"
    ${WordReplace} $R0 ";${PACKAGE_BINDIR}" "" "+" $R1
    WriteRegExpandStr ${HKLM} "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$R1;${PACKAGE_BINDIR}"
  ${Else}
    ReadRegStr $R0 ${HKCU} "Environment" "Path"
    ${WordReplace} $R0 ";${PACKAGE_BINDIR}" "" "+" $R1
    WriteRegExpandStr ${HKCU} "Environment" "Path" "$R1;${PACKAGE_BINDIR}"
  ${EndIf}
   SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
SectionEnd

${PACKAGE_NSIS_INSTALL_SECTIONS}

; define language strings
LangString DESC_InstallExeutable ${LANG_ENGLISH} "${PACKAGE_DESCRIPTION}"
LangString DESC_InstallPath ${LANG_ENGLISH} "Add ${PACKAGE_NAME} to PATH"
${PACKAGE_NSIS_INSTALL_DESCS}

; assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${InstallExeutable} $(DESC_InstallExeutable)
!insertmacro MUI_DESCRIPTION_TEXT ${InstallPath} $(DESC_InstallPath)
${PACKAGE_NSIS_INSTALL_DESCRIPTION_TEXTS}
!insertmacro MUI_FUNCTION_DESCRIPTION_END

; setup uninstaller
Function un.onInit
  ; check if we need uac
  ReadRegStr $NoAdmin ${HKLM} ${RegUninstall} "NoAdmin"
  IfErrors 0 +2
  ReadRegStr $NoAdmin ${HKCU} ${RegUninstall} "NoAdmin"

  ${IfNot} $NoAdmin == "true"
    !insertmacro Init "uninstaller"
  ${EndIf}
FunctionEnd

Section "Uninstall"

  ; add uninstall commands
  ${PACKAGE_UNINSTALLCMDS}

  ; remove the binary directory from %Path%
  ${If} $NoAdmin == "false"
    DeleteRegKey ${HKLM} ${RegUninstall}
    ReadRegStr $R0 ${HKLM} "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path"
    ${WordReplace} $R0 ";${PACKAGE_BINDIR}" "" "+" $R1
    WriteRegExpandStr ${HKLM} "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$R1"
  ${Else}
    DeleteRegKey ${HKCU} ${RegUninstall}
    ReadRegStr $R0 ${HKCU} "Environment" "Path"
    ${WordReplace} $R0 ";${PACKAGE_BINDIR}" "" "+" $R1
    WriteRegExpandStr ${HKCU} "Environment" "Path" "$R1"
  ${EndIf}

  ; remove uninstall.exe
  ${unRMFileIfExists} "$InstDir\uninstall.exe"
  ${unRMEmptyParentDirs} "$InstDir\uninstall.exe"

SectionEnd