]> git.lyx.org Git - lyx.git/blobdiff - development/Win32/pdfview/pdfview.nsi
installer: release version 5 of the 2.0.5.1 installer
[lyx.git] / development / Win32 / pdfview / pdfview.nsi
index f00457be526ac6b218c0cdb9661ad63a50f01e64..aab892f44ca668dbcf7f45ca14cfc24cb4f011f3 100644 (file)
@@ -1,60 +1,72 @@
 /*
 
 Windows PDF view helper
 /*
 
 Windows PDF view helper
-Author: Joost Verburg
+Author: Joost Verburg and Uwe Stöhr
 
 This will be installed as pdfview.exe.
 
 The application will launch the default PDF viewer to display the PDF file,
 
 This will be installed as pdfview.exe.
 
 The application will launch the default PDF viewer to display the PDF file,
-but works around the file locking problems of Adobe Reader.
+but works around the file locking problems of Adobe Reader and Acrobat.
 
 
-Source code of pdfopen/pdfclose is available at:
-http://magic.aladdin.cs.cmu.edu/2005/07/15/pdfopen-and-pdfclose/
+The files pdfopen/pdfclose are part of this archive:
+http://www.tex.ac.uk/tex-archive/systems/win32/w32tex/pdftex-w32.tar.xz
 
 */
 
 
 */
 
-!include "LogicLib.nsh"
-!include "FileFunc.nsh"
-!insertmacro GetParameters
-!insertmacro GetFileName
+!include LogicLib.nsh
+!include FileFunc.nsh
 
 #--------------------------------
 
 #--------------------------------
-#Settings
+# Settings
 
 Caption "PDF Viewer"
 OutFile pdfview.exe
 
 Caption "PDF Viewer"
 OutFile pdfview.exe
-Icon "..\packaging\icons\lyx_32x32.ico"
+Icon "..\packaging\icons\lyx.ico"
 SilentInstall silent
 
 #--------------------------------
 SilentInstall silent
 
 #--------------------------------
-#Windows Vista settings
+# Windows Vista (and later) settings
 
 RequestExecutionLevel user
 
 #--------------------------------
 
 RequestExecutionLevel user
 
 #--------------------------------
-#Constants
+# Constants
 
 !define FALSE 0
 !define TRUE 1
 
 
 !define FALSE 0
 !define TRUE 1
 
+# see http://msdn.microsoft.com/en-us/library/windows/desktop/aa364417%28v=vs.85%29.aspx
+!define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+# see http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx
+!define WAIT_TIMEOUT 0x00000102
+
 #--------------------------------
 #--------------------------------
-#Variables
+# Variables
+
+Var Character
+Var RunAppReturn
 
 
-Var Dummy
 Var OriginalFile
 Var OriginalFileName
 Var OriginalFile
 Var OriginalFileName
+Var OriginalDir
+
 Var PDFFile
 Var PDFFile
+Var ViewerFileName
 Var Viewer
 Var Viewer
-Var OriginalTimeHigh
-Var OriginalTimeLow
-Var CurrentTimeHigh
-Var CurrentTimeLow
+
+Var ChangeNotification
+Var WaitReturn
+Var LockedFile
+
+Var TimeDiff
 
 #--------------------------------
 
 #--------------------------------
-#Macros
+# Macros
 
 !macro SystemCall STACK
 
 
 !macro SystemCall STACK
 
+  # Call a Windows API function
+
   Push `${STACK}`
   CallInstDLL "$EXEDIR\System.dll" Call
 
   Push `${STACK}`
   CallInstDLL "$EXEDIR\System.dll" Call
 
@@ -62,118 +74,217 @@ Var CurrentTimeLow
 
 !macro HideConsole COMMAND_LINE
 
 
 !macro HideConsole COMMAND_LINE
 
+  # Run an application and hide console output
+
   Push `${COMMAND_LINE}`
   CallInstDLL "$EXEDIR\Console.dll" Exec
   Push `${COMMAND_LINE}`
   CallInstDLL "$EXEDIR\Console.dll" Exec
-  Pop $Dummy
+  Pop $RunAppReturn
   
   
-  ${if} $Dummy == "error"
-    MessageBox MB_OK|MB_ICONSTOP "Error opening PDF file $R0."
-  ${endif}
+  ${If} $RunAppReturn == "error"
+    MessageBox MB_OK|MB_ICONSTOP "Error opening PDF file $PDFFile."
+  ${EndIf}
+
+!macroend
+
+# all following macros and functions are from
+# http://nsis.sourceforge.net/FileTimeDiff
+!define GetFileTimeS "!insertmacro _GetFileTimeS"
+
+!macro _GetFileTimeS _Time_ _File_
+
+   Push "${_File_}"
+   Call GetFileTimeS
+   Pop ${_Time_}
+   
+!macroend
 
 
+Function GetFileTimeS
+       
+   Exch $0  # File / hi
+   Push $1  # lo
+   ClearErrors
+   GetFileTime "$0" $0 $1
+   IfErrors err
+   System::Call '*(i r1, i r0) i .r0'
+   System::Call '*$0(l .r0)'
+   System::Int64Op $0 / 10000000  # Conversion From '100 ns' to '1 sec' unit
+   Goto end
+   err:
+      Push ""
+      SetErrors
+      Goto +3
+   end:
+   System::Free $0
+   Exch 2
+   Pop $0
+   Pop $1
+   
+FunctionEnd
+
+!define FileTimeDiff "!insertmacro _FileTimeDiff"
+
+!macro _FileTimeDiff _RetVal_ _FileA_ _FileB_
+
+   Push "${_FileB_}"
+   Push "${_FileA_}"
+   Call FileTimeDiff
+   Pop ${_RetVal_}
+   
 !macroend
 
 !macroend
 
+Function FileTimeDiff 
+   Exch $0  # FileA
+   Exch 
+   Exch $1  # FileB
+   ${GetFileTimeS} $0 "$0"
+   IfErrors err
+   ${GetFileTimeS} $1 "$1"
+   IfErrors err
+   System::Int64Op $0 - $1
+   Goto end
+   err:
+      Push ""
+      SetErrors
+   end:
+   Exch 2
+   Pop $0
+   Pop $1
+   
+FunctionEnd
+
 #--------------------------------
 #--------------------------------
-#PDF vieweing
+# PDF viewing
 
 Section "View PDF file"
 
 
 Section "View PDF file"
 
-  InitPluginsDir #Temporary directory for PDF file
+  InitPluginsDir # Temporary directory for PDF file
 
 
-  #Command line parameters
-  Call GetParameters
-  Pop $OriginalFile
+  # Command line parameters
+  ${GetParameters} $OriginalFile
 
 
-  #Trim quotes
-  StrCpy $Dummy $OriginalFile 1
-  ${if} $Dummy == '"'
+  # Trim quotes
+  StrCpy $Character $OriginalFile 1
+  ${If} $Character == '"'
     StrCpy $OriginalFile $OriginalFile "" 1
     StrCpy $OriginalFile $OriginalFile "" 1
-  ${endif}
-  StrCpy $Dummy $OriginalFile 1 -1
-  ${if} $Dummy == '"'
+  ${EndIf}
+  StrCpy $Character $OriginalFile 1 -1
+  ${If} $Character == '"'
     StrCpy $OriginalFile $OriginalFile -1
     StrCpy $OriginalFile $OriginalFile -1
-  ${endif}
+  ${EndIf}
 
   GetFullPathName $OriginalFile $OriginalFile
 
   GetFullPathName $OriginalFile $OriginalFile
-  Push $OriginalFile
-  Call GetFileName
-  Pop $OriginalFileName
+  ${GetFileName} $OriginalFile $OriginalFileName
+  ${GetParent} $OriginalFile $OriginalDir # tmpbuf
+  ${GetParent} $OriginalDir $OriginalDir # tmpdir
 
 
-  SetOutPath $TEMP #The LyX tmpbuf should not be locked
+  SetOutPath $TEMP # The LyX tmpbuf should not be locked
 
   StrCpy $PDFFile $PLUGINSDIR\$OriginalFileName
 
 
   StrCpy $PDFFile $PLUGINSDIR\$OriginalFileName
 
-  #Check whether the file will be opened with Adobe Reader or Adobe Acrobat
-  Push $OriginalFile
-  !insertmacro SystemCall "shell32::FindExecutable(t s, t '', t .s)"
-  Call GetFileName
-  Pop $Viewer
+  # Check whether the file will be opened with Adobe Reader or Adobe Acrobat
+  !insertmacro SystemCall "shell32::FindExecutable(t '$OriginalFile', t '', t .s)"
+  Pop $ViewerFileName
+  ${GetFileName} $ViewerFileName $Viewer
 
 
-  ${if} $Viewer == ""
+  ${If} $Viewer == ""
     MessageBox MB_OK|MB_ICONEXCLAMATION "No PDF viewer is installed. \
         Please install a PDF viewer such as Adobe Reader."
     Quit        
     MessageBox MB_OK|MB_ICONEXCLAMATION "No PDF viewer is installed. \
         Please install a PDF viewer such as Adobe Reader."
     Quit        
-  ${endif}
+  ${EndIf}
 
 
-  ${if} $Viewer == "AcroRd32.exe"
-    ${orif} $Viewer == "Acrobat.exe"
-    
-    #Using Adobe viewer
+  ${If} $Viewer == "AcroRd32.exe"
+  ${OrIf} $Viewer == "Acrobat.exe"
+  
+    # get the version of Acrobat - currenly not necessary
+    #GetDLLVersion $ViewerFileName $R0 $R1
+    #IntOp $R2 $R0 >> 16
+    #IntOp $R2 $R2 & 0x0000FFFF ; $R2 now contains major version
+    #IntOp $R3 $R0 & 0x0000FFFF ; $R3 now contains minor version
+    #IntOp $R4 $R1 >> 16
+    #IntOp $R4 $R4 & 0x0000FFFF ; $R4 now contains release
+    #IntOp $R5 $R1 & 0x0000FFFF ; $R5 now contains build
+    #StrCpy $ViewerVersion "$R2"
     
     
-    #Close existing view
-    ${if} ${fileexists} $PDFFile
+    # Close existing view
+    ${If} ${FileExists} $PDFFile
       !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
       !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
-    ${endif}
+    ${EndIf}
     
     
-    #Copy PDF to temporary file to allow LyX to overwrite the original
+    # Copy PDF to temporary file to allow LyX to overwrite the original
     CopyFiles /SILENT $OriginalFile $PDFFile
     
     CopyFiles /SILENT $OriginalFile $PDFFile
     
-    #Open a new view
-    !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --back --file "$PDFFile"'
-    
-    #Monitor for updates of the original file
-    
-    GetFileTime $OriginalFile $OriginalTimeHigh $OriginalTimeLow
+    # Open a new view
+    !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --file "$PDFFile"'
+        
+    # check if a file in LyX's temp folder has been changed
+    !insertmacro SystemCall "kernel32::FindFirstChangeNotification(t '$OriginalDir', \
+      i 1, i ${FILE_NOTIFY_CHANGE_LAST_WRITE}) i.s"
+    Pop $ChangeNotification
     
     
-    ${do}
+    ${Do}
     
     
-      Sleep 500
-      
-      FileOpen $Dummy $PDFFile a
+      # wait until the folder is not changed anymore, if so a "0" is returned
+      # otherwise a "258" (0x00000102) is returned
+      !insertmacro SystemCall "kernel32::WaitForSingleObject(i $ChangeNotification, i 10000) i.s"
+      Pop $WaitReturn
       
       
-      ${if} $Dummy != ""
-        #File no longer locked, reader closed
-        FileClose $Dummy
+      # Check whether the lock of the PDF file is still active (if not, Adobe Reader is closed)
+      FileOpen $LockedFile $PDFFile a
+      ${If} $LockedFile != ""
+        # Quit this application
+        FileClose $LockedFile
         Delete $PDFFile
         Delete $PDFFile
+        !insertmacro SystemCall "kernel32::FindCloseChangeNotification(i $ChangeNotification)"
         Quit
         Quit
-      ${endif}
+      ${EndIf}
       
       
-      ${if} ${fileexists} $OriginalFile
-        
-        GetFileTime $OriginalFile $CurrentTimeHigh $CurrentTimeLow
+      # if the folder is (for now) not changed anymore
+      ${IfNot} $WaitReturn = ${WAIT_TIMEOUT}
+      
+        # check if the PDF-file in our temp directory is older than the one
+        # in LyX's temp folder because then it has been changed by LaTeX
+        ${FileTimeDiff} $TimeDiff "$PDFFile" "$OriginalFile"
         
         
-        ${if} $OriginalTimeHigh != $CurrentTimeHigh
-          ${orif} $OriginalTimeLow != $CurrentTimeLow
-          
-          #Original has been modified, update!
-          
-          StrCpy $OriginalTimeHigh $CurrentTimeHigh
-          StrCpy $OriginalTimeLow  $CurrentTimeLow
+        # if the file is older than 1 second
+        ${If} $TimeDiff < -1
+          # close the PDF
           !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
           !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
-          CopyFiles /SILENT $OriginalFile $PDFFile
-          !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --back --file "$PDFFile"'
           
           
-        ${endif}
+          # The problem is now that LaTeX might need several runs and therefore the PDF can
+          # also be rewritten consecutively several times.
+          # If we would directly open the file we will get in troubles as the PDF can be
+          # unreadable. We also don't know the time of a LaTeX run.
+          # (As example take UserGuide.lyx, view it, then remove a letter in a section heading
+          # and finally update the view.)
+          # We therefore loop until the PDF is no longer changed and wait some time in each loop.
+          ${Do}
+           CopyFiles /SILENT $OriginalFile $PDFFile
+           # wait 1.666 seconds (is empirically enough time that the PDF can be changed)
+           Sleep 1666
+           ${FileTimeDiff} $TimeDiff "$PDFFile" "$OriginalFile"
+          ${LoopUntil} $TimeDiff = 0
+          
+          # open the new file
+          !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --file "$PDFFile"'
+        ${EndIf}
+        
+        #Monitor again
+        !insertmacro SystemCall "kernel32::FindNextChangeNotification(i $ChangeNotification)"
         
         
-      ${endif}
+      ${EndIf} # end ifnot
     
     
-    ${loop}
+    ${Loop}
     
     
-  ${else}
+  ${Else}
   
   
-    #Another PDF viewer like GSView is used
-    #No need for special actions, just forward to ShellExecute
+    # Another PDF viewer like GSView is used
+    # No need for special actions, just forward to ShellExecute
     ExecShell open $OriginalFile
     
     ExecShell open $OriginalFile
     
-  ${endif}
+  ${EndIf}
     
 SectionEnd
     
 SectionEnd