Added GetWinVer instruction

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@7309 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2021-08-29 18:39:07 +00:00
parent cdffbfe870
commit 52d6782447
14 changed files with 257 additions and 31 deletions

View file

@ -51,6 +51,14 @@ The error flag is set if the shortcut cannot be created (i.e. either of the path
\c "some command line parameters" "$INSTDIR\My Program.exe" 2 SW_SHOWNORMAL \
\c ALT|CONTROL|SHIFT|F5 "a description"
\S2{getwinver} GetWinVer
\c user_var(output) Major|Minor|Build|ServicePack
Gets the Windows version as reported by GetVersionEx. WinVer.nsh is the preferred method for performing Windows version checks.
\c GetWinVer $1 Build
\S2{getdllversion} GetDLLVersion
\c filename user_var(high dword output) user_var(low dword output)

View file

@ -18,6 +18,8 @@ Released on ???? ??th, 20??
\b Added \cw{$USER..} and \cw{$COMMON..} alias constants
\b Added \R{getwinver}{GetWinVer} instruction
\b Disallow start maximized mode
\b Added /LAUNCH compiler switch

View file

@ -202,6 +202,54 @@
# lazy initialization macro
!define /IfNDef __WinVer_GWV GetWinVer
!macro __WinVer_InitVars_NEW
!insertmacro __WinVer_DeclareVars
# only calculate version once
StrCmp $__WINVERV "" _winver_noveryet
Return
_winver_noveryet:
Push $0
${__WinVer_GWV} $0 Product
${__WinVer_GWV} $__WINVERV NTDDIMajMin
IntOp $__WINVERV $__WINVERV << 16 ; _WINVER_MASKVMAJ & _WINVER_MASKVMIN
IntOp $__WINVERSP $0 & 2
IntOp $__WINVERSP $__WINVERSP << 29 ; _WINVER_NTSRVBIT & _WINVER_NTDCBIT
${If} $__WINVERSP <> 0 ; Server?
${If} $__WINVERV U>= 0x06000000
${AndIf} $__WINVERV U< 0x09000000
IntOp $__WINVERV $__WINVERV | ${_WINVER_VERXBIT} ; Extra bit so Server 2008 comes after Vista SP1 that has the same minor version, same for Win7 vs 2008R2
${EndIf}
${Else}
${If} $__WINVERV = 0x05020000
StrCpy $__WINVERV 0x05010000 ; Change XP 64-bit from 5.2 to 5.1 so it's still XP
${EndIf}
${EndIf} ;~ Server
${If} $0 <> 0 ; WNT?
!if "${NSIS_PTR_SIZE}" <= 4
!ifdef WINVER_NT4_OVER_W95
${If} $__WINVERV = 0x04000000
IntOp $__WINVERV $__WINVERV | ${_WINVER_VERXBIT} ; change NT 4.0.reserved.0 to 4.0.reserved.1
${EndIf}
!endif
!endif
IntOp $__WINVERSP $__WINVERSP | ${_WINVER_NTBIT} ; _WINVER_NTBIT
IntOp $__WINVERV $__WINVERV | ${_WINVER_NTBIT} ; _WINVER_NTBIT
${EndIf} ;~ WNT
${__WinVer_GWV} $0 Build
IntOp $__WINVERSP $__WINVERSP | $0 ; _WINVER_MASKVBLD
${__WinVer_GWV} $0 ServicePack
IntOp $0 $0 << 16
IntOp $__WINVERSP $__WINVERSP | $0 ; _WINVER_MASKSP
Pop $0
!macroend
!ifmacrondef __WinVer_Call_GetVersionEx
!macro __WinVer_Call_GetVersionEx STRUCT_SIZE
@ -213,7 +261,7 @@
!endif
!macro __WinVer_InitVars
!macro __WinVer_InitVars_OLD
# variables
!insertmacro __WinVer_DeclareVars
@ -389,6 +437,14 @@
!macroend
!macro __WinVer_InitVars
!ifndef WinVer_v3_7
!insertmacro __WinVer_InitVars_NEW
!else
!insertmacro __WinVer_InitVars_OLD
!endif
!macroend
# version comparison LogicLib macros
!macro _WinVerAtLeast _a _b _t _f
@ -452,9 +508,13 @@
# service pack macros
!macro _WinVer_GetServicePackLevel OUTVAR
!ifndef WinVer_v3_7
${__WinVer_GWV} ${OUTVAR} ServicePack
!else
${CallArtificialFunction} __WinVer_InitVars
IntOp ${OUTVAR} $__WINVERSP & ${_WINVER_MASKSP}
IntOp ${OUTVAR} ${OUTVAR} >> 16
!endif
!macroend
!define WinVerGetServicePackLevel '!insertmacro _WinVer_GetServicePackLevel '
@ -492,6 +552,7 @@
!define IsStarterEdition `${SM_STARTER} WinVer_SysMetricCheck ""`
!define OSHasMediaCenter `${SM_MEDIACENTER} WinVer_SysMetricCheck ""`
!define OSHasTabletSupport `${SM_TABLETPC} WinVer_SysMetricCheck ""`
!define IsSafeBootMode `67 WinVer_SysMetricCheck ""`
# version retrieval macros
@ -509,7 +570,14 @@
!define WinVerGetMajor '!insertmacro __WinVer_GetVer $__WINVERV 24 ${_WINVER_MASKVMAJ}'
!define WinVerGetMinor '!insertmacro __WinVer_GetVer $__WINVERV 16 ${_WINVER_MASKVMIN}'
!ifndef WinVer_v3_7
!macro __WinVer_GetVerBuild outvar
${__WinVer_GWV} ${outvar} Build
!macroend
!define WinVerGetBuild '!insertmacro __WinVer_GetVerBuild '
!else
!define WinVerGetBuild '!insertmacro __WinVer_GetVer $__WINVERSP "" ${_WINVER_MASKVBLD}'
!endif
!macro _WinVer_BuildNumCheck op num _t _f
!insertmacro _LOGICLIB_TEMP

View file

@ -71,10 +71,7 @@
# SUCCESS Windows 95 OSR B
# SUCCESS Windows 98
# SUCCESS Windows ME
# Server detection failed for Windows NT4 SP1
# Expected: server
# Got: client
# FAILURE Windows NT4 SP1
# SUCCESS Windows NT4 SP1
# SUCCESS Windows NT4 SP6
# SUCCESS Windows 2000
# SUCCESS Windows 2000 SP4
@ -85,12 +82,6 @@
# SUCCESS Windows Server 2008
# Completed
#
# FAILURES
#
# * On NT4 below SP6, the registry has to be checked to figure out if it's
# a server or not. WinVer doesn't do that yet.
#
#
####
Name winver
@ -110,6 +101,59 @@ Var OSVERSIONINFOEX_INIT
Var WVSTATS_TESTS
Var WVSTATS_FAILS
!define __WinVer_GWV '!insertmacro __WinVerTest_GWV '
!include Util.nsh
!macro __WinVerTest_GWV_Imp ; This macro simulates the GetWinVer instruction
System::Store S
System::Call '*(&i999)p.r0'
Push $OSVERSIONINFO_CSD
System::Call '*$0($OSVERSIONINFO_INIT)'
${If} $OSVERSIONINFOEX_RES <> 0
Push $OSVERSIONINFOEX_CSD
System::Call '*$0($OSVERSIONINFOEX_INIT)'
${EndIf}
Pop $8
${If} $8 == Product
System::Call '*$0(i,i,i,i,i.r1,&t128,&i2,&i2,&i2,&i1.r2)'
StrCpy $9 0 ; W9x
${If} $1 U>= 2
StrCpy $9 $2
${IfThen} $9 = 0 ${|} StrCpy $9 4 ${|}
${EndIf}
${ElseIf} $8 == NTDDIMajMin
System::Call '*$0(i,i.r1,i.r2)'
IntOp $9 $1 << 8
IntOp $9 $9 | $2
${ElseIf} $8 == Build
System::Call '*$0(i,i,i,i.r9)'
${ElseIf} $8 == ServicePack
System::Call '*$0(i,i,i,i,i,&t128.r1,&i2.r9,&i2,&i2,&i1)'
StrCpy $2 $1 1
${If} $9 = 0
${AndIf} $2 != ""
StrCpy $9 $1 "" 13
${If} $2 != "S"
StrCpy $2 $1 1 1
StrCmp $2 "" +3
IntFmt $2 "%#x" 0x$2
IntOp $9 $2 - 9 ; W9x
${EndIf}
${EndIf}
${Else}
MessageBox mb_iconstop "Unknown: $8"
Quit
${EndIf}
System::Free $0
Push $9
System::Store L
!macroend
!macro __WinVerTest_GWV outvar field
Push "${field}"
${CallArtificialFunction} __WinVerTest_GWV_Imp
Pop ${outvar}
!macroend
!macro __WinVer_Call_GetVersionEx STRUCT_SIZE
!if ${STRUCT_SIZE} == ${OSVERSIONINFO_SIZE}
@ -412,6 +456,7 @@ Section
# 940000000400000000000000650500000200000053657276696365205061636b2031000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
!insertmacro TestWinVer "Windows NT4 SP1" NT4 1 client nt ; Server can only be detected by reading the registry, cannot be performed in test environment.
DetailPrint "NOTE: NT4 SP1 client/server test is inaccurate"
#### WINDOWS NT4 SP6 Server

View file

@ -96,18 +96,50 @@ EXTERN_C void NSISWinMainNOCRT()
TCHAR *realcmds;
TCHAR seekchar=_T(' ');
TCHAR *cmdline;
OSVERSIONINFOEX ovi;
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
g_WinVer = GetVersion() & ~(NSIS_WINVER_WOW64FLAG); // We store a private flag in the build number bits
// Get the version as reported by Windows
if (sizeof(void*) < 8)
{
*((UINT32*)&ovi.szCSDVersion[0]) = 0; // Zero out SP
*((UINT64*)&ovi.wServicePackMajor) = 0; // wServicePackMajor, wSuiteMask and wProductType
}
ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!GetVersionEx((OSVERSIONINFO*) &ovi) && sizeof(void*) < 8)
{
ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx((OSVERSIONINFO*) &ovi);
if (sizeof(TCHAR) == 2 || ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
ovi.wProductType = 4; // TODO: For < NT4SP6, look it up in the registry. 4 means not W9x and not VER_NT_*
ovi.wServicePackMajor = ovi.szCSDVersion[0] == 'S' ? ovi.szCSDVersion[13] - '0' : 0;
}
}
if (sizeof(TCHAR) == 1 && ovi.dwPlatformId < VER_PLATFORM_WIN32_NT)
{
ovi.wProductType = 0;
ovi.wServicePackMajor = ovi.szCSDVersion[1] >= 'A' ? ovi.szCSDVersion[1] - ('A'-1) : 0; // A, B or C
}
if (sizeof(void*) < 8 && ovi.dwMajorVersion < 10) // Ideally (sizeof(TCHAR) == 1 && ovi.dwMajorVersion < 5) but the compatibility tab emulates this bug
{
ovi.dwBuildNumber &= 0xffff; // Remove W9x garbage
}
// Save the packed version information
{
UINT32 *p = &g_osinfo.WVBuild;
p[0] = ovi.dwBuildNumber;
p[1] = MAKELONG(MAKEWORD(ovi.wProductType, ovi.wServicePackMajor), MAKEWORD(ovi.dwMinorVersion, ovi.dwMajorVersion));
}
{
// bug #1125: Don't load modules from the application nor current directory.
// SetDefaultDllDirectories() allows us to restrict implicitly loaded and
// dynamically loaded modules to just %windir%\System32 and directories
// added with AddDllDirectory(). This prevents DLL search order attacks (CAPEC-471).
DWORD winver = g_WinVer;
// CoCreateInstance(CLSID_ShellLink, ...) fails on Vista if SetDefaultDllDirectories is called
BOOL avoidwinbug = LOWORD(winver) == MAKEWORD(6, 0);
BOOL avoidwinbug = IsWinVista();
if (!avoidwinbug)
{
FARPROC fp = myGetProcAddress(MGA_SetDefaultDllDirectories);
@ -160,7 +192,7 @@ EXTERN_C void NSISWinMainNOCRT()
// accessing a unsupported view and RegKey* takes care of that by looking at the WOW64 flag.
FARPROC fp = myGetProcAddress(MGA_IsOS);
enum { os_wow6432 = 30 };
if (fp && ((BOOL(WINAPI*)(UINT))fp)(os_wow6432)) g_WinVer |= NSIS_WINVER_WOW64FLAG;
if (fp && ((BOOL(WINAPI*)(UINT))fp)(os_wow6432)) g_osinfo.WVProd |= NSIS_OSINFO_PROD_WOW64FLAG;
}
#endif

View file

@ -45,8 +45,9 @@ typedef struct _stack_t {
static stack_t *g_st;
#endif
exec_flags_t g_exec_flags;
exec_flags_t g_exec_flags_last_used;
execflags_and_osinfo g_execflags_and_osinfo;
extra_parameters plugin_extra_parameters = {
&g_exec_flags,
@ -1721,10 +1722,10 @@ static int NSISCALL ExecuteEntry(entry *entry_)
case EW_GETOSINFO:
{
//switch(parm0)
switch(parm3)
{
#ifdef NSIS_SUPPORT_FNUTIL
//case 0:
case GETOSINFO_KNOWNFOLDER:
{
TCHAR *outstr = var1;
IID kfid;
@ -1740,8 +1741,18 @@ static int NSISCALL ExecuteEntry(entry *entry_)
if (!succ)
exec_error++, *outstr = _T('\0');
}
//break;
break;
#endif
case GETOSINFO_READMEMORY:
{
TCHAR *outstr = var1;
SIZE_T addr = GetIntPtrFromParm(2), spec = GetIntPtrFromParm(4), value = 0;
UINT cb = LOBYTE(spec), offset = (UINT)(spec) >> 24;
if (addr == ABI_OSINFOADDRESS) addr = (SIZE_T) (&g_execflags_and_osinfo);
mini_memcpy(&value, ((char*) addr) + offset, cb);
iptrtostr(outstr, value);
}
break;
}
}
break;

View file

@ -21,9 +21,6 @@
#include "api.h"
extern exec_flags_t g_exec_flags;
extern exec_flags_t g_exec_flags_last_used;
int NSISCALL ExecuteCodeSegment(int pos, HWND hwndProgress); // returns 0 on success
int NSISCALL ExecuteCallbackFunction(int num); // returns 0 on success

View file

@ -568,6 +568,18 @@ typedef struct {
#endif
#define GETOSINFO_KNOWNFOLDER 0
#define GETOSINFO_READMEMORY 1
typedef struct {
UINT32 WVBuild;
BYTE WVProd; // W9x: 0, WNT:AnyServer: & 2, WNT:DC: & 7 == 3
BYTE WVSP;
BYTE WVMin;
BYTE WVMaj;
} osinfo;
#define ABI_OSINFOOFFSET ( sizeof(exec_flags_t) )
#define ABI_OSINFOADDRESS ( 0 )
// special escape characters used in strings: (we use control codes in order to minimize conflicts with normal characters)
#define NS_LANG_CODE _T('\x01') // for a langstring
#define NS_SHELL_CODE _T('\x02') // for a shell folder path

View file

@ -1,5 +1,5 @@
/*
* fileform.h
* state.h
*
* This file is a part of NSIS.
*
@ -16,7 +16,10 @@
* Unicode support by Jim Park -- 08/22/2007
*/
#ifndef NSIS_EXEHEAD_STATE_H
#define NSIS_EXEHEAD_STATE_H
#include "fileform.h"
#include "api.h"
#ifdef __GNUC__
// GCC warns about array bounds when accessing g_usrvarssection[2] because it is only [1] at compile time,
@ -50,3 +53,15 @@ extern HWND insthwnd,insthwndbutton;
#define g_hwnd 0
#define g_hInstance 0
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
typedef struct {
exec_flags_t exec_flags;
osinfo osi;
} execflags_and_osinfo;
extern execflags_and_osinfo g_execflags_and_osinfo;
#define g_exec_flags (g_execflags_and_osinfo.exec_flags)
#define g_osinfo (g_execflags_and_osinfo.osi)
#endif //~ Include guard

View file

@ -851,7 +851,7 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
LPITEMIDLIST idl;
int x = 2;
DWORD ver = sizeof(void*) > 4 ? MAKEWORD(5, 2) : g_WinVer; // We only care about 95/98 vs ME/NT4+
BOOL isWin9598 = IsWin9598();
/*
SHGetFolderPath as provided by shfolder.dll is used to get special folders
unless the installer is running on Windows 95/98. For 95/98 shfolder.dll is
@ -869,8 +869,7 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
*/
BOOL use_shfolder =
// Use shfolder if not on 95/98
!((ver & 0x80000000) && (LOWORD(ver) != MAKEWORD(4,90))) ||
!isWin9598 ||
// Unless the Application Data or Documents folder is requested
(
(fldrs[3] == CSIDL_COMMON_APPDATA) ||

View file

@ -68,10 +68,13 @@ LONG NSISCALL RegKeyCreate(HKEY hBase, LPCTSTR SubKey, REGSAM RS, HKEY*phKey);
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, UINT altview);
extern DWORD g_WinVer; // GetVersion()
#define IsWin95NT4() ( sizeof(void*) == 4 && LOWORD(g_WinVer) == 0x0004 )
#define NSIS_WINVER_WOW64FLAG ( sizeof(void*) > 4 ? ( 0 ) : ( 0x40000000 ) )
#define IsWow64() ( sizeof(void*) > 4 ? ( FALSE ) : ( g_WinVer & NSIS_WINVER_WOW64FLAG ) )
#define GetWinVerNTDDIMajMin() ( *(UINT16*)(&g_osinfo.WVMin) )
#define IsWin95NT4() ( sizeof(void*) == 4 && GetWinVerNTDDIMajMin() == 0x0400 )
#define IsWin9598ME() ( sizeof(TCHAR) == 1 && g_osinfo.WVProd == 0 )
#define IsWin9598() ( IsWin9598ME() && GetWinVerNTDDIMajMin() < MAKEWORD(90, 4) )
#define IsWinVista() ( GetWinVerNTDDIMajMin() == 0x0600 )
#define NSIS_OSINFO_PROD_WOW64FLAG ( sizeof(void*) > 4 ? ( 0 ) : ( 0x80 ) )
#define IsWow64() ( sizeof(void*) > 4 ? ( FALSE ) : ( (signed char) g_osinfo.WVProd < 0 ) ) // NSIS_OSINFO_PROD_WOW64FLAG
#define SystemSupportsAltRegView() ( sizeof(void*) > 4 ? ( TRUE ) : ( IsWow64() ) )

View file

@ -4183,9 +4183,39 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
return add_entry(&ent);
case TOK_GETKNOWNFOLDERPATH:
ent.which=EW_GETOSINFO;
ent.offsets[0]=0; // Operation
ent.offsets[1]=GetUserVarIndex(line, 1);
ent.offsets[2]=add_string(line.gettoken_str(2));
ent.offsets[3]=GETOSINFO_KNOWNFOLDER;
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T("->%") NPRIs _T("\n"), get_commandtoken_name(which_token), line.gettoken_str(2), line.gettoken_str(1));
return add_entry(&ent);
case TOK_GETWINVER:
{
int k = line.gettoken_enum(2, _T("major\0minor\0build\0servicepack\0product\0ntddimajmin")), cb = 0, ofs = 0;
switch(k)
{
case 0: cb = 1, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVMaj); break;
case 1: cb = 1, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVMin); break;
case 2: cb = 4, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVBuild); break;
case 3: cb = 1, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVSP); break;
case 4: cb = 1, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVProd); break;
case 5: cb = 2, ofs = ABI_OSINFOOFFSET + FIELD_OFFSET(osinfo, WVMin); break;
default: PRINTHELP();
}
ent.which=EW_GETOSINFO;
ent.offsets[1]=GetUserVarIndex(line, 1);
ent.offsets[2]=add_intstring(ABI_OSINFOADDRESS);
ent.offsets[3]=GETOSINFO_READMEMORY;
ent.offsets[4]=add_intstring((cb << 0) | (ofs << 24));
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T("=%") NPRIs _T("\n"), get_commandtoken_name(which_token), line.gettoken_str(1), line.gettoken_str(2));
}
return add_entry(&ent);
case TOK_READMEMORY:
ent.which=EW_GETOSINFO;
ent.offsets[1]=GetUserVarIndex(line, 1);
ent.offsets[2]=add_string(line.gettoken_str(2));
ent.offsets[3]=GETOSINFO_READMEMORY;
ent.offsets[4]=add_string(line.gettoken_str(3));
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T("=*%") NPRIs _T("\n"), get_commandtoken_name(which_token), line.gettoken_str(1), line.gettoken_str(2));
return add_entry(&ent);
case TOK_SEARCHPATH:
ent.which=EW_SEARCHPATH;

View file

@ -111,6 +111,8 @@ static tokenType tokenlist[TOK__LAST] =
{TOK_GETFULLPATHNAME,_T("GetFullPathName"),2,1,_T("[/SHORT] $(user_var: result) path_or_file"),TP_CODE},
{TOK_GETTEMPFILENAME,_T("GetTempFileName"),1,1,_T("$(user_var: name output) [base_dir]"),TP_CODE},
{TOK_GETKNOWNFOLDERPATH,_T("GetKnownFolderPath"),2,0,_T("$(user_var: result) knownfolderid"),TP_CODE},
{TOK_GETWINVER,_T("GetWinVer"),2,0,_T("$(user_var: result) field\n field=MAJOR|MINOR|BUILD|SERVICEPACK"),TP_CODE},
{TOK_READMEMORY,_T("ReadMemory"),3,0,_T("$(user_var: result) address size"),TP_CODE},
{TOK_HIDEWINDOW,_T("HideWindow"),0,0,_T(""),TP_CODE},
{TOK_ICON,_T("Icon"),1,0,_T("local_icon.ico"),TP_GLOBAL},
{TOK_IFABORT,_T("IfAbort"),1,1,_T("label_to_goto_if_abort [label_to_goto_if_no_abort]"),TP_CODE},

View file

@ -283,6 +283,8 @@ enum
TOK_FILESEEK,
TOK_GETFULLPATHNAME,
TOK_GETKNOWNFOLDERPATH,
TOK_GETWINVER,
TOK_READMEMORY,
TOK_REBOOT,
TOK_IFREBOOTFLAG,
TOK_SETREBOOTFLAG,