Can i detect 32 or 64 bit OS without plugin somehow? - nsis

now i use the x64.nsh for this, but i can detect it without this plugin?
${If} ${RunningX64}
MessageBox MB_OK "running on 64 bit"
File /r ${64BIT_OPENVPN_INSTALL}
Execwait ${64BIT_OPENVPN_INSTALL}
${Else}
MessageBox MB_OK "running on 32 bit"
File /r ${32BIT_OPENVPN_INSTALL}
Execwait ${32BIT_OPENVPN_INSTALL}
${EndIf}

x64.nsh does not implies specific external plugin usage (apart the system plugin): it is just an included file that defines 3 macros based on kernel calls (i.e kernel32::GetCurrentProcess() and kernel32::IsWow64Process()) through the system plugin, that can be conveniently used with LogicLib.nsh

There are probably many ways to detect the native bitness by just looking at files and registry keys but there is always the risk that some 32-bit systems have somehow ended up with a SysWOW64 folder in %WinDir% etc.
The SetRegView test should be pretty safe but there is a small window where some other app could change the registry at just the wrong time giving you the wrong result.
The correct way to detect this is of course to call the IsWow64Process function and the x64.nsh header already does that for you.
!include LogicLib.nsh
Section
!if "${NSIS_PTR_SIZE}" > 4
DetailPrint "64-bit NSIS, this must be a 64-bit system"
!endif
${If} ${FileExists} "$WinDir\SysWOW64\kernel32.dll"
DetailPrint "Probably not a native 32-bit system"
${EndIf}
${If} ${FileExists} "$WinDir\SysNative\kernel32.dll"
DetailPrint "Probably a 32-bit app on a native 64-bit system (Vista+ only)"
${EndIf}
SetRegView 64
ReadRegStr $6 HKLM "Software\Microsoft\Windows\CurrentVersion" "ProgramFilesDir"
SetRegView lastused
SetRegView 32
ReadRegStr $3 HKLM "Software\Microsoft\Windows\CurrentVersion" "ProgramFilesDir"
SetRegView lastused
${If} $3 != $6
DetailPrint "Probably a 32-bit app on a native 64-bit system"
${EndIf}
; ReadEnvStr on ProgramW6432 or PROCESSOR_ARCHITEW6432 etc
SectionEnd

Related

How to make NSIS section mandatory depending on condition

I have a section in my installer I am attempting to make mandatory depending on some condition (the presence of a registry value) but I am not getting the behaviour I am expecting.
I am attempting to use the following command to make the section ticked and locked:
SectionIn RO
I also have a registry value that definitely exists but both of the following code chunks cause the section to be locked and ticked...
ClearErrors
ReadRegStr $0 HKCU "Software\Test" "TestValue"
${If} ${Errors}
SectionIn RO ; registry key not found
${Else}
; do nothing
${EndIf}
ClearErrors
ReadRegStr $0 HKCU "Software\Test" "TestValue"
${If} ${Errors}
; do nothing
${Else}
SectionIn RO ; registry key was found
${EndIf}
So it seems like either both control paths are being executed or the SectionIn command is trancending the if logic.
I can't seem to find much documentation on this particular command but I am a bit stumped. Any ideas?
SectionIn is an attribute and cannot be changed at run-time.
You should use the section helper macros in .onInit:
Section "blah" S_1
SectionEnd
!include LogicLib.nsh
!include Sections.nsh
Function .onInit
...
${If} ${Errors}
!insertmacro SetSectionFlag ${S_1} ${SF_RO}
${EndIf}
FunctionEnd

How to show the popup message when user tries to install on Unsupported Operating System

When installing the software, I wanted to detect the operating system and if it is "Windows 10 Pro" or "Windows Server 2012" it should pop up a message box and the installation should stop.
I am using the below code snippet. But here even if the operating system is "Windows 10 Pro", message box is not popping up.
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
${If} $R0 == "Windows 10 Pro"
MessageBox MB_OK|MB_ICONQUESTION "This operating system is not supported." IDOK
Quit
${EndIf}
Is it the correct way or is there any way we can detect the operating system and show the message box?
I don't really understand why you need these restrictions but here you go:
!include WinVer.nsh
!define /IfNDef PRODUCT_PROFESSIONAL 0x00000030
!define /IfNDef PRODUCT_PROFESSIONAL_N 0x00000031
!define /IfNDef PRODUCT_PRO_WORKSTATION 0x000000A1
!define /IfNDef PRODUCT_PRO_WORKSTATION_N 0x000000A2
!define /IfNDef ERROR_INSTALL_REJECTED 1654
Function .onInit
System::Call 'KERNEL32::GetProductInfo(i6,i1,i0,i0,*i0r1)'
${WinVerGetBuild} $2
${If} ${IsServerOS} ; Windows Server?
${AndIf} $2 U>= 9200 ; Server 2012?
${AndIf} $2 U< 9600 ; and not Server 2012 R2?
Goto die_unsupported_os
${EndIf}
${If} $2 U>= 9800 ; Windows 10?
${AndIfNot} ${IsServerOS} ; Not Windows Server?
${If} $1 = ${PRODUCT_PROFESSIONAL}
${OrIf} $1 = ${PRODUCT_PROFESSIONAL_N}
${OrIf} $1 = ${PRODUCT_PRO_WORKSTATION}
${OrIf} $1 = ${PRODUCT_PRO_WORKSTATION_N}
die_unsupported_os:
MessageBox mb_IconStop|mb_OK "Not allowed to run on this version of Windows for some reason!" /SD IDOK
SetErrorLevel ${ERROR_INSTALL_REJECTED}
Quit
${EndIf}
${EndIf}
FunctionEnd
Note: Windows Insider builds are also identified as Pro so you will end up blocking those as well.

Check/Prevent Windows Shutdown (NSIS)

To summarize, I need to check and/or prevent a user if he/she decides to shutdown the computer while the installer is running. Now I've researched for a while and came up with the following:
${If} ${AtMostWinXP}
System::Call `kernel32::GetModuleHandle(i0)i.r3`
System::Call `user32::CreateWindowEx(i0,t"STATIC",t"MyApp",i0,i0,i0,i0,i0,i$HWNDPARENT,i0,ir3,i0)i.r1`
${ElseIf} ${AtLeastVista}
System::Call `user32::ShutdownBlockReasonCreate(ir1,w"MyApp is running and still needs to clean up before shutting down!")i.r0`
${EndIf}
However the above snippet isn't working. Am I missing something? I've tried using just:
System::Call `kernel32::GetModuleHandle(i0)i.r3`
System::Call `user32::CreateWindowEx(i0,t"STATIC",t"MyApp",i0,i0,i0,i0,i0,i$HWNDPARENT,i0,ir3,i0)i.r1`
System::Call `user32::ShutdownBlockReasonCreate(ir1,w"MyApp is running and still needs to clean up before shutting down!")i.r0`
As the first two calls are meant for Windows XP and earlier and the third call is meant for Windows Vista or later but is ignored by Windows XP and earlier I believe (I have no evidence to support this theory). This too isn't working.
Also, I can use user32::ShutdownBlockReasonCreate(ir1,w"$(PreventShutdown)")i.r0 instead of using the entire string in the above snippet for different language support, right?
Your code for Windows XP makes no sense, the window needs to handle WM_QUERYENDSESSION to block the shutdown. Luckily NSIS already handles WM_QUERYENDSESSION for you.
Use something like this for Vista and later:
LoadLanguageFile "${NSISDIR}\Contrib\Language Files\English.nlf"
LangString BlockReason ${LANG_ENGLISH} "Installer blah blah"
LoadLanguageFile "${NSISDIR}\Contrib\Language Files\Swedish.nlf"
LangString BlockReason ${LANG_SWEDISH} "Installer bork bork"
!include nsDialogs.nsh ; For WS_CHILD
!define /ifndef WS_POPUP 0x80000000
!include LogicLib.nsh
Function CreateShutdownBlockReason
StrCpy $1 $hwndParent
${If} $1 Z= 0 ; $hwndParent is 0, create a new window for silent installers
System::Call 'USER32::CreateWindowEx(i0, t "STATIC", t "$(^Name)", i ${WS_CHILD}|${WS_POPUP}, i0, i0, i0, i0, p r1, i0, i0, i0)p.r1'
${EndIf}
System::Call 'USER32::ShutdownBlockReasonCreate(p r1, w "$(BlockReason)")'
FunctionEnd
Function .onInit
IfSilent 0 +2
Call CreateShutdownBlockReason ; .onGuiInit is not executed in silent installers
FunctionEnd
Function .onGuiInit
Call CreateShutdownBlockReason
FunctionEnd
I'm not sure if a silent installer will be able to block the shutdown but this is the best you can do without a plug-in.

nsis - remove pinned icon from taskbar on uninstall

I'm working on an app for a company and they requested that if the app is pinned to the taskbar, when uninstalling the app should be unpinned. If I just delete the icon from quicklaunch\user pinned\taskbar then it leaves a blank icon on the taskbar.
I need to somehow actually unpin it. The only thing I've come across is installing winshell plugin (http://nsis.sourceforge.net/WinShell_plug-in) and then calling IStartMenuPinnedList::RemoveFromList (https://msdn.microsoft.com/en-us/library/windows/desktop/bb774817(v=vs.85).aspx)
I'd rather not install a plugin if I don't need to. Does anyone have any suggestions?
NSIS does not have native support for this interface so you have to use a plug-in. If you want to avoid that 3rd-party plug-in (written by me) then you can use the System plug-in instead:
!include "LogicLib.nsh"
!include "Win\COM.nsh" ; NSIS v3+
!macro UnpinShortcut lnkpath
Push $0
Push $1
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
${If} $0 P<> 0
System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${lnkpath}"
${If} $1 P<> 0
${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
${IUnknown::Release} $1 ""
${EndIf}
${IUnknown::Release} $0 ""
${EndIf}
Pop $1
Pop $0
!macroend
Section Uninstall
!insertmacro UnpinShortcut "$SMPrograms\MyApp.lnk"
Delete "$SMPrograms\MyApp.lnk"
SectionEnd

How to detect windows 32bit or 64 bit using NSIS script?

I have written nsis script for java project.I have Batch file in my project.I have written batch file for commonly windows 32bit and 64 bit.After installing i have started batch file automatically using Exec command.Its woks fine in 32bit windows.but the same time this is not worked well in 64 bit.so i suspect that before installing i should check whether windows is 32 bit or 64 bit version.please share your views how to check?
For future lazy googlers - A small snippet:
Include this:
!include x64.nsh
And use this if:
${If} ${RunningX64}
# 64 bit code
${Else}
# 32 bit code
${EndIf}
Use the RunningX64 macro in the x64.nsh header:
!include LogicLib.nsh
!include x64.nsh
Section
${If} ${RunningX64}
DetailPrint "64-bit Windows"
${Else}
DetailPrint "32-bit Windows"
${EndIf}
SectionEnd
Here's what I use most of the time without the need for x64.nsh
Var Bit
System::Call "kernel32::GetCurrentProcess()i.s"
System::Call "kernel32::IsWow64Process(is,*i.r0)"
StrCmpS $0 0 +3
StrCpy $Bit 64
Goto +2
StrCpy $Bit 32
Now $Bit holds either 64 or 32 which can be used like this:
${If} $Bit == 64
...64-bit code..
${Else}
..32-bit code...
${EndIf}
Or
StrCmpS $Bit 64 SixtyFour ThirtyTwo
SixtyFour:
...
Goto End
ThirtyTwo:
...
End:
I used StrCmpS as I believe it's a hair faster. Lol. Hope this helps! =)

Resources