]> git.lyx.org Git - features.git/blob - development/Win32/packaging/installer2/src/main.nsh
Consider inset strings in simple find/replaceAll (#12049)
[features.git] / development / Win32 / packaging / installer2 / src / main.nsh
1 #-------------------------------------------------------------
2 # - - - - - - - - - - - - Preamble - - - - - - - - - - - - - -
3 #-------------------------------------------------------------
4
5   # Do a Cyclic Redundancy Check to make sure the installer
6   # was not corrupted by the download.
7   CRCCheck force
8   # Make the installer as small as possible
9   SetCompressor /SOLID lzma
10   # Make it a Unicode installer
11   Unicode true
12   # Enable support for high DPI resolution
13   ManifestDPIAware true
14
15   Name "LyX ${APP_VERSION}" # Name of the Program to be displayed during installation
16   BrandingText " " # Remove branding text ('Nullsoft Install System vX.XX')
17
18   # ===== Variables =====
19
20     Var LatexPath # Used to store path to "latex.exe"
21     Var StartMenuFolder # Used to store the start menu folder
22     Var pathPrefix
23
24     # FIXME Variables needed due to "old" set of language strings, delete
25     Var LaTeXInstalled
26     Var LaTeXName
27     Var OldVersionNumber
28     Var AppPre
29     Var AppSuff
30     # R3
31
32     # FIXME Compile time constants needed due to "old" set of language strings, delete
33     !define APP_SERIES_KEY2 ${APP_VERSION}
34     !define APP_DIR_USERDATA "LyX${VERSION_MAJOR}.${VERSION_MINOR}"
35
36   # ========= Multiuser settings =========
37
38     !define MULTIUSER_MUI # Multiuser uses modern UI 2
39     !define MULTIUSER_EXECUTIONLEVEL Highest # Can install with any privileges (admin, user)
40     !if ${APP_ARCHITECTURE} = 64
41       !define MULTIUSER_USE_PROGRAMFILES64 # Install 64 bit program in "Program files" instead of "Program files (x86)"
42     !endif
43
44     !define MULTIUSER_INSTALLMODE_COMMANDLINE # Allow setting installmode in commandline (/AllUsers or /CurrentUser)
45
46     # Set default install mode based on a non empty registry entry (if exists in HKLM, then all users, if HKCU then current user)
47     !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "SOFTWARE\LyX"
48     !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "InstDir${VERSION_MAJOR}${VERSION_MINOR}"
49
50     !define MULTIUSER_INSTALLMODE_INSTDIR "LyX ${VERSION_MAJOR}.${VERSION_MINOR}" # Default install dir if not over-installing
51
52     # Retrieve default install location from following registry entry (HKCU/HKLM  is chosen automatically)
53     !define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "SOFTWARE\LyX"
54     !define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "InstDir${VERSION_MAJOR}${VERSION_MINOR}"
55
56     !include MultiUser.nsh # Header file: Installer configuration for multi-user Windows environments
57     # When MULTIUSER_INSTALLMODE_COMMANDLINE is defined, MultiUser.nsh defines ${StrStr} and ${UnStrStr} functions
58
59   # ============= Modern UI 2 general settings ===============
60
61     #!include MUI2.nsh # included in MultiUser # Header file for creating modern looking installer
62     !define MUI_ABORTWARNING # Show a message box with a warning when the user wants to close the installer.
63     !define MUI_ICON "..\installer\icons\lyx.ico" # FIXME path # The icon for the installer.
64     !define MUI_UNICON "..\installer\icons\lyx.ico" # FIXME path # The icon for the uninstaller
65     !define MUI_HEADERIMAGE # Display an image on the header of the page.
66     !define MUI_HEADERIMAGE_BITMAP "..\installer\graphics\header.bmp" # FIXME path # Header image source
67     !define MUI_HEADERIMAGE_RIGHT # Display header image on the right and not left
68     !define MUI_WELCOMEFINISHPAGE_BITMAP "..\installer\graphics\wizard.bmp" # FIXME path # Source for image on welcome and finish page of the installer
69     !define MUI_UNWELCOMEFINISHPAGE_BITMAP "..\installer\graphics\wizard.bmp" # FIXME path # Source for image on welcome and finish page of the uninstaller
70
71   # ======== Pages definitions ==========
72
73     # Installer
74
75     !define MUI_WELCOMEPAGE_TEXT $(TEXT_WELCOME) # Use custom welcome text
76     !insertmacro MUI_PAGE_WELCOME # Welcome page
77
78     !insertmacro MUI_PAGE_LICENSE "..\installer\license.rtf" # FIXME path # License page
79
80     !define MUI_PAGE_CUSTOMFUNCTION_PRE PrepareShellCTX # Prepare shell context before the multiuser page is created, so that the installer searches for default install folder in the right context (x64/x32)
81     !insertmacro MULTIUSER_PAGE_INSTALLMODE # Multiuser page
82
83     !define MUI_PAGE_CUSTOMFUNCTION_LEAVE VerifyInstDir # Custom leave-function for directory page to verify installdir
84     !insertmacro MUI_PAGE_DIRECTORY # Directory page (where to install)
85
86     !define MUI_PAGE_CUSTOMFUNCTION_PRE DefaultDesktopFileAssoc # Custom pre-function for components page to search for already present dictionaries (in dictionaries.nsh)
87     !insertmacro MUI_PAGE_COMPONENTS # Components page (what to install)
88
89     # Default startmenu folder if registry contains no information from a previous installment, same as the default install dir
90     !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${MULTIUSER_INSTALLMODE_INSTDIR}"
91     # Define registry entry to store the startmenu folder, also reads this entry in as default startmenu folder in case of over-installing
92     !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" # Context dependent on what the user chooses on multiuser page
93     !define MUI_STARTMENUPAGE_REGISTRY_KEY "SOFTWARE\LyX"
94     !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "SMDir${VERSION_MAJOR}${VERSION_MINOR}"
95     !define MUI_PAGE_CUSTOMFUNCTION_PRE PrepareShellCTX # Prepare shell context before the startmenu page is created, so that the installer searches for default startmenu folder in the right context
96     !define MUI_PAGE_CUSTOMFUNCTION_SHOW RetrieveSMState # Custom show-function for startmenu page to disable startmenu dir creation in case of over-installment where previously disabled
97     !insertmacro MUI_PAGE_STARTMENU startmenuPage $StartMenuFolder # Page to choose start menu folder entry, the folder is stored in VARIABLE
98
99     # Latexfolder page
100     !include "src\CustomPages\LaTeXFolder.nsdinc"
101     Page custom LatexFolder_Show LatexFolder_Leave
102
103     !insertmacro MUI_PAGE_INSTFILES # Progress page
104
105     !define MUI_FINISHPAGE_SHOWREADME # Showreadme-checkbox appears
106     !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED # Showreadme-checkbox disabled by default
107     !define MUI_FINISHPAGE_SHOWREADME_FUNCTION StartLyX # Custom function for the showreadme-checkbox (start latex instead of show readme)
108     !define MUI_FINISHPAGE_SHOWREADME_TEXT $(FinishPageRun) # Custom text for the label on the showreadme-checkbox
109     !define MUI_FINISHPAGE_LINK $(TEXT_FINISH_WEBSITE) # Text for the link on the bottom of finish page
110     !define MUI_FINISHPAGE_LINK_LOCATION "https://www.lyx.org/" # Website opens by clicking on the link on finish page
111     !insertmacro MUI_PAGE_FINISH # Finish page
112
113     # Uninstaller
114
115     !insertmacro MUI_UNPAGE_WELCOME # Welcome page
116     !insertmacro MUI_UNPAGE_CONFIRM # Confirmation page
117
118     !define MUI_PAGE_CUSTOMFUNCTION_PRE un.ComponentsPre # Custom function for components page to prepare strings for the description of a section
119     !insertmacro MUI_UNPAGE_COMPONENTS # Components page
120
121     !insertmacro MUI_UNPAGE_INSTFILES # Progress page
122     !insertmacro MUI_UNPAGE_FINISH # Finish page
123
124   # ======= Other includes =======
125
126     !include "src\lang\TranslatedLanguages.nsh" # languages strings
127
128     #!include LogicLib.nsh # included in MUI2 # Allows using logic commands (such as ${If}..${Else}..${EndIf})
129     #!include LangFile.nsh # included in MUI2 # Header file to create language files that can be included with a single command.
130     !include x64.nsh # Header file to check if target system is 64 bit or not with ${RunningX64}, also defines ${DisableX64FSRedirection} and ${EnableX64FSRedirection}
131     !include NSISList.nsh # Header file to create and work with lists in NSIS (plugin)
132
133     #!include StrFunc.nsh # included in MultiUser # Provides some additional string functions
134     ${StrRep} # Define this function from StrFunc.nsh for further use
135     ${StrStrAdv} # Define this function from StrFunc.nsh for further use
136     ${UnStrStrAdv} # Define this function from StrFunc.nsh for further use
137     ${UnStrRep} # Define this function from StrFunc.nsh for further use
138
139   # ========= Installer Attributes ===========
140
141     VIProductVersion "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}.${VERSION_BUILD}" # Must be X.X.X.X format
142     VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "LyX"
143     VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "LyX ${APP_VERSION} installer"
144     VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${APP_VERSION}"
145     VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "LyX - The Document Processor"
146     VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "LyX is Copyright © 1995 by Matthias Ettrich, 1995-${COPYRIGHT_YEAR} by the LyX Team"
147     VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "LyX Team"
148     VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalTrademarks" ""
149
150 #-------------------------------------------------------------
151 # - - - - - - - - - - Helper Functions - - - - - - - - - - - -
152 #-------------------------------------------------------------
153
154   # Forward declarations
155   
156   !macro SearchAllRegistry resultVar resultStateIdx resultRegIdx subKey searchFor startStateIdx startRegIdx
157     Push ${subKey}
158     Push ${searchFor}
159     Push ${startStateIdx}
160     Push ${startRegIdx}
161     Call SearchAllRegistry
162     Pop ${resultStateIdx}
163     Pop ${resultRegIdx}
164     Pop ${resultVar}
165   !macroend
166   
167   !define SearchAllRegistry "!insertmacro SearchAllRegistry"
168   
169   !macro SearchRegistry resultVar resultRegIdx subKey searchFor startRegIdx
170     Push ${subKey}
171     Push ${searchFor}
172     Push ${startRegIdx}
173     Call SearchRegistry
174     Pop ${resultRegIdx}
175     Pop ${resultVar}
176   !macroend
177   
178   !define SearchRegistry "!insertmacro SearchRegistry"
179   
180   # Functions
181   
182   Function SearchAllRegistry
183     Exch $9 # startRegIdx
184     Exch
185     Exch $8 # startStateIdx
186     Exch 2
187     Exch $7 # searchFor
188     Exch 3
189     Exch $6 # subKey
190     Push $5
191   
192     ${Do}
193       ${Select} $8
194         ${Case} 0
195           SetShellVarContext all
196           ${If} ${RunningX64}
197             SetRegView 64
198           ${Else}
199             IntOp $8 $8 + 1
200           ${EndIf}
201         ${Case} 1
202           SetShellVarContext all
203           ${If} ${RunningX64}
204             SetRegView 32
205           ${EndIf}
206         ${Case} 2
207           SetShellVarContext current
208           ${If} ${RunningX64}
209             SetRegView 64
210           ${Else}
211             IntOp $8 $8 + 1
212           ${EndIf}
213         ${Case} 3
214           SetShellVarContext current
215           ${If} ${RunningX64}
216             SetRegView 32
217           ${EndIf}
218       ${EndSelect}
219       ${SearchRegistry} $5 $9 $6 $7 $9
220       ${If} $5 != ""
221         ${Break}
222       ${EndIf}
223       IntOp $8 $8 + 1
224       StrCpy $9 0
225     ${LoopUntil} $8 >= 4
226   
227     Exch $5 # resultVar
228     Exch 4
229     Pop $7
230     Pop $6
231     Exch $9 # resultRegIdx
232     Exch
233     Exch $8 # resultStateIdx
234   FunctionEnd
235   
236   Function SearchRegistry
237     Exch $9 # startRegIdx
238     Exch
239     Exch $8 # searchFor
240     Exch 2
241     Exch $7 #subKey
242     Push $6
243     Push $5
244   
245     ${Do}
246       EnumRegKey $6 SHCTX $7 $9
247       ${StrStr} $5 $6 $8
248       IntOp $9 $9 + 1
249       ${If} $5 != ""
250         ${Break}
251       ${EndIf}
252     ${LoopUntil} $6 == ""
253   
254     Exch $5 # resultVar
255     Exch 4
256     Pop $8
257     Pop $6
258     Pop $7
259     Exch $9 # resultRegIdx
260   FunctionEnd
261   
262   !macro PrepareShellCTX
263     ${if} $MultiUser.InstallMode == "CurrentUser"
264       SetShellVarContext current
265     ${Else}
266       SetShellVarContext all
267     ${EndIf}
268     ${If} ${RunningX64}
269       SetRegView ${APP_ARCHITECTURE}
270     ${EndIf}
271   !macroend
272
273   Function PrepareShellCTX
274     !insertmacro PrepareShellCTX
275   FunctionEnd
276
277   Function un.PrepareShellCTX
278     !insertmacro PrepareShellCTX
279   FunctionEnd
280
281 #-------------------------------------------------------------
282 # - - - - - - - - - - - - Sections - - - - - - - - - - - - - -
283 #-------------------------------------------------------------
284
285 # ============ Installer Page Functions ============
286
287 Function .onInit # Callback function, called at the very beginning, when user double clicks on the installer
288
289   !if ${APP_ARCHITECTURE} = 64 # If 64 bit installer
290     # Abort if not 64 bit Windows
291     ${IfNot} ${RunningX64}
292       MessageBox MB_OK|MB_ICONSTOP "Cannot install a 64 bit application on 32 bit Windows, please use the 32 bit installer" /SD IDOK
293       Quit
294     ${EndIf}
295   !EndIf
296
297   # Check Windows version
298   ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
299   ${if} $0 S<= "6.0" # Atleast Win7 is needed
300     MessageBox MB_OK|MB_ICONSTOP "LyX ${APP_VERSION} requires Windows 7 or newer." /SD IDOK
301     Quit
302   ${endif}
303
304   Call PrepareShellCTX # MULTIUSER_INIT should search in the right registry view
305   !insertmacro MULTIUSER_INIT # Verify multiuser privileges
306
307   # Check if the same version of LyX is installed anywhere (admin/user, x64/x32) on the computer
308   StrCpy $1 0
309   StrCpy $2 0
310   ${DoUntil} $1 >= 4
311     ${SearchAllRegistry} $0 $1 $2 "SOFTWARE\LyX" ${APP_VERSION_DOTLESS} $1 $2 # Helper Function from above
312     ${If} $0 == ${APP_VERSION_DOTLESS}
313       ReadRegStr $0 SHCTX "SOFTWARE\LYX\$0" ""
314       ${If} ${FileExists} "$0\Uninstall-LyX.exe"
315         ${IfCmd} MessageBox MB_YESNO|MB_DEFBUTTON2|MB_ICONEXCLAMATION "$(AlreadyInstalled)" /SD IDNO IDNO ${||} Quit ${|}
316       ${Else}
317         DeleteRegKey SHCTX "SOFTWARE\LYX\$0"
318       ${EndIf}
319     ${EndIf}
320   ${Loop} 
321
322   # Check if a newer version of the same LyX series is installed anywhere (admin/user, x64/x32) on the computer
323   StrCpy $1 0
324   StrCpy $2 0
325   ${DoUntil} $1 >= 4
326     ${SearchAllRegistry} $R9 $1 $2 "SOFTWARE\LyX" "${VERSION_MAJOR}${VERSION_MINOR}" $1 $2 # Helper Function from above
327     StrCpy $OldVersionNumber $R9 # FIXME remove
328     ${If} $R9 S> ${APP_VERSION_DOTLESS} # $R9 is used in $(NewerInstalled)
329       ReadRegStr $0 SHCTX "SOFTWARE\LYX\$0" ""
330       ${If} ${FileExists} "$0\Uninstall-LyX.exe"
331         MessageBox MB_OK|MB_ICONSTOP "$(NewerInstalled)" /SD IDOK
332         Quit
333       ${Else}
334         DeleteRegKey SHCTX "SOFTWARE\LYX\$0"
335       ${EndIf}
336     ${EndIf}
337   ${Loop}
338 FunctionEnd
339
340 Function CheckIfRunning # Check that LyX in $INSTDIR is not currently running, called from Function VerifyInstDir and Section -CheckSilent (if silentinstall)
341   ${If} ${RunningX64}
342     ${DisableX64FSRedirection} # We need the following process to be 64 bit on 64 bit system
343   ${EndIf}
344   nsExec::ExecToStack "powershell (Get-Process LyX).Path"
345   Pop $0 # Exit code
346   Pop $0 # Result string
347   ${If} ${RunningX64}
348     ${EnableX64FSRedirection} # Need to be anabled asap or installer might crash
349   ${EndIf}
350   ${StrStr} $0 $0 "$INSTDIR\bin\LyX.exe"
351   ${If} $0 != ""
352     MessageBox MB_OK|MB_ICONSTOP "$(UnInstallRunning)" /SD IDOK
353     Abort # Abort leaving the page (when called from the page callback) / Abort install (when called from the section)
354   ${EndIf}
355 FunctionEnd
356
357 Function VerifyInstDir # Custom Function, called when leaving directory page
358   # if the $INSTDIR does not contain "LyX" we must add a subfolder to avoid that LyX will e.g.
359   # be installed directly to "C:\Program Files" - the uninstaller will then delete the whole
360   # "C:\Program Files" directory
361   ${StrStr} $0 $INSTDIR LyX
362   ${If} $0 == ""
363     StrCpy $INSTDIR "$INSTDIR\${MULTIUSER_INSTALLMODE_INSTDIR}" # Append e.g. "LyX 2.3" to $INSTDIR
364     ${NSD_SetText} $mui.DirectoryPage.Directory $INSTDIR # Refresh Textbox
365     Abort # Abort leaving the page
366   ${EndIf}
367
368   Call CheckIfRunning
369 FunctionEnd
370
371 Function RetrieveSMState # Custom function, called after the Startmenu page has been created
372   ${IfNot} ${FileExists} "$INSTDIR\Uninstall-LyX.exe"
373     Return # Not over-installing
374   ${Else}
375     ${GetFileVersion} "$INSTDIR\Uninstall-LyX.exe" $0
376     StrCpy $0 $0 3 # get only the first 3 chars, e.g. "2.3"
377     ${If} $0 != "${VERSION_MAJOR}.${VERSION_MINOR}"
378       Return # Installing over a wrong version
379     ${EndIf}
380   ${EndIf}
381
382   Call PrepareShellCTX # Helper function from above
383   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "SMDir${VERSION_MAJOR}${VERSION_MINOR}"
384   ${If} $0 == ""
385     ${If} ${Silent}
386       StrCpy $StartMenuFolder ">$StartMenuFolder"
387     ${Else}
388       GetDlgItem $0 $mui.StartMenuPage 1005 # Get the HWND of the checkbox, MUI2 does not provide variable for that
389       ${NSD_GetState} $0 $1
390       ${If} $1 = ${BST_UNCHECKED}
391         SendMessage $0 ${BM_CLICK} 0 0 # NSIS delivers no other possibility here other than to send a click event to the checkbox
392       ${EndIf}
393     ${EndIf}
394   ${EndIf}
395 FunctionEnd
396
397 Function LatexFolder_Show # Custom Function, called before showing the LaTeXFolder page to create it
398   Call FindLatex # detect latex  
399   Pop $0 # Result string from FindLatex
400   # $0 should contain the path to latex.exe, it is used in the fnc_LaTeXFolder_Create
401   ${StrStr} $1 $0 "\latex.exe"
402   ${If} $1 != "" # If latex was actually found
403     ${StrRep} $0 $0 $1 ""
404     # $R9 is used in $(EnterLaTeXFolder) on the page
405     ${StrStr} $1 $0 "\miktex\bin"
406     ${If} $1 != ""
407       StrCpy $R9 "MiKTeX"
408     ${Else}
409       StrCpy $R9 "TeXLive"
410     ${EndIf}
411     StrCpy $LaTeXName $R9 # FIXME remove
412     StrCpy $1 $(EnterLaTeXFolder) # $1 is used on the page
413   ${Else}
414     StrCpy $1 $(EnterLaTeXFolderNone)
415   ${EndIf}
416   ${StrRep} $1 $1 "\r\n" "$\r$\n" # FIXME remove
417
418   Call fnc_LaTeXFolder_Show # In LaTeXFolder.nsdinc, defined by NSIS Dialog Designer
419 FunctionEnd
420
421 Function FindLatex # Searches latex.exe, called from pre and leave functions of latexfolder page
422   # Find "LaTeX Path" value in registry written by a previous installment of the same LyX series, prioritized, because could be user preference
423   Call PrepareShellCTX
424   ${If} ${RunningX64}
425     SetRegView 64
426   ${EndIf}
427   StrCpy $1 0
428   StrCpy $2 0
429   ${DoUntil} $2 > 1
430     ${SearchRegistry} $0 $1 "SOFTWARE\LyX" "${VERSION_MAJOR}${VERSION_MINOR}" $1
431     ${If} $0 != ""
432       ReadRegStr $0 SHCTX "SOFTWARE\LyX\$0" "LaTeX Path"
433       StrCpy $0 "$0\latex.exe"
434       ${If} ${FileExists} $0
435         Push $0
436         Return
437       ${EndIf}
438     ${ElseIf} ${RunningX64}
439       IntOp $2 $2 + 1
440       SetRegView 32
441     ${Else}
442       ${Break}
443     ${EndIf}
444   ${Loop}
445
446   nsExec::ExecToStack "where latex.exe" # Ask CMD to find "latex.exe" for us, works if latexpath is added to PATH
447   Pop $0 # Exit code: 0 = success, 1 = fail
448   ${If} $0 = 0
449     Return
450   ${EndIf}
451   Pop $0 # If search failed, this is garbage, otherwise path to latex
452
453   # Search the registry for TexLive
454   StrCpy $1 0
455   StrCpy $2 0
456   ${DoUntil} $1 >= 4
457     ${SearchAllRegistry} $0 $1 $2 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" "TeXLive" $1 $2 # Helper Function from above
458     ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$0" "UninstallString"
459     ${StrRep} $0 $0 '"' ""
460     ${StrRep} $0 $0 "tlpkg\installer\uninst.bat" "bin\win32\latex.exe" # TeXLive is not 64 bit yet
461     ${If} ${FileExists} $0
462       Push $0
463       Return
464     ${EndIf}
465   ${Loop}
466
467   # Search the registry for MiKTex  
468   StrCpy $1 0
469   StrCpy $2 0
470   ${DoUntil} $1 >= 4
471     ${SearchAllRegistry} $0 $1 $2 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" "MiKTeX" $1 $2 # Helper Function from above
472     ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$0" "InstallLocation"
473     StrCpy $0 "$0\miktex\bin\latex.exe"
474     ${If} ${FileExists} $0
475       Push $0
476       Return
477     ${EndIf}
478     ${If} ${RunningX64} # MiKTeX can also be x64
479       ${StrRep} $0 $0 "latex.exe" "x64\latex.exe"
480       ${If} ${FileExists} $0
481         Push $0
482         Return
483       ${EndIf}
484     ${EndIf}
485   ${Loop}
486
487   # No latex was found
488   Push "C:\"
489
490 FunctionEnd
491
492 Function LatexFolder_Leave # Custom function, called when trying to leave LatexFolder page to verify that "latex.exe" really exists in the given path
493   ${NSD_GetText} $hCtl_LaTeXFolder_DirRequest1_Txt $LatexPath
494   ${NSD_GetState} $hCtl_LaTeXFolder_CheckBox1 $0
495
496   ${If} $0 = ${BST_CHECKED}
497     StrCpy $LatexPath ""
498   ${ElseIfNot} ${FileExists} "$LatexPath\latex.exe"
499     MessageBox MB_OK $(InvalidLaTeXFolder)
500     Call FindLatex # Search for latex again
501     Pop $0 # Result string from FindLatex
502     ${StrStrAdv} $0 $0 "\latex.exe" ">" "<" "0" "0" "0" # Get everything before "\latex.exe"
503     ${NSD_SetText} $hCtl_LaTeXFolder_DirRequest1_Txt $0 # Refresh textbox
504     Abort # Abort leaving the page
505   ${EndIf}
506 FunctionEnd
507
508 # ========= Installer Sections =========
509
510 Section -CheckSilent # This section checks if it's a silent install and calls needed callback- and custom-pagefunctions, which are not called in this case
511   ${IfNot} ${Silent}
512     Return
513   ${EndIf}
514
515   # .onInit is called
516
517   Call CheckIfRunning
518
519   Call RetrieveSMState
520
521   Call FindLatex # Search for latex
522   Pop $0 # Result string from FindLatex
523   ${StrStrAdv} $0 $0 "\latex.exe" ">" "<" "0" "0" "0" # Get everything before "\latex.exe"
524   ${If} ${FileExists} "$0\latex.exe"
525     StrCpy $LatexPath $0
526   ${Else}
527     MessageBox MB_OK $(InvalidLaTeXFolder)
528     Quit
529   ${EndIf}
530
531   Call DefaultDesktopFileAssoc
532 SectionEnd
533
534 Section -UninstallOld
535   ${If} ${FileExists} "$INSTDIR\Uninstall-LyX.exe"
536     ${GetFileVersion} "$INSTDIR\Uninstall-LyX.exe" $0
537     StrCpy $0 $0 3 # get only the first 3 chars, e.g. "2.3"
538     ${If} $0 != "${VERSION_MAJOR}.${VERSION_MINOR}"
539       ExecWait "$INSTDIR\Uninstall-LyX.exe /S _?=$INSTDIR" # silently uninstall old LyX
540       Delete "$INSTDIR\Uninstall-LyX.exe"
541     ${EndIf}
542   ${EndIf}
543 SectionEnd
544
545 Section -OverInstallReg # If over-installing, we need to delete the registry keys written by the previous installment
546   Call PrepareShellCTX # Helper function from above
547   StrCpy $1 0
548   ${Do}
549     EnumRegKey $2 SHCTX "SOFTWARE\LyX" $1
550     ${StrStr} $3 $2 "${VERSION_MAJOR}${VERSION_MINOR}"
551     ReadRegStr $0 SHCTX "SOFTWARE\LyX\$3" ""
552     ${If} $0 == $INSTDIR
553       DeleteRegKey SHCTX "SOFTWARE\LyX\$3"
554       DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX$3"
555     ${EndIf}
556     IntOp $1 $1 + 1
557   ${LoopUntil} $2 == ""
558 SectionEnd
559
560 Section -ProgramFiles
561
562   # Install the core LyX files
563   
564   # Initializes the plug-ins dir ($PLUGINSDIR) if not already initialized.
565   # $PLUGINSDIR is automatically deleted when the installer exits.
566   InitPluginsDir
567   
568   # Binaries
569   SetOutPath "$INSTDIR\bin"
570   File "${FILES_LYX}\bin\LyX.exe"
571   File "${FILES_LYX}\bin\tex2lyx.exe"
572   # Visual C++ redistributable (if native build)
573   File "${FILES_DEPS}\bin\concrt140.dll"
574   File "${FILES_DEPS}\bin\msvcp140.dll"
575   File "${FILES_DEPS}\bin\msvcp140_1.dll"
576   File "${FILES_DEPS}\bin\vcamp140.dll"
577   File "${FILES_DEPS}\bin\vccorlib140.dll"
578   File "${FILES_DEPS}\bin\vcomp140.dll"
579   File "${FILES_DEPS}\bin\vcruntime140.dll"
580   !if ${APP_ARCHITECTURE} = 64
581     File "${FILES_DEPS}\bin\vcruntime140_1.dll"
582   !endif
583   # MinGW redistributable (if cross platform with MinGW)
584   #File "${FILES_DEPS}\bin\iconv.dll"
585   #File "${FILES_DEPS}\bin\libbz2-1.dll"
586   #File "${FILES_DEPS}\bin\libfreetype-6.dll"
587   #File "${FILES_DEPS}\bin\libgcc_s_sjlj-1.dll"
588   #File "${FILES_DEPS}\bin\libglib-2.0-0.dll"
589   #File "${FILES_DEPS}\bin\libharfbuzz-0.dll"
590   #File "${FILES_DEPS}\bin\libintl-8.dll"
591   #File "${FILES_DEPS}\bin\libjpeg-62.dll"
592   #File "${FILES_DEPS}\bin\libpcre-1.dll"
593   #File "${FILES_DEPS}\bin\libpcre2-16-0.dll"
594   #File "${FILES_DEPS}\bin\libpng16-16.dll"
595   #File "${FILES_DEPS}\bin\libstdc++-6.dll"
596   #File "${FILES_DEPS}\bin\libtiff-5.dll"
597   #File "${FILES_DEPS}\bin\libwinpthread-1.dll"
598   #File "${FILES_DEPS}\bin\libwebp-7.dll"
599   #File "${FILES_DEPS}\bin\libwebpdemux-2.dll"
600   #File "${FILES_DEPS}\bin\zlib1.dll"
601   # Netpbm
602   File "${FILES_DEPS}\bin\libnetpbm10.dll"
603   File "${FILES_DEPS}\bin\pnmcrop.exe"
604   # Rsvg
605   File "${FILES_DEPS}\bin\rsvg-convert.exe"
606   # Pdfview
607   File "${FILES_DEPS}\bin\pdfview.exe"
608   # Qt libraries
609   File "${FILES_QT}\bin\Qt5Concurrent.dll"
610   File "${FILES_QT}\bin\Qt5Core.dll"
611   File "${FILES_QT}\bin\Qt5Gui.dll"
612   File "${FILES_QT}\bin\Qt5Network.dll"
613   File "${FILES_QT}\bin\Qt5OpenGL.dll"
614   File "${FILES_QT}\bin\Qt5PrintSupport.dll"
615   File "${FILES_QT}\bin\Qt5Svg.dll"
616   File "${FILES_QT}\bin\Qt5Widgets.dll"
617   File "${FILES_QT}\bin\Qt5WinExtras.dll"
618
619   # Qt plugin DLLs
620   SetOutPath "$INSTDIR\bin\imageformats"
621   File "${FILES_QT}\bin\imageformats\qgif.dll"
622   File "${FILES_QT}\bin\imageformats\qico.dll"
623   File "${FILES_QT}\bin\imageformats\qjpeg.dll"
624   File "${FILES_QT}\bin\imageformats\qsvg.dll"
625   File "${FILES_QT}\bin\imageformats\qicns.dll"
626   File "${FILES_QT}\bin\imageformats\qtiff.dll"
627   File "${FILES_QT}\bin\imageformats\qwbmp.dll"
628   File "${FILES_QT}\bin\imageformats\qwebp.dll"
629
630   SetOutPath "$INSTDIR\bin\iconengines"
631   File "${FILES_QT}\bin\iconengines\qsvgicon.dll"
632
633   SetOutPath "$INSTDIR\bin\platforms"
634   File "${FILES_QT}\bin\platforms\qminimal.dll"
635   File "${FILES_QT}\bin\platforms\qwindows.dll"
636
637   SetOutPath "$INSTDIR\bin\styles"
638   File "${FILES_QT}\bin\styles\qwindowsvistastyle.dll"
639
640   # Resources
641   SetOutPath "$INSTDIR\Resources"
642   # recursively copy all files under Resources
643   File /r "${FILES_LYX}\Resources\"
644   File /r "${FILES_DEPS}\Resources\" # Already present files will be skiped
645
646   # Python
647   SetOutPath "$INSTDIR\Python"
648   # recursively copy all files under Python
649   File /r "${FILES_DEPS}\Python\"
650
651   # Components of ImageMagick
652   SetOutPath "$INSTDIR\imagemagick"
653   File /r "${FILES_DEPS}\imagemagick\"
654
655   # Components of Ghostscript
656   SetOutPath "$INSTDIR\ghostscript"
657   File /r "${FILES_DEPS}\ghostscript\"
658
659   # Install unoconv
660   SetOutPath "$INSTDIR\Python\Lib"
661   File "${FILES_DEPS}\bin\unoconv.py"
662   
663   WriteUninstaller "$INSTDIR\Uninstall-LyX.exe"
664 SectionEnd
665
666 Section -TexRessources # Section installs cls files from Ressources\tex and updates latex filebase
667   # First make sure that latex was found in LatexFolder_Leave function
668   ${If} $LatexPath == ""
669     Return
670   ${EndIf}
671
672   # Miktex or Texlive?
673   ${StrStr} $0 $LatexPath "\miktex\bin"
674   ${If} $0 == "" # TexLive
675     ${StrRep} $0 $LatexPath "\bin\win32" "\texmf-dist\tex\latex\lyx"
676     ${If} ${FileExists} "$0\broadway.cls"
677       Return
678     ${EndIf}
679     CopyFiles /SILENT "$INSTDIR\Resources\tex\*.*" $0
680     ExecWait '$LatexPath\texhash' # Update package file list
681
682   ${Else} # Miktex
683     ${StrRep} $0 $LatexPath $0 "\tex\latex\lyx"
684     ${If} ${FileExists} "$0\broadway.cls"
685       Return
686     ${EndIf}
687     CopyFiles /SILENT "$INSTDIR\Resources\tex\*.*" $0 # First try to put into Miktex install dir
688
689     ${IfNot} ${FileExists} "$0\broadway.cls" # Check if copying succeeded
690       # Didn't suceed to put into install dir, put into users dir
691       nsExec::ExecToStack "$LatexPath\mpm.exe --version" # get the Miktex version
692       Pop $0 # Exit code
693       Pop $0 # Result
694       ${StrStrAdv} $0 $0 "MiKTeX Package Manager " ">" ">" "0" "0" "0" # $0 contains "2.9.7420 ......" now (everything after "MiKTeX Package Manager ")
695       ${StrStrAdv} $0 $0 "." ">" "<" "0" "1" "0" # $0 contains "2.9" now (everything before the second dot)
696       SetShellVarContext current
697       ${If} ${FileExists} "$APPDATA\MiKTeX\$0\tex\latex\lyx\broadway.cls" # UserInstall-dir can not be changed in Miktex currently, so this should work
698         Return
699       ${EndIf}
700       CopyFiles /SILENT "$INSTDIR\Resources\tex\*.*" "$APPDATA\MiKTeX\$0\tex\latex\lyx" # Put into user install dir
701     ${EndIf}
702
703     # Update package file list
704     nsExec::ExecToLog "$LatexPath\initexmf.exe --admin --update-fndb" # Try as admin
705     Pop $0 # Exit code
706     ${If} $0 <> 0 # Not successful
707       nsExec::ExecToLog "$LatexPath\initexmf.exe --update-fndb" # Do as user
708       Pop $0
709     ${EndIf}
710   ${EndIf}
711 SectionEnd
712
713 Section -CompilePython
714   # Compile all Python files to byte-code
715   # The user using the scripts may not have write access
716   FileOpen $R0 "$INSTDIR\compilepy.py" w
717   FileWrite $R0 "import compileall$\r$\n"
718   FileWrite $R0 "compileall.compile_dir('$INSTDIR\python\Lib')$\r$\n"
719   FileWrite $R0 "compileall.compile_dir('$INSTDIR\Resources')$\r$\n"
720   FileClose $R0
721   DetailPrint $(TEXT_CONFIGURE_PYTHON)
722   nsExec::ExecToLog '"$INSTDIR\python\python.exe" "$INSTDIR\compilepy.py"'
723   Pop $0 # Exit code
724   Delete "$INSTDIR\compilepy.py"
725 SectionEnd
726
727 Section -LyxrcDist
728   StrCpy $pathPrefix "$LatexPath;$$LyXDir\bin;$$LyXDir\Python;$$LyXDir\Python\Lib;$$LyXDir\imagemagick;$$LyXDir\ghostscript\bin"
729
730   # Find additional software and add their install locations to the path_prefix
731   # This list contains all software, which write the string value "InstallLocation" in their corresponding keys in "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
732   # To add additional software matching this requirement, just append it to the string after "${List.Append} editors "
733   ${List.Create} editors
734   ${List.Append} editors "jEdit,PSPad,WinShell,TeXnicCenter,WinEdt"
735   ${List.Count} $R1 editors
736   IntOp $R1 $R1 - 1
737   ${For} $R2 0 $R1
738     ${List.Get} $0 editors $R2
739     ${SearchAllRegistry} $0 $1 $1 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" $0 0 0 # Helper Function from above
740     ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$0" "InstallLocation"
741     ${If} $0 != ""
742       StrCpy $1 $0 "" -1 # Get the last char
743       ${If} $1 == "\" # If ends with "\"
744         StrCpy $0 $0 -1 # Remove "\"
745       ${EndIf}
746       StrCpy $pathPrefix "$pathPrefix;$0"
747     ${EndIf}
748   ${Next}
749   ${List.Destroy} editors
750
751   # Following Software does not create "InstallLocation"
752   # Vim  
753   ${SearchAllRegistry} $0 $1 $1 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" "Vim" 0 0 # Helper Function from above
754   ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$0" "DisplayIcon"
755   ${StrStrAdv} $0 $0 "\gvim.exe" ">" "<" "0" "0" "0" # get everything before "\gvim.exe"
756   ${If} $0 != ""
757     StrCpy $pathPrefix "$pathPrefix;$0"
758   ${EndIf}
759
760   # JabRef, Hard to locate, JabRef uses MSI installer, lets try to find it through the .bib extension
761   SetShellVarContext all
762   ${If} ${RunningX64}
763     SetRegView 64
764   ${EndIf}
765   ${For} $R1 0 1 # Try as admin and then as user
766     ReadRegStr $0 SHCTX "SOFTWARE\Classes\.bib" ""
767     ReadRegStr $0 SHCTX "Software\Classes\$0\shell\open\command" ""
768     ${StrRep} $0 $0 '"' "" # Remove quotes
769     ${StrStrAdv} $0 $0 "\JabRef.exe" ">" "<" "0" "0" "0" # Get everything before "\JabRef.exe"
770     ${If} ${FileExists} "$0\JabRef.exe"
771       StrCpy $pathPrefix "$pathPrefix;$0"
772       ${Break}
773     ${EndIf}
774     SetShellVarContext current # Retry as user
775   ${Next}
776
777   # Gnumeric
778   SetShellVarContext all
779   ${If} ${RunningX64}
780     SetRegView 64
781   ${EndIf}
782   ${For} $R1 0 1 # Try as admin and then as user
783     ReadRegStr $0 SHCTX "Software\Classes\Applications\gnumeric.exe\shell\Open\command" ""
784     ${StrRep} $0 $0 '"' "" # Remove quotes
785     ${StrStrAdv} $0 $0 "\gnumeric.exe" ">" "<" "0" "0" "0" # Get everything before "\gnumeric.exe"
786     ${If} $0 != ""
787       StrCpy $pathPrefix "$pathPrefix;$0"
788       ${Break}
789     ${EndIf}
790     SetShellVarContext current # Retry as user
791   ${Next}
792
793   # Pandoc, same as JabRef, can only attempt to ask cmd if added to PATH, the user can't disable that while installing pandoc though
794   nsExec::ExecToStack "where pandoc.exe"
795   Pop $1 # Exit code
796   Pop $0 # Return sring
797   ${If} $1 = 0
798     ${StrStrAdv} $0 $0 "\pandoc.exe" ">" "<" "0" "0" "0" # Get everything before "\pandoc.exe"
799     ${If} $0 != ""
800       StrCpy $pathPrefix "$pathPrefix;$0"
801     ${EndIf}
802   ${EndIf}
803
804   ${Map.Create} softwarePathsMap # Create a map (NSISList plugin) to temp store paths of 3rd party software
805
806   # LilyPond
807   ${SearchAllRegistry} $0 $1 $1 "SOFTWARE" "LilyPond" 0 0 # Helper Function from above
808   ReadRegStr $0 SHCTX "SOFTWARE\$0" "Install_Dir"
809   ${If} $0 != ""
810     StrCpy $pathPrefix "$pathPrefix;$0\usr\bin"
811     ${Map.Set} softwarePathsMap "LilyPond" "$0\usr\bin"
812   ${EndIf}
813
814   # Gimp
815   ${SearchAllRegistry} $2 $1 $1 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" "GIMP" 0 0 # Helper Function from above
816   ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$2" "InstallLocation"
817   ${If} $0 != ""
818     StrCpy $pathPrefix "$pathPrefix;$0bin" # Install Location ends with '\' for Gimp in Registry
819     ReadRegStr $0 SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$2" "DisplayIcon"
820     ${StrStrAdv} $0 $0 ".exe" ">" "<" "0" "0" "0" # Get everything before the ".exe"
821     ${StrStrAdv} $0 $0 "\" "<" ">" "0" "0" "0" # Get everything after the last "\", $0 contains "gimp-10" now
822     ${Map.Set} softwarePathsMap "ImageEditor" $0
823   ${EndIf}
824
825   # Krita
826   ${SearchAllRegistry} $0 $1 $1 "SOFTWARE" "Krita" 0 0 # Helper Function from above
827   ReadRegStr $0 SHCTX "SOFTWARE\$0" "InstallLocation"
828   ${If} $0 != ""
829     StrCpy $pathPrefix "$pathPrefix;$0\bin"
830     ${Map.Set} softwarePathsMap "ImageEditor" "krita"
831   ${EndIf}
832
833   # Photoshop
834   SetShellVarContext all
835   ${If} ${RunningX64}
836     SetRegView 64
837   ${EndIf}
838   ${For} $R1 0 1 # Try as admin and then as user
839     ReadRegStr $0 SHCTX "Software\Classes\Applications\Photoshop.exe\shell\Open\command" ""
840     ${StrRep} $0 $0 '"' "" # Remove quotes
841     ${StrStrAdv} $0 $0 "\photoshop.exe" ">" "<" "0" "0" "0" # Get everything before "\photoshop.exe"
842     ${If} $0 != ""
843       StrCpy $pathPrefix "$pathPrefix;$0"
844       ${Break}
845     ${EndIf}
846     SetShellVarContext current # Retry as user
847   ${Next}
848
849   ClearErrors
850
851   FileOpen $R0 "$INSTDIR\Resources\lyxrc.dist" a
852   FileSeek $R0 0 END
853   # set some general things
854   FileWrite $R0 '\screen_zoom 120$\r$\n'
855
856   FileWrite $R0 '\path_prefix "$pathPrefix"$\r$\n'
857   
858   # use pdfview for all types of PDF files
859   FileWrite $R0 '\format "pdf5" "pdf" "PDF (LuaTeX)" "u" "pdfview" "" "document,vector,menu=export" "application/pdf"$\r$\n\
860                 \format "pdf4" "pdf" "PDF (XeTeX)" "X" "pdfview" "" "document,vector,menu=export" "application/pdf"$\r$\n\
861                 \format "pdf3" "pdf" "PDF (dvipdfm)" "m" "pdfview" "" "document,vector,menu=export" "application/pdf"$\r$\n\
862                 \format "pdf2" "pdf" "PDF (pdflatex)" "F" "pdfview" "" "document,vector,menu=export" "application/pdf"$\r$\n\
863                 \format "pdf" "pdf" "PDF (ps2pdf)" "P" "pdfview" "" "document,vector,menu=export" "application/pdf"$\r$\n'
864
865   # If krita or gimp was found previously
866   ${Map.Get} $0 softwarePathsMap "ImageEditor"
867   ${If} $0 != "__NULL" # If "ImageEditor" is set in map    
868     FileWrite $R0 '\format "gif" "gif" "GIF" "" "auto" "$0" "" "image/gif"$\r$\n\
869                   \format "jpg" "jpg, jpeg" "JPEG" "" "auto" "$0" "" "image/jpeg"$\r$\n\
870                   \format "png" "png" "PNG" "" "auto" "$0" "" "image/x-png"$\r$\n'
871   ${EndIf}
872   
873   FileWrite $R0 '\converter "wmf" "eps" "magick -density 300 $$$$i $$$$o" ""$\r$\n\
874     \converter "emf" "eps" "magick -density 300 $$$$i $$$$o" ""$\r$\n'
875
876   # If LilyPond was found previously
877   ${Map.Get} $0 softwarePathsMap "LilyPond"
878   ${If} $0 != "__NULL" # If "LilyPond" is set in map
879     FileWrite $R0 '\format "lilypond-book" "lytex" "LilyPond book (LaTeX)" "" "" "auto" "document,menu=export" ""$\r$\n\
880                   \converter "lilypond-book" "pdflatex" "python \"$0\\lilypond-book.py\" --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$$$i" ""$\r$\n\
881                   \converter "lilypond-book" "xetex" "python \"$0\\lilypond-book.py\" --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$$$i" ""$\r$\n\
882                   \converter "lilypond-book" "luatex" "python \"$0\\lilypond-book.py\" --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$$$i" ""$\r$\n\
883                   \converter "lilypond-book" "latex" "python \"$0\\lilypond-book.py\" --safe --lily-output-dir=ly-eps $$$$i" ""$\r$\n'
884   ${EndIf}
885
886   ${Map.Destroy} softwarePathsMap
887
888   FileClose $R0
889   
890   ${If} ${Errors}
891     MessageBox MB_OK|MB_ICONEXCLAMATION "$(ModifyingConfigureFailed)" /SD IDOK
892     ClearErrors
893   ${EndIf}
894 SectionEnd
895
896 Section "$(SecFileAssocTitle)" SecFileAssoc # Registry information to assiciate ".lyx" extension with this LyX installation
897   Call PrepareShellCTX # Helper function from above
898
899   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\LyX.exe" "" "$INSTDIR\bin\LyX.exe" # Writes in both 64 and 32 bit registry
900   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\LyX.exe" "Version" ${APP_VERSION} # Writes in both 64 and 32 bit registry
901   
902   WriteRegStr SHCTX "Software\Classes\.lyx" "" "LyX.Document"
903   WriteRegStr SHCTX "Software\Classes\.lyx" "Content Type" "application/lyx"
904
905   WriteRegStr SHCTX "Software\Classes\LyX.Document" "" "LyX Document"
906   WriteRegStr SHCTX "Software\Classes\LyX.Document\DefaultIcon" "" "$INSTDIR\bin\LyX.exe,1"
907   WriteRegStr SHCTX "Software\Classes\LyX.Document\Shell\open\command" "" '"$INSTDIR\bin\LyX.exe" "%1"'
908
909   # we need to update also the automatically created entry about the lyx.exe
910   # otherwise .lyx-files will could be opened with an older LyX version
911   ReadRegStr $0 SHCTX "Software\Classes\Applications\LyX.exe\shell\open\command" ""
912   ${if} $0 != "" # if something was found
913     WriteRegStr SHCTX "Software\Classes\Applications\LyX.exe\shell\open\command" "" '"$INSTDIR\bin\LyX.exe" "%1"'
914   ${endif}
915
916   WriteRegStr SHCTX "SOFTWARE\LyX" "FileAssoc${VERSION_MAJOR}${VERSION_MINOR}" $INSTDIR # Save user preference for over-installing
917 SectionEnd
918
919 Section "$(SecDesktopTitle)" SecDesktop
920   SetOutPath "$INSTDIR\bin" # Need to set this so that the shortcut to lyx.exe is executed in the bin folder
921   CreateShortCut "$DESKTOP\LyX ${VERSION_MAJOR}.${VERSION_MINOR}.lnk" "$INSTDIR\bin\LyX.exe" "" "" "" "" "" "LyX - The Document Processor" # Last parameter is the comment of the shortcut
922   Call PrepareShellCTX
923   WriteRegStr SHCTX "SOFTWARE\LyX" "Desktop${VERSION_MAJOR}${VERSION_MINOR}" $INSTDIR # Save user preference for over-installing
924 SectionEnd
925
926 Section -StartMenuFolder # Creates starm menu shortcut and website links to lyx website and lyx wiki
927   Call PrepareShellCTX # Helper function from above, need to call be before the following macro, because the macro writes registry string (storing the default startmenu folder)
928   !insertmacro MUI_STARTMENU_WRITE_BEGIN startmenuPage # This macro also assures that the folder is not empty for us
929     SetOutPath "$INSTDIR\bin" # Need to set this so that the shortcut to lyx.exe is executed in the bin folder
930     CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
931     CreateShortCut "$SMPROGRAMS\$StartMenuFolder\LyX.lnk" "$INSTDIR\bin\LyX.exe" "" "" "" "" "" "LyX - The Document Processor" # Last parameter is the comment of the shortcut
932     SetOutPath $INSTDIR
933     CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall LyX.lnk" "$INSTDIR\Uninstall-LyX.exe"
934     WriteINIStr "$SMPROGRAMS\$StartMenuFolder\LyX Website.url" "InternetShortcut" "URL" "https://www.lyx.org/"
935     WriteINIStr "$SMPROGRAMS\$StartMenuFolder\LyX Wiki.url" "InternetShortcut" "URL" "https://wiki.lyx.org"
936   !insertmacro MUI_STARTMENU_WRITE_END
937 SectionEnd
938
939 !include "src\dictionaries.nsh"
940
941 Section -SoftwareRegistry # Registry information in "SOFTWARE" subkey
942   Call PrepareShellCTX # Helper function from above
943
944   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "latestVersion"
945   ${If} $0 S< ${APP_VERSION_DOTLESS}
946     WriteRegStr SHCTX "SOFTWARE\LyX" "latestVersion" ${APP_VERSION_DOTLESS}
947   ${EndIf}
948   WriteRegStr SHCTX "SOFTWARE\LyX\${APP_VERSION_DOTLESS}" "" $INSTDIR
949   WriteRegStr SHCTX "SOFTWARE\LyX\${APP_VERSION_DOTLESS}" "LaTeX Path" $LatexPath
950   WriteRegStr SHCTX "SOFTWARE\LyX" "InstDir${VERSION_MAJOR}${VERSION_MINOR}" $INSTDIR # Remember install dir for the next over-installment of the same series
951 SectionEnd
952
953 Section -UninstallInfoRegistry # Registry information in "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" subkey
954   Call PrepareShellCTX # Helper function from above
955
956   ${If} $MultiUser.InstallMode == "AllUsers"
957     WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "DisplayName" "LyX ${APP_VERSION}"
958   ${Else}
959     WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "DisplayName" "LyX ${APP_VERSION} $(TEXT_INSTALL_CURRENTUSER)"
960   ${EndIf}
961
962   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "UninstallString" '"$INSTDIR\Uninstall-LyX.exe"'
963   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "DisplayVersion" "${APP_VERSION}"
964   WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "VersionMajor" "${VERSION_MAJOR}"
965   WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "VersionMinor" "${VERSION_MINOR}"
966   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "DisplayIcon" "$INSTDIR\bin\LyX.exe"
967   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "URLUpdateInfo" "https://www.lyx.org/"
968   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "URLInfoAbout" "https://www.lyx.org/AboutLyX"
969   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "Publisher" "LyX Team"
970   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "HelpLink" "https://www.lyx.org/MailingLists"
971   WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "NoModify" 0x00000001
972   WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "NoRepair" 0x00000001
973   WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "InstallLocation" "$INSTDIR"
974
975   ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
976   IntFmt $0 "0x%08X" $0
977   WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}" "EstimatedSize" $0
978 SectionEnd
979
980 !if ${VERSION_MINOR} > 0 # Only valid for minor releases of the same major release (e.g. not valid for 3.0)
981   Section -CopyOldPreferences # Searches user's preferences (userdir) from previous minor release and copies it if necessary
982     Call PrepareShellCTX
983     SetShellVarContext current # Otherwise $APPDATA would return C:\ProgrammData instead of C:\Users\username\AppData\Roaming
984     
985     IntOp $0 ${VERSION_MINOR} - 1 # only check the direct previous minor release
986     ${If} ${FileExists} "$APPDATA\LyX${VERSION_MAJOR}.$0\lyxrc.defaults"
987     ${AndIfNot} ${FileExists} "$APPDATA\LyX${VERSION_MAJOR}.${VERSION_MINOR}\lyxrc.defaults"
988       CopyFiles /SILENT "$APPDATA\LyX${VERSION_MAJOR}.$0\*.*" "$APPDATA\LyX${VERSION_MAJOR}.${VERSION_MINOR}"
989     ${EndIf}
990   SectionEnd
991 !endif
992
993 Section -ConfigureScript # Runs the configure.py script
994
995   # Manipulate PATH environment of the running installer process, so that configure.py can find all the stuff needed
996   ReadEnvStr $0 "PATH"
997   ${StrRep} $pathPrefix $pathPrefix "$$LyXDir" "$INSTDIR"
998   System::Call 'Kernel32::SetEnvironmentVariable(t "PATH", t "$pathPrefix;$0")'
999   
1000   Call PrepareShellCTX
1001   SetShellVarContext current # Otherwise $APPDATA would return C:\ProgrammData instead of C:\Users\username\AppData\Roaming
1002   SetOutPath "$APPDATA\LyX${VERSION_MAJOR}.${VERSION_MINOR}" # Need to run configure from the user dir, because it creates .lst files and some folders.
1003
1004   ${StrStr} $0 $LatexPath "\miktex\bin"
1005   # R9 is used in $(TEXT_CONFIGURE_LYX)
1006   ${If} $0 == "" # TexLive
1007     StrCpy $R9 "TeXLive"
1008   ${Else}
1009     StrCpy $R9 "MiKTeX"
1010   ${EndIf}
1011   StrCpy $LaTeXInstalled $R9 # FIXME remove
1012   DetailPrint $(TEXT_CONFIGURE_LYX) # Uses R9 to display the name of the installed latex distribution
1013   
1014   nsExec::ExecToLog '"$INSTDIR\Python\python.exe" "$INSTDIR\Resources\configure.py"'
1015   Pop $0 # Return value
1016 SectionEnd
1017
1018 Function DefaultDesktopFileAssoc # Custom function, called before the components page, reads the states of SecDesktop and SecFileAssoc from registry (if overinstalling) and sets them
1019
1020   Call CheckDictionaries # Search for already installed dictionaries, in dictionaries.nsh
1021
1022   ${IfNot} ${FileExists} "$INSTDIR\Uninstall-LyX.exe"
1023     Return # Not over-installing
1024   ${Else}
1025     ${GetFileVersion} "$INSTDIR\Uninstall-LyX.exe" $0
1026     StrCpy $0 $0 3 # get only the first 3 chars, e.g. "2.3"
1027     ${If} $0 != "${VERSION_MAJOR}.${VERSION_MINOR}"
1028       Return # Installing over a wrong version
1029     ${EndIf}
1030   ${EndIf}
1031
1032   Call PrepareShellCTX
1033   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "FileAssoc${VERSION_MAJOR}${VERSION_MINOR}"
1034   ${If} $0 == ""
1035     SectionSetFlags ${SecFileAssoc} 0 # 0 means unselected
1036   ${EndIf}
1037   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "Desktop${VERSION_MAJOR}${VERSION_MINOR}"
1038   ${If} $0 == ""
1039     SectionSetFlags ${SecDesktop} 0 # 0 means unselected
1040   ${EndIf}
1041 FunctionEnd
1042
1043 Function StartLyX
1044   ShellExecAsUser::ShellExecAsUser "" "$INSTDIR\bin\LyX.exe"
1045 FunctionEnd
1046
1047 # Installer Section Descriptions
1048
1049 !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
1050   !insertmacro MUI_DESCRIPTION_TEXT ${SecFileAssoc} "$(SecFileAssocDescription)"
1051   !insertmacro MUI_DESCRIPTION_TEXT ${SecDesktop} "$(SecDesktopDescription)"
1052   !insertmacro MUI_DESCRIPTION_TEXT ${SecDictionaries} "$(SecDictionariesDescription)" # In dictionaries.nsh
1053   !insertmacro MUI_DESCRIPTION_TEXT ${SecThesaurus} "$(SecThesaurusDescription)" # In dictionaries.nsh
1054 !insertmacro MUI_FUNCTION_DESCRIPTION_END
1055
1056 # ===== Uninstaller ======
1057
1058 Function un.onInit # Callback function, called when the uninstaller initializes
1059   # Check that LyX is not currently running
1060   ${If} ${RunningX64}
1061     ${DisableX64FSRedirection} # We need the following process to be 64 bit on 64 bit system
1062   ${EndIf}
1063   nsExec::ExecToStack "powershell (Get-Process LyX).Path"
1064   Pop $0 # Exit code
1065   Pop $0 # Result string
1066   ${If} ${RunningX64}
1067     ${EnableX64FSRedirection} # Need to be enabled asap or installer might crash
1068   ${EndIf}
1069   ${UnStrStr} $0 $0 "$INSTDIR\bin\LyX.exe"
1070   ${If} $0 != ""
1071     MessageBox MB_OK|MB_ICONSTOP "$(UnInstallRunning)" /SD IDOK
1072     Quit # Quit uninstaller
1073   ${EndIf}
1074
1075   Call un.PrepareShellCTX
1076   !insertmacro MULTIUSER_UNINIT
1077
1078   # Ascertain whether the user has sufficient privileges to uninstall.
1079   # abort when LyX was installed with admin permissions but the user doesn't have administrator privileges
1080   Call un.PrepareShellCTX # Helperfunction from above
1081   ReadRegStr $0 HKLM "SOFTWARE\LyX\${APP_VERSION_DOTLESS}" ""
1082   ${If} $0 == $INSTDIR
1083     ${If} $MultiUser.Privileges != "Admin"
1084     ${AndIf} $MultiUser.Privileges != "Power"
1085       MessageBox MB_OK|MB_ICONSTOP "$(UnNotAdminLabel)" /SD IDOK
1086       Abort
1087     ${Else}
1088       StrCpy $MultiUser.InstallMode "AllUsers"
1089     ${EndIf}
1090   ${Else}
1091     ReadRegStr $0 HKCU "SOFTWARE\LyX\${APP_VERSION_DOTLESS}" ""
1092     ${If} $0 == ""
1093       MessageBox MB_OK|MB_ICONEXCLAMATION "$(UnNotInRegistryLabel)" /SD IDOK
1094     ${Else}
1095       StrCpy $MultiUser.InstallMode "CurrentUser"
1096     ${EndIf}
1097   ${EndIf}
1098
1099   # question message if the user really wants to uninstall LyX
1100   ${IfCmd} MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "$(UnReallyRemoveLabel)" /SD IDYES IDNO ${||} Quit ${|}
1101 FunctionEnd
1102
1103 Function un.ComponentsPre # Callback Function, called before the components page is loaded
1104   # R9 and R8 are used in $(SecUnPreferencesDescription)
1105   SetShellVarContext current
1106   ${UnStrStrAdv} $R9 $PROFILE "\" "<" "<" "0" "0" "0" # Get everything before the last "\" of $PROFILE ("C:\Users\username") -> $R9: "C:\Users"
1107   StrCpy $AppPre $R9 # FIXME remove
1108   ${UnStrRep} $R8 $APPDATA "$PROFILE\" "" # "C:\Users\username\" gets replaced with "" in "C:\Users\username\AppData\Roaming" -> $R8: "Appdata\Roaming"
1109   StrCpy $AppSuff $R8 # FIXME remove
1110 FunctionEnd
1111
1112 Section "un.LyX" un.SecUnProgramFiles # Deletes files in $INSTDIR and registry entries
1113   SectionIn RO
1114   # LaTeX class files that were installed together with LyX
1115   # will not be uninstalled because other LyX versions will
1116   # need them and these few files don't harm to stay in LaTeX 
1117
1118   Call un.PrepareShellCTX # Helperfunction from above
1119
1120   # Subfolders and unistaller
1121   RMDir /r "$INSTDIR\bin"
1122   RMDir /r "$INSTDIR\Resources"
1123   RMDir /r "$INSTDIR\Python"
1124   RMDir /r "$INSTDIR\imagemagick"
1125   RMDir /r "$INSTDIR\ghostscript"
1126   Delete "$INSTDIR\Uninstall-LyX.exe"
1127   # Install directory
1128   SetOutPath $PLUGINSDIR
1129   RMDir $INSTDIR
1130
1131   # Startmenu
1132   !insertmacro MUI_STARTMENU_GETFOLDER startmenuPage $StartMenuFolder # Reads registry value written with macro MUI_STARTMENU_WRITE_BEGIN
1133   ShellLink::GetShortCutTarget "$SMPROGRAMS\$StartMenuFolder\LyX.lnk" # Check if the shortcut really is pointing to the current installation
1134   Pop $0
1135   ${IfNot} ${FileExists} $0 # If still exists, then belongs to another lyx installment, so don't delete
1136     RMDir /r "$SMPROGRAMS\$StartMenuFolder"
1137     DeleteRegValue SHCTX "SOFTWARE\LyX" "SMDir${VERSION_MAJOR}${VERSION_MINOR}"
1138   ${EndIf}
1139
1140   # Desktop icon
1141   ShellLink::GetShortCutTarget "$DESKTOP\LyX ${VERSION_MAJOR}.${VERSION_MINOR}.lnk"
1142   Pop $0
1143   ${UnStrStr} $0 $0 $INSTDIR
1144   ${If} $0 != ""
1145     Delete "$DESKTOP\LyX ${VERSION_MAJOR}.${VERSION_MINOR}.lnk"
1146   ${EndIf}
1147   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "Desktop${VERSION_MAJOR}${VERSION_MINOR}"
1148   ${If} $0 == $INSTDIR
1149     DeleteRegValue SHCTX "SOFTWARE\LyX" "Desktop${VERSION_MAJOR}${VERSION_MINOR}"
1150   ${EndIf}
1151
1152   # File association
1153   ReadRegStr $0 SHCTX "Software\Classes\LyX.Document\DefaultIcon" ""
1154   ${UnStrStr} $0 $0 $INSTDIR
1155   ${If} $0 != ""
1156     DeleteRegKey SHCTX "Software\Classes\LyX.Document"
1157     DeleteRegKey SHCTX "Software\Classes\.lyx"
1158   ${EndIf}
1159   ReadRegStr $0 SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\LyX.exe" ""
1160   ${UnStrStr} $0 $0 $INSTDIR
1161   ${If} $0 != ""
1162     DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\LyX.exe" # Deletes key in both 64 and 32 bit registry
1163   ${EndIf}
1164   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "FileAssoc${VERSION_MAJOR}${VERSION_MINOR}"
1165   ${If} $0 == $INSTDIR
1166     DeleteRegValue SHCTX "SOFTWARE\LyX" "FileAssoc${VERSION_MAJOR}${VERSION_MINOR}"
1167   ${EndIf}
1168   DeleteRegKey SHCTX "Software\Classes\Applications\LyX.exe"
1169
1170   # Uninstaller info registry
1171   DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\LyX${APP_VERSION_DOTLESS}"
1172
1173   # Software registry
1174   DeleteRegKey SHCTX "SOFTWARE\LyX\${APP_VERSION_DOTLESS}"
1175   DeleteRegValue SHCTX "SOFTWARE\LyX" "latestVersion"
1176   ReadRegStr $0 SHCTX "SOFTWARE\LyX" "InstDir${VERSION_MAJOR}${VERSION_MINOR}"
1177   ${If} $0 == $INSTDIR
1178     DeleteRegValue SHCTX "SOFTWARE\LyX" "InstDir${VERSION_MAJOR}${VERSION_MINOR}"
1179   ${EndIf}
1180   DeleteRegValue SHCTX "SOFTWARE\LyX" "latestVersion"
1181   # Now that "latestVersion" is gone we need to find if there is another (newest) LyX version installed and write it's verion to "latestVersion"
1182   # The keys in the registry are sorted alphabetically, so we dont need to compare, the latest found will be the newest version
1183   StrCpy $0 0
1184   StrCpy $1 ""
1185   ${Do}
1186     StrCpy $2 $1
1187     EnumRegKey $2 SHCTX "SOFTWARE\LyX" $0
1188     IntOp $0 $0 + 1
1189   ${LoopUntil} $1 == ""
1190   ${If} $2 != ""
1191     WriteRegStr SHCTX "SOFTWARE\LyX" "latestVersion" $2
1192   ${EndIf}
1193   DeleteRegKey /ifempty SHCTX "SOFTWARE\LyX"
1194 SectionEnd
1195
1196 Section /o "un.$(UnLyXPreferencesTitle)" un.SecUnPreferences # Deletes user preferences folders for all users (if admin) and registry entry made by LyX to HKCU
1197   Call un.PrepareShellCTX
1198   SetShellVarContext current
1199   # If installed as user, only delete folder and registry key of current user
1200   ${If} $MultiUser.InstallMode == "CurrentUser"
1201     RMDir /r "$APPDATA\LyX${VERSION_MAJOR}.${VERSION_MINOR}"
1202
1203   ${Else} # If installed as admin, things are a little more complicated
1204     ${UnStrStrAdv} $2 $PROFILE "\" "<" ">" "0" "0" "0" # Get everything after the last "\" of $PROFILE ("C:\Users\username") -> $2: "username"
1205     ${UnStrStrAdv} $3 $PROFILE "\" "<" "<" "0" "0" "0" # Get everything before the last "\" of $PROFILE ("C:\Users\username") -> $3: "C:\Users"
1206     ClearErrors
1207     FindFirst $1 $0 "$3\*" # Find any folder/file in "C:\Users"
1208     ${DoUntil} ${Errors} # Errors are set while FindFirst/FindNext if the search is completed (there are no more files)
1209       ${UnStrRep} $0 $APPDATA $2 $0 # Replace "username" in $APPDATA ("C:\Users\username\AppData\Roaming") with what was found
1210       ${If} ${FileExists} "$0\LyX${VERSION_MAJOR}.${VERSION_MINOR}\*" # Check if anything exists in the LyX userdir
1211         RMDir /r "$0\LyX${VERSION_MAJOR}.${VERSION_MINOR}"
1212       ${EndIf}
1213       FindNext $1 $0
1214     ${Loop}
1215     FindClose $1
1216   ${EndIf}
1217
1218   # Can only delete for current user, because Admin can't access registry of other users
1219   DeleteRegKey HKCU "Software\LyX\LyX${VERSION_MAJOR}.${VERSION_MINOR}"
1220   DeleteRegKey /ifempty HKCU "Software\LyX"
1221 SectionEnd
1222
1223 # Uninstaller Section Descriptions
1224
1225 !insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN
1226   !insertmacro MUI_DESCRIPTION_TEXT ${un.SecUnProgramFiles} "$(SecUnProgramFilesDescription)"
1227   !insertmacro MUI_DESCRIPTION_TEXT ${un.SecUnPreferences} "$(SecUnPreferencesDescription)"
1228 !insertmacro MUI_UNFUNCTION_DESCRIPTION_END