Показать полную графическую версию : .: NSIS - все вопросы :. часть 2.
Как лучше определить, что юзаем десятку? »
WinVer2.nsh от kotkovets правильно определяет ОС - Win10 + прочие параметры десятки, но... в пределах запуска скомпилированного скрипта с HDD...
Запускаю тот же скомпилированный скрипт с флешки - ОС Win10, почему то определяется как Win8 + прочие параметры восьмёрки...
И как это понимать ? :) Сначала было даже смешно..., но как работать с флешки ? :)
wolkow70
22-10-2015, 15:45
MKN,
Windows 8.1 - 6.3
Windows 8 - 6.2
Windows 10 - 10.0
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
У меня в реестре почему-то
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion]
"ProductName"="Windows 10 Home"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion]
"CurrentVersion"="6.3"
WinVer2.nsh от kotkovets »
Этот хедер не совместим одновременно со стандартным WinVer.nsh, который мне нужен в скрипте. Вот если бы отдельно функцию выдрать...
Т.е. - при запуске exe-скрипта с флешки из под Win10 и с помощью чисто GetVersionEx, и с помощью WinVer2.nsh - ошибочная версия ОС. (при запуске с флешки из под W7 и W8 - всё ОК)
При запуске с флешки из под Win10 с помощью WMI.nsh ( т.е. с использованием WMIC) - всё определяется правильно :
;http://nsis.sourceforge.net/WMI_header
OutFile "OperatingSystemInfo.exe"
!include MUI2.nsh
!include WMI.nsh
!include LogicLib.nsh
!insertmacro MUI_LANGUAGE "English"
Var WMI_Caption
Var WMI_Version
Var WMI_CSDVersion
Var WMI_ServicePackMajorVersion
Var WMI_ServicePackMinorVersion
Var WMI_PushVar
Section
; короткое описание версии операционной системы
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem Caption callback_Function
StrCpy $WMI_Caption $WMI_PushVar
; версия ОС
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem Version callback_Function
StrCpy $WMI_Version $WMI_PushVar
; последний установленный сервис-пак (строка); если никакой сервис-пак не установлен, пустая строка.
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem CSDVersion callback_Function
StrCpy $WMI_CSDVersion $WMI_PushVar
; версия сервис-пака
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem ServicePackMajorVersion callback_Function
StrCpy $WMI_ServicePackMajorVersion $WMI_PushVar
; подверсия сервис-пака
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem ServicePackMinorVersion callback_Function
StrCpy $WMI_ServicePackMinorVersion $WMI_PushVar
SectionEnd
Function callback_Function
System::Call "user32::OemToChar(t R2, t. r2)"
detailprint "$2"
StrCpy $WMI_PushVar $2
FunctionEnd
А такой код (ранее предложенный kotkovets), в Win10 - c HDD работате нормально, с флешки в Win10 - вообще не работает
OutFile "WMI_OperatingSystem.exe"
!include "LogicLib.nsh"
!macro IWbemClassObject->Get NameObject OUT
System::Call "*(i,i,i)i.R4"
System::Call "$R3->4(w'${NameObject}',i0,iR4,i0,i0)"
System::Call "*$R4(i.R6,i,i.R5)"
StrCmp $R6 3 0 +2
IntFmt $R5 %u $R5
StrCmp $R6 8 0 +2
!ifdef NSIS_UNICODE
IntFmt $R5 %s $R5
!else
IntFmt $R5 %S $R5
!endif
System::Call "ole32::VariantClear(iR4)"
System::Free $R4
StrCpy ${OUT} $R5
!macroend
Section
System::Call "ole32::CoInitializeEx(i0,i2)"
System::Call "ole32::CoCreateInstance(g'{4590f811-1d3a-11d0-891f-00aa004b2e24}',i0,i1,g'{dc12a687-737f-11cf-884d-00aa004b2e24}',*i.R0)i.R7"
${If} $R7 == 0
System::Call "ole32::CoInitializeSecurity(i0,i-1,i0,i0,i2,i3,i0,i0,i0)"
System::Call "$R0->3(w'root\CIMV2',i0,i0,i0,i0,i0,i0,*i.R1)i.R7"
${If} $R7 == 0
System::Call "$R1->20(w'WQL', w'SELECT * FROM Win32_OperatingSystem',i48,i0,*i.R2)i.R7"
System::Call "$R2->4(i0xffffffff,i1,*i.R3,*i)i.R7"
${If} $R7 == 0
!insertmacro IWbemClassObject->Get "Caption" $7
MessageBox MB_OK "Caption=$7"
!insertmacro IWbemClassObject->Get "Version" $7
MessageBox MB_OK "Version=$7"
System::Call "$R0->2()"
System::Call "$R1->2()"
System::Call "$R2->2()"
System::Call "$R3->2()"
${Else}
System::Call "$R0->2()"
System::Call "$R1->2()"
System::Call "$R2->2()"
${EndIf}
${Else}
System::Call "$R0->2()"
System::Call "$R1->2()"
${EndIf}
${EndIf}
SectionEnd
Может Вячеслав скажет в чём тут дело ? (и подправит код...)
PS StdUtils плаг - также правильно определяет параметры Win10, и с флешки и с HDD. (кстати, он обновился Version 1.08, released 2015-10-10 )
wolkow70
22-10-2015, 17:39
MKN,
Коды WMI работают, но нужно в какой-то переменной просто получить значение 10, а не полную версию Оси.
Можно конечно отрезать, но это уже гемор дополнительный.
kotkovets
22-10-2015, 20:15
с флешки в Win10 - вообще не работает »
спотыкается здесь именно выделенным, возвращается не ноль в $R7, загадка, причины непонятна......
System::Call "$R1->20(w'WQL', w'SELECT * FROM Win32_OperatingSystem',i48,i0,*i.R2)i.R7"
System::Call "$R2->4(i0xffffffff,i1,*i.R3,*i)i.R7"
${If} $R7 == 0
Пример "географического" кода для определения параметров локализации
(используются функции GetUserDefaultLangID GetLocaleInfo GetUserGeoID GetGeoInfo ) :
OutFile "GetGeoInfo_test.exe"
!include LogicLib.nsh
; LCTYPE Constants - https://msdn.microsoft.com/en-us/library/ms906223.aspx
!define LOCALE_SCOUNTRY 6
!define LOCALE_SENGCOUNTRY 4098
!define LOCALE_SENGLANGUAGE 0x00001001
; SYSGEOTYPE enumeration - https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd374071(v=vs.85).aspx
!define GEOCLASS_NATION 16
!define GEOID_NOT_AVAILABLE -1
!define GEO_ISO2 4
!define GEO_ISO3 5
!define GEO_OFFICIALNAME 9
!define GEO_LATITUDE 2
!define GEO_LONGITUDE 3
Section
System::Call 'KERNEL32::GetUserDefaultLangID()i.r0'
DetailPrint LANGID=$0 ; ID языка, по умолчанию используемого в локали текущего пользователя
System::Call 'KERNEL32::GetLocaleInfo(i$0,i${LOCALE_SENGCOUNTRY},t.r1,i1000)'
DetailPrint LOCALE_SENGCOUNTRY=$1 ; Полное английское название страны / региона.
System::Call 'KERNEL32::GetLocaleInfo(i$0,i${LOCALE_SCOUNTRY},t.r1,i1000)'
DetailPrint LOCALE_SCOUNTRY=$1 ; Полное локализованное название страны / региона.
System::Call 'KERNEL32::GetLocaleInfo(i$0,i${LOCALE_SENGLANGUAGE},t.r1,i1000)'
DetailPrint LOCALE_SENGLANGUAGE=$1 ; Полное английское название языка по международному стандарту кода языков ( ISO 639 )
; текущий регион (местоположение)
; Table of Geographical Locations - https://msdn.microsoft.com/en-us/library/dd374073.aspx
System::Call 'KERNEL32::GetUserGeoID(i${GEOCLASS_NATION})i.r0'
DetailPrint GEOID=$0 ; Geographical location identifier (Decimal). 203 - Russia
${If} $0 <> ${GEOID_NOT_AVAILABLE} ; Only available if the user has set a country/location
${AndIf} $0 != "error" ; GetUserGeoID is WinXP+
; Извлекаем информацию о заданном географическом местоположении на основании GeoID
System::Call 'KERNEL32::GetGeoInfo(i$0,i${GEO_ISO2},t.r1,i1000,i0)'
DetailPrint GEO_ISO2=$1 ; 2-буквенный код страны / региона
System::Call 'KERNEL32::GetGeoInfo(i$0,i${GEO_ISO3},t.r1,i1000,i0)'
DetailPrint GEO_ISO3=$1 ; 3-буквенный код страны / региона
System::Call 'KERNEL32::GetGeoInfo(i$0,i${GEO_OFFICIALNAME},t.r1,i1000,i0)'
DetailPrint GEO_OFFICIALNAME=$1 ; Официальное название страны
System::Call 'KERNEL32::GetGeoInfo(i$0,i${GEO_LATITUDE},t.r1,i1000,i0)'
; координаты расположения страны (точка на карте ~ в центре страны)
DetailPrint GEO_LATITUDE=$1 ; Широта места. Это значение - число с плавающей точкой.
System::Call 'KERNEL32::GetGeoInfo(i$0,i${GEO_LONGITUDE},t.r1,i1000,i0)'
DetailPrint GEO_LONGITUDE=$1 ; Долгота места. Это значение - числo с плавающей точкой.
${EndIf}
SectionEnd
В частности, практический интерес представляет функция GetUserGeoID. Можно автоматом (не выбирая язык из списка) устанавливать, к примеру, язык интерфейса установки и т.д., соответствующий локали пользователя, запустившего инсталлятор.
Да... Похоже для определения Windows 10 надо использовать новую функцию - IsWindowsVersionOrGreater
http://stackoverflow.com/questions/32115255/c-how-to-detect-windows-10
http://www.tek-tips.com/faqs.cfm?fid=7848
Осталось адаптировать эту функцию под NSIS...
Вариант определения major и minor версий ОС с помощью функции NetWkstaGetInfo.
В Win 10 работатет (и с флешки тоже)
OutFile WinVer-NetWkstaGetInfo.exe
InstallDir $TEMP
ShowInstDetails show
RequestExecutionLevel admin
Page instfiles
# Примечание: В старых версиях NSIS (в том числе 2,46) System plug-in не поддерживае тип р, нужный для правильной работы кода
; используется структура WKSTA_INFO_100 https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa371402(v=vs.85).aspx
; а именно : DWORD wki100_ver_major и DWORD wki100_ver_minor;
Section
System::Call "netapi32::NetWkstaGetInfo(pn,i100,*p.R1)i.R2"
System::Call "*$R1(i,p,p,i.R3,i.R4)"
# в $R3 - основной номер версии ОС ver_major, в $R4 - доп. номер версии**ver_minor
IntOp $R0 $R3 << 16
IntOp $R0 $R0 | $R4
System::Call "netapi32::NetApiBufferFree(pR1)"
;Результат в шестнадцатеричной системе счисления
# 0x00050000 5.0 Windows 2000
# 0x00050001 5.1 Windows XP
# 0x00050002 5.2 Windows XP (x64), Windows Server 2003, Windows Server 2003 R2
# 0x00060000 6.0 Windows Vista, Windows Server 2008
# 0x00060001 6.1 Windows 7, Windows Server 2008 R2
# 0x00060002 6.2 Windows 8, Windows Server 2012
# 0x00060003 6.3 Windows 8.1, Windows Server 2012 R2
# 0x000A0000 10.0 Windows 10, Windows Server Technical Preview
IntFmt $R0 "0x%08X" $R0
DetailPrint "$R0"
; получаем ver_major и ver_minor "в десятичном виде"
IntOp $0 $R0 >> 16
IntOp $1 $R0 & 0xFFFF
DetailPrint "$0.$1"
SectionEnd
wolkow70
27-10-2015, 14:57
MKN,
Я для своих нужд так сделал:
Var IsOSWin10
StrCpy $IsOSWin10 "0"
Push $R0
Push $R1
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
StrCpy $R1 $R0 10
${If} $R1 == "Windows 10"
StrCpy $IsOSWin10 "1"
${EndIf}
Pop $R1
Pop $R0
${If} $IsOSWin10 == "1"
Выполняем комманды для Windows 10
${EndIf}
kotkovets
27-10-2015, 21:40
Вариант определения major и minor версий ОС с помощью функции NetWkstaGetInfo »
будет время попытаюсь, вшить эти директивчики десяточные в winver2
# Примечание: В старых версиях NSIS (в том числе 2,46) System plug-in не поддерживае тип р, нужный для правильной работы кода »
нормально всё работает на 2,46, вместо p - i (integer)
wolkow70
29-10-2015, 07:37
MKN,
Подкорректируйте пожалуйста код NetWkstaGetInfo для 2,46, с учетом замечания
kotkovets, нормально всё работает на 2,46, вместо p - n (integer) »
wolkow70,
Можно ещё проще, без канители с конвертированием. ( Я ведь такой код уже выкладывал в прошлом году... )
System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i r0 r0) i.r6"
System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
MessageBox MB_OK "$2 $3 domain (platform_id $1 - ver OS $4.$5) "
System::Call "netapi32::NetApiBufferFree(*i r0) i.r6"
но, как рекомендуют, если вдруг функция выполнится с ошибкой , так :
!include LogicLib.nsh
System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1"
${If} 0 = $1
System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
MessageBox MB_OK "$2 $3 domain (platform_id $1 - ver OS $4.$5) "
${EndIf}
${IfThen} $0 <> 0 ${|} System::Call "netapi32::NetApiBufferFree(ir0)" ${|}
Есть ещё такой занятный код - версия ОС берётся из ресурсов какой-либо системной DLL, например из kernel32.dll.
Работает в Win10
Outfile "OS-Info_test.exe"
!ifndef RT_VERSION
!define RT_VERSION 16
!endif
!ifndef VS_FILE_INFO
!define VS_FILE_INFO ${RT_VERSION}
!endif
!ifndef VS_VERSION_INFO
!define VS_VERSION_INFO 1
!endif
Section
StrCpy $R0 0
System::Call 'kernel32::LoadLibrary(t"kernel32.dll")p.R1' ; System::Call "kernel32::LoadLibrary(t '\path\your.dll(exe)') i .r0"
IntCmp $R1 0 error
System::Call 'kernel32::FindResource(pR1,p${VS_VERSION_INFO},p${VS_FILE_INFO})p.R2'
IntCmp $R2 0 ok
System::Call 'kernel32::LoadResource(pR1,pR2)p.R3'
IntCmp $R3 0 ok
System::Call 'kernel32::LockResource(pR3)p.R4'
IntCmp $R4 0 ok
System::Call "*$R4(&i2,&i2.R5,&i2,&w16,&i2,i,i,i.R6)"
IntCmp $R5 0 ok
IntFmt $R0 "0x%08X" $R6
ok:
System::Call "kernel32::FreeLibrary(pR1)"
error:
IntOp $0 $R0 >> 16
IntOp $1 $R0 & 0xFFFF
DetailPrint "$0.$1"
MessageBox MB_OK "ver $0.$1"
SectionEnd
Этот код можно использовать для определения версий не только DLL, но и EXE.
Жаль, что только до одного знака подверсии... Возможно можно как то подкорректировтаь...
Также интересна функция System::Call 'ntdll::RtlGetVersion , работающая в Win10
Но с её синтаксисом я не разобрался...
wolkow70
29-10-2015, 13:28
MKN,
Можно ещё проще, без канители с конвертированием. ( Я ведь такой код уже выкладывал в прошлом году... ) »
Похоже, что-то не то в конце получается:
DetailPrint
0x00000000
0.0
Completed
Похоже, что-то не то в конце получается: »
У меня всё нормально работает и после компиляции NSIS 3 и после NSIS 2.46 и на всех ОС.
wolkow70
29-10-2015, 13:48
У меня всё нормально работает и после компиляции NSIS 3 и после NSIS 2.46 и на всех ОС. »
Можно более полный блок кода?
Можно более полный блок кода? »
:) Куда уж полнее, чем уже дан... Выложи ка свой, не работающий код.
wolkow70
29-10-2015, 17:29
MKN,
Собственно с вашего копировал...
OutFile WinVer-NetWkstaGetInfo.exe
InstallDir $TEMP
ShowInstDetails show
RequestExecutionLevel admin
Page instfiles
!include LogicLib.nsh
# Примечание: В старых версиях NSIS (в том числе 2,46) System plug-in не поддерживае тип р, нужный для правильной работы кода
; используется структура WKSTA_INFO_100 https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa371402(v=vs.85).aspx
; а именно : DWORD wki100_ver_major и DWORD wki100_ver_minor;
Section
System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1"
${If} 0 = $1
System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
MessageBox MB_OK "$2 $3 domain (platform_id $1 - ver OS $4.$5) "
${EndIf}
${IfThen} $0 <> 0 ${|} System::Call "netapi32::NetApiBufferFree(ir0)" ${|}
;Результат в шестнадцатеричной системе счисления
# 0x00050000 5.0 Windows 2000
# 0x00050001 5.1 Windows XP
# 0x00050002 5.2 Windows XP (x64), Windows Server 2003, Windows Server 2003 R2
# 0x00060000 6.0 Windows Vista, Windows Server 2008
# 0x00060001 6.1 Windows 7, Windows Server 2008 R2
# 0x00060002 6.2 Windows 8, Windows Server 2012
# 0x00060003 6.3 Windows 8.1, Windows Server 2012 R2
# 0x000A0000 10.0 Windows 10, Windows Server Technical Preview
IntFmt $R0 "0x%08X" $R0
DetailPrint "$R0"
; получаем ver_major и ver_minor "в десятичном виде"
IntOp $0 $R0 >> 16
IntOp $1 $R0 & 0xFFFF
DetailPrint "$0.$1"
SectionEnd
wolkow70,
В примерах были разные переменные для версий. И во втором варианте НЕ нужно кода конвертации.
Т.е. в итоге :
OutFile WinVer-NetWkstaGetInfo.exe
InstallDir $TEMP
ShowInstDetails show
RequestExecutionLevel admin
Page instfiles
!include LogicLib.nsh
Section
System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1"
${If} 0 = $1
System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
;MessageBox MB_OK "ver OS $4.$5) "
DetailPrint "$4.$5"
${EndIf}
${IfThen} $0 <> 0 ${|} System::Call "netapi32::NetApiBufferFree(ir0)" ${|}
SectionEnd
Dodakaedr
03-11-2015, 08:35
Объясните, пожалуйста, почему если указать в строке 'StrCmp $R0 "0"' 0 +5 сообщение показываеться, а если +4 то нет.
outfile "test.exe"
!include "Registry.nsh"
Autoclosewindow true
Silentinstall silent
section "Main"
${registry::KeyExists} "HKCU\Software\11" $R0
StrCmp $R0 "0" 0 +4
${registry::MoveKey} "HKCU\SOFTWARE\11" "HKCU\SOFTWARE\11_backup" $R4
${registry::Unload}
goto +2
MessageBox mb_ok|mb_iconinformation "Ключа нет"
quit
sectionend
Объясните, пожалуйста, почему если указать в строке 'StrCmp $R0 "0"' 0 +5 сообщение показываеться, а если +4 то нет. »
Потому что строки:
${registry::MoveKey} "HKCU\SOFTWARE\11" "HKCU\SOFTWARE\11_backup" $R4
${registry::Unload}
это не команды, а макросы, а в макросах может содержаться несколько команд
Макрос в NSIS своеобразная "оболочка" для команд, в макросы можно заключить несколько часто используемых команд+удобно потом ориентироваться в коде
Т.е. прописывая сроку с макросом, при компиляции эта самая строка может развернуться в несколько десятков строк (в зависимости от команд, которые прописаны в теле макроса) и, соответственно, при использовании всяких +2 +3 +5 прыжков на строку, которая прописана за макросом, может оказаться проблемой и вы получите нерабочий/не правильно работающий код
Конкретно в вашем коде - макрос ${registry::MoveKey} содержит в себе 2 строки команд:
!macro registry::MoveKey _PATH_SOURCE _PATH_TARGET _ERR
registry::_MoveKey /NOUNLOAD `${_PATH_SOURCE}` `${_PATH_TARGET}`
Pop ${_ERR}
!macroend
Из-за чего ваш код стал не рабочим
Для решения этой проблемы либо создавайте метку и указывайте её в качестве цели "прыжка" (за место +4), либо еще лучше, пользуйтесь конструкциями с ${If}
outfile "test.exe"
!include "Registry.nsh"
Autoclosewindow true
Silentinstall silent
section "Main"
${registry::KeyExists} "HKCU\Software\11" $R0
${If} $R0 == "0"
${registry::MoveKey} "HKCU\SOFTWARE\11" "HKCU\SOFTWARE\11_backup" $R4
${registry::Unload}
${Else}
MessageBox mb_ok|mb_iconinformation "Ключа нет"
${EndIf}
quit
sectionend
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC