Browse Source

refactor(bundler/nsis): replace nsis_process dll usage with nsProcess

`nsis_process` dll is written by us in https://github.com/tauri-apps/nsis-tauri-utils but anti virus tools picks it up as virus. Its code does as much as `nsProcess` but I guss we just don't have enough popularity as `nsProcess` has with anti-virus tools.

closes https://github.com/tauri-apps/nsis-tauri-utils/issues/39
ref: https://github.com/tauri-apps/nsis-tauri-utils/issues/37
amrbashir 10 months ago
parent
commit
c823ccef6d

+ 37 - 17
crates/tauri-bundler/src/bundle/windows/nsis.rs

@@ -33,9 +33,12 @@ const NSIS_URL: &str =
   "https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip";
 #[cfg(target_os = "windows")]
 const NSIS_SHA1: &str = "057e83c7d82462ec394af76c87d06733605543d4";
-const NSIS_TAURI_UTILS_URL: &str =
-  "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.4.1/nsis_tauri_utils.dll";
-const NSIS_TAURI_UTILS_SHA1: &str = "F99A50209A345185A84D34D0E5F66D04C75FF52F";
+const NSIS_NS_PROCESS_URL: &str =
+  "https://github.com/tauri-apps/binary-releases/releases/download/nsis-plugins-v0/nsProcess.dll";
+const NSIS_NS_PROCESS_SHA1: &str = "B058E3FCFB7B550041DA16BF10D8837024C38BF6";
+const NSIS_SEMVERCOMPARE_URL: &str =
+  "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_semvercompare-v0.3.0/nsis_semvercompare.dll";
+const NSIS_SEMVERCOMPARE_SHA1: &str = "CD84C1B0D63D217F85E0CC6474FC415C572ADE6D";
 
 #[cfg(target_os = "windows")]
 const NSIS_REQUIRED_FILES: &[&str] = &[
@@ -43,22 +46,34 @@ const NSIS_REQUIRED_FILES: &[&str] = &[
   "Bin/makensis.exe",
   "Stubs/lzma-x86-unicode",
   "Stubs/lzma_solid-x86-unicode",
-  "Plugins/x86-unicode/nsis_tauri_utils.dll",
   "Include/MUI2.nsh",
   "Include/FileFunc.nsh",
   "Include/x64.nsh",
   "Include/nsDialogs.nsh",
   "Include/WinMessages.nsh",
+  "Plugins/x86-unicode/nsis_semvercompare.dll",
+  "Plugins/x86-unicode/nsProcess.dll",
 ];
 #[cfg(not(target_os = "windows"))]
-const NSIS_REQUIRED_FILES: &[&str] = &["Plugins/x86-unicode/nsis_tauri_utils.dll"];
+const NSIS_REQUIRED_FILES: &[&str] = &[
+  "Plugins/x86-unicode/nsis_semvercompare.dll",
+  "Plugins/x86-unicode/nsProcess.dll",
+];
 
-const NSIS_REQUIRED_FILES_HASH: &[(&str, &str, &str, HashAlgorithm)] = &[(
-  "Plugins/x86-unicode/nsis_tauri_utils.dll",
-  NSIS_TAURI_UTILS_URL,
-  NSIS_TAURI_UTILS_SHA1,
-  HashAlgorithm::Sha1,
-)];
+const NSIS_REQUIRED_FILES_HASH: &[(&str, &str, &str, HashAlgorithm)] = &[
+  (
+    "Plugins/x86-unicode/nsis_semvercompare.dll",
+    NSIS_SEMVERCOMPARE_URL,
+    NSIS_SEMVERCOMPARE_SHA1,
+    HashAlgorithm::Sha1,
+  ),
+  (
+    "Plugins/x86-unicode/nsProcess.dll",
+    NSIS_NS_PROCESS_URL,
+    NSIS_NS_PROCESS_SHA1,
+    HashAlgorithm::Sha1,
+  ),
+];
 
 /// Runs all of the commands to build the NSIS installer.
 /// Returns a vector of PathBuf that shows where the NSIS installer was created.
@@ -111,17 +126,22 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c
     fs::rename(_tauri_tools_path.join("nsis-3.08"), nsis_toolset_path)?;
   }
 
-  let nsis_plugins = nsis_toolset_path.join("Plugins");
+  let target_folder = nsis_toolset_path.join("Plugins").join("x86-unicode");
+  fs::create_dir_all(&target_folder)?;
 
   let data = download_and_verify(
-    NSIS_TAURI_UTILS_URL,
-    NSIS_TAURI_UTILS_SHA1,
+    NSIS_SEMVERCOMPARE_URL,
+    NSIS_SEMVERCOMPARE_SHA1,
     HashAlgorithm::Sha1,
   )?;
+  fs::write(target_folder.join("nsis_semvercompare.dll"), data)?;
 
-  let target_folder = nsis_plugins.join("x86-unicode");
-  fs::create_dir_all(&target_folder)?;
-  fs::write(target_folder.join("nsis_tauri_utils.dll"), data)?;
+  let data = download_and_verify(
+    NSIS_NS_PROCESS_URL,
+    NSIS_NS_PROCESS_SHA1,
+    HashAlgorithm::Sha1,
+  )?;
+  fs::write(target_folder.join("nsProcess.dll"), data)?;
 
   Ok(())
 }

+ 153 - 0
crates/tauri-bundler/src/bundle/windows/templates/GetProcessInfo.nsh

@@ -0,0 +1,153 @@
+; NSIS PROCESS INFO LIBRARY - GetProcessInfo.nsh
+; Version 1.1 - Mar 28th, 2011
+;
+; Description:
+;   Gets process information.
+;
+; Usage example:
+;   ${GetProcessInfo} 0 $0 $1 $2 $3 $4
+;   DetailPrint "pid=$0 parent_pid=$1 priority=$2 process_name=$3 exe=$4"
+;
+; History:
+;   1.1 - 28/03/2011 - Added uninstall function, include guards, file header. Fixed getting full exe path on pre vista systems. (Sergius)
+;
+
+!ifndef GETPROCESSINFO_INCLUDED
+!define GETPROCESSINFO_INCLUDED
+
+!define PROCESSINFO.TH32CS_SNAPPROCESS      2
+!define PROCESSINFO.INVALID_HANDLE_VALUE    -1
+
+!define GetProcessInfo '!insertmacro GetProcessInfo'
+
+;@in pid_in - if 0 - get current process info
+;@out pid_out - real process id (may be useful, if pid_in=0)
+;@out ppid - parent process id
+;@out priority
+;@out name - name of process
+;@out fullname - fully-qualified path of process
+!macro GetProcessInfo pid_in pid_out ppid priority name fullname
+    Push ${pid_in}
+    !ifdef __UNINSTALL__
+        Call un._GetProcessInfo
+    !else
+        Call _GetProcessInfo
+    !endif
+    ;name;pri;ppid;fname;pid;
+    Pop ${name}
+    Pop ${priority}
+    Pop ${ppid}
+    Pop ${fullname}
+    Pop ${pid_out}
+!macroend
+
+!macro FUNC_GETPROCESSINFO
+    Exch $R3 ;pid
+    Push $0
+    Push $1
+    Push $2
+    Push $3
+    Push $4
+    Push $5
+    Push $R0 ;hSnapshot
+    Push $R1 ;result
+    Push $R9 ;PROCESSENTRY32;MODULEENTRY32 and so on
+    Push $R8
+
+    ;zero registers to waste trash, if error occurred
+    StrCpy $0 ""
+    StrCpy $1 ""
+    StrCpy $2 ""
+    StrCpy $3 ""
+    StrCpy $4 ""
+    StrCpy $5 ""
+
+    IntCmp $R3 0 0 skip_pid_detection skip_pid_detection
+    System::Call 'kernel32::GetCurrentProcess() i.R0'
+    System::Call "Kernel32::GetProcessId(i R0) i.R3"
+
+skip_pid_detection:
+    System::Call 'Kernel32::CreateToolhelp32Snapshot(i ${PROCESSINFO.TH32CS_SNAPPROCESS},i R3) i.R0'
+
+    IntCmp $R0 ${PROCESSINFO.INVALID_HANDLE_VALUE} end ;someting wrong
+
+    ;$R9=PROCESSENTRY32
+    ;typedef struct tagPROCESSENTRY32 {
+    ;  DWORD     dwSize;
+    ;  DWORD     cntUsage;
+    ;  DWORD     th32ProcessID;
+    ;  ULONG_PTR th32DefaultHeapID;
+    ;  DWORD     th32ModuleID;
+    ;  DWORD     cntThreads;
+    ;  DWORD     th32ParentProcessID;
+    ;  LONG      pcPriClassBase;
+    ;  DWORD     dwFlags;
+    ;  TCHAR     szExeFile[MAX_PATH];
+    ;}PROCESSENTRY32, *PPROCESSENTRY32;
+    ;dwSize=4*9+2*260
+
+    System::Alloc 1024
+    pop $R9
+    System::Call "*$R9(i 556)"
+
+    System::Call 'Kernel32::Process32FirstW(i R0, i $R9) i.R1'
+    StrCmp $R1 0 end
+
+nnext_iteration:
+    System::Call "*$R9(i,i,i.R1)" ;get PID
+    IntCmp $R1 $R3 exitloop
+
+    System::Call 'Kernel32::Process32NextW(i R0, i $R9) i.R1'
+    IntCmp $R1 0 0 nnext_iteration nnext_iteration
+
+exitloop:
+    ;$0 - pid
+    ;$1 - threads
+    ;$2 - ppid
+    ;$3 - priority
+    ;$4 - process name
+    System::Call "*$R9(i,i,i.r0,i,i,i.r1,i.r2,i.r3,i,&w256.r4)" ; Get next module
+
+    ;free:
+    System::Free $R9
+    System::Call "Kernel32::CloseToolhelp32Snapshot(i R0)"
+
+    ;===============
+    ;now get full path and commandline
+
+    System::Call "Kernel32::OpenProcess(i 1040, i 0, i r0)i .R0"
+
+    StrCmp $R0 0 end
+
+    IntOp $R8 0 + 256
+    System::Call "psapi::GetModuleFileNameExW(i R0,i 0,t .r5, *i $R8)i .R1"
+
+end:
+    Pop $R8
+    Pop $R9
+    Pop $R1
+    Pop $R0
+    Exch $5
+    Exch 1
+    Exch $4
+    Exch 2
+    Exch $3
+    Exch 3
+    Exch $2
+    Exch 4
+    Pop $1
+    Exch 4
+    Exch $0
+    Exch 5
+    Pop $R3
+!macroend ;FUNC_GETPROCESSINFO
+
+Function _GetProcessInfo
+    !insertmacro FUNC_GETPROCESSINFO
+FunctionEnd
+
+Function un._GetProcessInfo
+    !insertmacro FUNC_GETPROCESSINFO
+FunctionEnd
+
+!endif ;GETPROCESSINFO_INCLUDED

+ 8 - 3
crates/tauri-bundler/src/bundle/windows/templates/installer.nsi

@@ -19,6 +19,7 @@ ManifestDPIAwareness PerMonitorV2
 !include WordFunc.nsh
 !include "utils.nsh"
 !include "FileAssociation.nsh"
+!include "GetProcessInfo.nsh"
 !include "Win\COM.nsh"
 !include "Win\Propkey.nsh"
 !include "StrFunc.nsh"
@@ -207,7 +208,7 @@ Function PageReinstall
   ${EndIf}
   ${IfThen} $R0 == "" ${|} StrCpy $R4 "$(unknown)" ${|}
 
-  nsis_tauri_utils::SemverCompare "${VERSION}" $R0
+  nsis_semvercompare::SemverCompare "${VERSION}" $R0
   Pop $R0
   ; Reinstalling the same version
   ${If} $R0 = 0
@@ -394,7 +395,8 @@ Var AppStartMenuFolder
 !insertmacro MUI_PAGE_FINISH
 
 Function RunMainBinary
-  nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" ""
+  ; https://mdb-blog.blogspot.com/2013/01/nsis-lunch-program-as-user-from-uac.html
+  Exec '"$WINDIR\explorer.exe" "$INSTDIR\${MAINBINARYNAME}.exe"'
 FunctionEnd
 
 ; Uninstaller Pages
@@ -725,7 +727,10 @@ Function .onInstSuccess
     ${GetOptions} $CMDLINE "/R" $R0
     ${IfNot} ${Errors}
       ${GetOptions} $CMDLINE "/ARGS" $R0
-      nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
+
+      ;https://mdb-blog.blogspot.com/2013/01/nsis-lunch-program-as-user-from-uac.html
+      CreateShortCut "$TEMP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
+      Exec '"$WINDIR\explorer.exe" "$TEMP\${MAINBINARYNAME}.lnk"'
     ${EndIf}
   ${EndIf}
 FunctionEnd

+ 47 - 11
crates/tauri-bundler/src/bundle/windows/templates/utils.nsh

@@ -18,25 +18,61 @@
   ${EndIf}
 !macroend
 
-; Checks whether app is running or not and prompts to kill it.
-!macro CheckIfAppIsRunning
+
+!macro FIND_PROCESS_ALL _EXE _RESULT
+  nsProcess::_FindProcess "${_EXE}"
+  Pop ${_RESULT}
+!macroend
+
+!macro FIND_PROCESS_USER _EXE _RESULT
+  nsExec::Exec `"$SYSDIR\cmd.exe" /c tasklist /FO csv /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_EXE}" | "$SYSDIR\find.exe" "${_EXE}"`
+  Pop ${_RESULT}
+!macroend
+
+!macro FIND_PROCESS _EXE _RESULT
   !if "${INSTALLMODE}" == "currentUser"
-    nsis_tauri_utils::FindProcessCurrentUser "${MAINBINARYNAME}.exe"
+    !insertmacro FIND_PROCESS_USER ${_EXE} ${_RESULT}
+  !else
+    ${If} $MultiUser.InstallMode == "CurrentUser"
+      !insertmacro FIND_PROCESS_USER ${_EXE} ${_RESULT}
+    ${Else}
+      !insertmacro FIND_PROCESS_ALL ${_EXE} ${_RESULT}
+    ${EndIf}
+  !endif
+!macroend
+
+!macro KILL_PROCESS_ALL _EXE _RESULT _CURRENT_PID
+  nsExec::Exec `taskkill /f /t /im "${_EXE}" /fi "PID ne ${_CURRENT_PID}"`
+!macroend
+
+!macro KILL_PROCESS_USER _EXE _RESULT _CURRENT_PID
+  nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /t /im "${_EXE}" /fi "PID ne ${_CURRENT_PID}" /fi "USERNAME eq %USERNAME%"`
+!macroend
+
+!macro KILL_PROCESS _EXE _RESULT _CURRENT_PID
+!if "${INSTALLMODE}" == "currentUser"
+    !insertmacro KILL_PROCESS_USER ${_EXE} ${_RESULT} ${_CURRENT_PID}
   !else
-    nsis_tauri_utils::FindProcess "${MAINBINARYNAME}.exe"
+    ${If} $MultiUser.InstallMode == "CurrentUser"
+      !insertmacro KILL_PROCESS_USER ${_EXE} ${_RESULT} ${_CURRENT_PID}
+    ${Else}
+      !insertmacro KILL_PROCESS_ALL ${_EXE} ${_RESULT} ${_CURRENT_PID}
+    ${EndIf}
   !endif
+!macroend
+
+Var pid
+
+; Checks whether app is running or not and prompts to kill it.
+!macro CheckIfAppIsRunning
+  !insertmacro FIND_PROCESS "${MAINBINARYNAME}.exe" $R0
   Pop $R0
   ${If} $R0 = 0
       IfSilent kill 0
       ${IfThen} $PassiveMode != 1 ${|} MessageBox MB_OKCANCEL "$(appRunningOkKill)" IDOK kill IDCANCEL cancel ${|}
       kill:
-        !if "${INSTALLMODE}" == "currentUser"
-          nsis_tauri_utils::KillProcessCurrentUser "${MAINBINARYNAME}.exe"
-        !else
-          nsis_tauri_utils::KillProcess "${MAINBINARYNAME}.exe"
-        !endif
-        Pop $R0
-        Sleep 500
+        ${GetProcessInfo} 0 $pid $1 $2 $3 $4
+        !insertmacro KILL_PROCESS "${MAINBINARYNAME}.exe" $R0 $pid
         ${If} $R0 = 0
           Goto app_check_done
         ${Else}