Войти

Показать полную графическую версию : .: NSIS - все вопросы :. часть 2.


Страниц : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 [139] 140 141 142 143 144 145 146

iglezz
11-07-2023, 17:05
AlekseyPopovv,
Изначальный xml-файл (до внесения изменений) есть?
Вот это вот похоже на некорректную запись (атрибуты записаны на простой текст):<Common>CreateBackupCopy="0" ShowSplashScreen="0"</Common>
должно быть
<Common CreateBackupCopy="0" ShowSplashScreen="0" />

Если файла изначально нет, то можно его создать просто через FileWrite
Если нужно именно модифицировать существующий, то это делается через плагин (nsisXML by Wizou (https://nsis.sourceforge.io/NsisXML_plug-in_(by_Wizou)))

AlekseyPopovv
11-07-2023, 19:03
iglezz,
Именно вот так выглядит оригинал.
<?xml version="1.0" encoding="UTF-8"?>
<RDLXSettings>
<LangIDList/>
<Common CreateBackupCopy="0" ShowSplashScreen="0">
<AutoSave Enable="0" Interval="1"/>
</Common>
<ProjectHistory LoadlastProject="0" NoProject="1"/>
<Spelling Type="1">
<HunSpellDictionary Enabled="1">$EXEDIR\${APPDIR}\ru-RU.dic</HunSpellDictionary>
</Spelling>
</RDLXSettings>
Я могу конечно его создать и положить в инсталлятор.
Но как потом удалить и снова добавить строку именно такую:
<HunSpellDictionary Enabled="1">$EXEDIR\${APPDIR}\ru-RU.dic</HunSpellDictionary>

iglezz
11-07-2023, 19:45
AlekseyPopovv, Что-то в итоге понятнее не стало.
Лучше сначала и по порядку:
1. какое содержимое файла до запуска инсталлера
2. что нужно изменить
3. какое должно быть содержимое файла в итоге

AlekseyPopovv
11-07-2023, 19:55
iglezz,
1. <?xml version="1.0" encoding="UTF-8"?>
<RDLXSettings>
<LangIDList/>
<Common CreateBackupCopy="0" ShowSplashScreen="0">
<AutoSave Enable="0" Interval="1"/>
</Common>
<ProjectHistory LoadlastProject="0" NoProject="1"/>
<Spelling Type="1">
<HunSpellDictionary Enabled="1"></HunSpellDictionary>
</Spelling>
</RDLXSettings>
2. Строку:
<HunSpellDictionary Enabled="1"></HunSpellDictionary>
заменить на:
<HunSpellDictionary Enabled="1">$EXEDIR\${APPDIR}\ru-RU.dic</HunSpellDictionary>
либо в неё записать значение
3. <?xml version="1.0" encoding="UTF-8"?>
<RDLXSettings>
<LangIDList/>
<Common CreateBackupCopy="0" ShowSplashScreen="0">
<AutoSave Enable="0" Interval="1"/>
</Common>
<ProjectHistory LoadlastProject="0" NoProject="1"/>
<Spelling Type="1">
<HunSpellDictionary Enabled="1">C:\my program\ru-RU.dic</HunSpellDictionary>
</Spelling>
</RDLXSettings>

iglezz
11-07-2023, 20:06
AlekseyPopovv, это простейшее изменение
nsisXML::create
nsisXML::load "x:\path\to\xml\file"
nsisXML::select '/RDLXSettings/Spelling/HunSpellDictionary'
nsisXML::setText 'x:\path\to\dict'
nsisXML::save "x:\path\to\xml\file"

Это без обработки ошибок, при отсутствии файла при чтении или выбираемого через ::select узла установщик просто упадёт.

AlekseyPopovv
19-07-2023, 12:30
Как записать в ini файл такую строку:
LanguagesPath=@ByteArray(P:/Folder/Program Portable/Settings/OCR)
Пишу так:
WriteINIStr "$EXEDIR\${DEFDIR}\${SETINI}" "OCR" "LanguagesPath" "@ByteArray($EXEDIR/${DEFDIR}/OCR)"
И получается так:
LanguagesPath=@ByteArray(P:\Folder\Program Portable/Settings/OCR)

iglezz
19-07-2023, 15:25
Для начала ту часть строки, в которой нужно преобразовать слеши (в данном случае $EXEDIR) нужно обработать
Например, ${StrRep} $0 $EXEDIR / \
И потом только результат можно использовать в WriteIniStr:
WriteINIStr "$EXEDIR\${DEFDIR}\${SETINI}" "OCR" "LanguagesPath" "@ByteArray($0/${DEFDIR}/OCR)"

Полагаю, что у программы могут возникнуть проблемы, если в записываемом пути будут символы вне ANSI-кодировки.

AlekseyPopovv
21-07-2023, 08:57
Например, ${StrRep} $0 $EXEDIR / \ »
Сработало:

!include "StrFunc.nsh"
${StrRep}

${StrRep} $0 "$EXEDIR" "\" "/"
WriteINIStr "$EXEDIR\${DEFDIR}\${SETINI}" "OCR" "LanguagesPath" "@ByteArray($0/${DEFDIR}/OCR)"

inco1
10-08-2023, 10:35
Всем хорошего дня.
Есть такой вопрос. Существует ли в NSIS задержка определенной команды на несколько секунд. Чтобы была не задержка всего процесса, а только задержка одной команды. Нужно добавить в реестр запись через 10 секунд после определенной команды, но чтобы весь процесс не останавливался на 10 секунд, как это делает команда "Sleep 10000".

iglezz
10-08-2023, 11:05
inco1, https://nsis.sourceforge.io/ThreadTimer_plug-in

AlekseyPopovv
10-08-2023, 11:35
Нужно что то подобное, без MUI. Есть варианты?
!include "MUI.nsh"

!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "English"

${If} $Language == 1049
MessageBox MB_USERICON|MB_OK 'Программа "${APP}" уже запущена!'
Abort
${Else}
MessageBox MB_USERICON|MB_OK 'The "${APP}" is already running!'
Abort
${EndIf}

iglezz
10-08-2023, 14:12
AlekseyPopovv,
Разница между с MUI и без MUI в том, что
с MUI пишется !insertmacro MUI_LANGUAGE "Russian"
без MUI пишется LoadLanguageFile "${NSISDIR}\Contrib\Language files\Russian.nlf"
Дальше всё одинаково.

Кроме того локалицацию проще и правильнее прописывать так:

; Подключение языковый файлов
; English должен быть первый, т.к. если в списке подключённых языков отсутствует язык системы, то грузится первый по списку
LoadLanguageFile "${NSISDIR}\Contrib\Language files\English.nlf"
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Russian.nlf"

; Объявление многоязычной строки:
LangString AlreadyRunningMessage ${LANG_ENGLISH} "The "${APP}" is already running!"
LangString AlreadyRunningMessage ${LANG_RUSSIAN} "Программа "${APP}" уже запущена!"

...

; Использование многоязычной строки:
MessageBox MB_USERICON|MB_OK $(AlreadyRunningMessage)
Abort


Если программа уже запущена, то вместо сообщения с прерыванием запуска можно активировать уже запущенный установщик
!include SingleInstance.nsh

RequestExecutionLevel user
Page instfiles
UninstPage uninstConfirm

Section
DetailPrint A
Sleep 1000
DetailPrint B
Sleep 1000
DetailPrint C
Sleep 1000
DetailPrint D
Sleep 1000
SectionEnd
Section un.
SectionEnd

Function .onInit
${IfThen} ${AlreadyRunning} ${|} ${ActivateAlreadyRunningAndAbort} ${|}
WriteUninstaller $EXEDIR\un1.exe
FunctionEnd

Function un.onInit
${IfThen} ${AlreadyRunning} ${|} ${ActivateAlreadyRunningAndAbort} ${|}
FunctionEnd


/*
Based on `Allow only one installer instance` example (https://nsis.sourceforge.io/Allow_only_one_installer_instance)

Usage example:

; Define unique mutex name (optional)
!define INSTALLERMUTEXNAME "myVeryUniqueInstallerMutexName"
!define UNINSTALLERMUTEXNAME "myVeryUniqueUninstallerMutexName"

${IfThen} ${AlreadyRunning} ${|} ${ActivateAlreadyRunningAndAbort} ${|}

${If} ${AlreadyRunning}
.. instructions before activate ..
${ActivateAlreadyRunning}
.. instructions after activate ..
Abort
${EndIf}

*/
!ifndef SingleInstance.nsh
!define SingleInstance.nsh


!include LogicLib.nsh
!include WinMessages.nsh
!include Win\WinError.nsh
!include Win\WinUser.nsh


!define AlreadyRunning `"" AlreadyRunning ""`
!macro _AlreadyRunning _a _b _t _f
!insertmacro _LOGICLIB_TEMP
!ifdef __UNINSTALL__
!define /ifndef UNINSTALLERMUTEXNAME '$(^Name)$(^UninstallCaption) Mutex'
!define /redef CHECKALREADYEXISTINGMUTEXNAME '${UNINSTALLERMUTEXNAME}'
!else
!define /ifndef INSTALLERMUTEXNAME '$(^Name)$(^SetupCaption) Mutex'
!define /redef CHECKALREADYEXISTINGMUTEXNAME '${INSTALLERMUTEXNAME}'
!endif
System::Call 'kernel32::CreateMutex(p 0, i 1, t "${CHECKALREADYEXISTINGMUTEXNAME}") ?e'
Pop $_LOGICLIB_TEMP
IntCmpU $_LOGICLIB_TEMP ${ERROR_ALREADY_EXISTS} `${_t}` `${_f}` `${_f}`
!macroend


!define ActivateAlreadyRunning `!insertmacro ActivateAlreadyRunning`
!macro ActivateAlreadyRunning
Push $0 ; Window handle
Push $1 ; Caption we are looking for
Push $2 ; Caption length
Push $3 ; GetWindowText output

StrCpy $0 '' ; Start FindWindow with NULL
!ifdef __UNINSTALL__
StrCpy $1 '$(^UninstallCaption)'
!else
StrCpy $1 '$(^SetupCaption)'
!endif
StrLen $2 $1
IntOp $2 $2 + 1 ; GetWindowText count includes \0

; loop:
FindWindow $0 '#32770' '' '' $0
StrCmp $0 0 +5 ; windownotfound: next
System::Call 'user32::GetWindowText(p r0, t.r3, i r2)'
StrCmp $3 $1 0 -3 ; windowfound: loop:

; windowfound:
SendMessage $0 ${WM_SYSCOMMAND} ${SC_RESTORE} 0 /TIMEOUT=2000 ; Restore the window if it is minimized
System::Call 'user32::SetForegroundWindow(p r0)'

; windownotfound:

Pop $3
Pop $2
Pop $1
Pop $0
!macroend


!define ActivateAlreadyRunningAndAbort `!insertmacro ActivateAlreadyRunningAndAbort`
!macro ActivateAlreadyRunningAndAbort
${ActivateAlreadyRunning}
Abort
!macroend


!endif

inco1
10-08-2023, 19:07
Ещё вопрос:
Можно ли "правильней" или "красивей" или по другому написать следующий код:

SetRegView 64
ClearErrors
EnumRegKey $0 HKLM "SOFTWARE\test" 0
${If} ${Errors}
Goto none
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
Quit
${EndIf}
none:
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Нету нужной записи в реестре"
SetRegView 32

iglezz
10-08-2023, 19:40
inco1,
1. От метки с Goto надо избавляться, раз присутствует конструкция If/Else:
SetRegView 64
ClearErrors
EnumRegKey $0 HKLM "SOFTWARE\test" 0
${If} ${Errors}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Ключ отсутствует ИЛИ недостаточно привилегий для доступа к ключу ИЛИ какая-то ошибка"
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
Quit
${EndIf}
SetRegView 32


2. Можно применить новый LogicLib-тест - RegKeyExists:SetRegView 64
${If} HKLM RegKeyExists "SOFTWARE\test"
; Существует
${Else}
; Ключ отсутствует ИЛИ недостаточно привилегий для доступа к ключу ИЛИ какая-то ошибка
${EndIf}
SetRegView 32

Код RegKeyExists:
!ifndef RegKeyExists
!macro _RegKeyExists _a _b _t _f
!insertmacro _LOGICLIB_TEMP
ClearErrors
EnumRegKey $_LOGICLIB_TEMP ${_a} `${_b}` 0
IfErrors `${_f}` `${_t}`
!macroend
!define RegKeyExists `RegKeyExists`
!endif

!!! Важное примечание:
Отсутствие ошибки EnumRegKey или положительный тест RegKeyExists значит, что ключ существует.
Ошибка после EnumRegKey или отрицательный тест RegKeyExists значит, что ключ отсутствует ИЛИ недостаточно привилегий для доступа к ключу ИЛИ какая-то ошибка

inco1
10-08-2023, 20:50
iglezz,
Для теста создал простой экзешник:

OutFile "Test.exe"
SilentInstall silent
!include "LogicLib.nsh"

Section

SetRegView 64
${If} HKLM RegKeyIsEmpty "SOFTWARE\test"
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
Quit
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Нету нужной записи в реестре"
${EndIf}
SetRegView default

SectionEnd

Пишет, что "Есть нужная запись в реестре", но такой записи в реале нету.

А мой вариант пишет правильно, что "Нету нужной записи в реестре".

OutFile "Test1.exe"
SilentInstall silent
!include "LogicLib.nsh"

Section

SetRegView 64
ClearErrors
EnumRegKey $0 HKLM "SOFTWARE\test" 0
${If} ${Errors}
Goto none
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
Quit
${EndIf}
none:
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Нету нужной записи в реестре"
SetRegView 32

SectionEnd

Что-то не так с вашим кодом.

inco1
10-08-2023, 21:24
iglezz,

OutFile "Test.exe"
SilentInstall silent
!include "LogicLib.nsh"

Section

SetRegView 64
${If} HKLM RegKeyIsEmpty "SOFTWARE\test"
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Нету нужной записи в реестре"
Quit
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
${EndIf}
SetRegView default

SectionEnd

В том то и дело, что теперь всегда показывает "Нету нужной записи в реестре", даже если запись есть.

inco1
10-08-2023, 22:15
iglezz,
В том то и дело,что я всегда проверяю с реальным реестром в двух реальных вариантах - на наличие записи, которую сам добавляю и на отсутствие,которую удаляю.
Реально работает только мой вот этот вариант, который я просил усовершенствовать:

OutFile "Test1.exe"
SilentInstall silent
!include "LogicLib.nsh"

Section

SetRegView 64
ClearErrors
EnumRegKey $0 HKLM "SOFTWARE\test" 0
${If} ${Errors}
Goto none
${Else}
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Есть нужная запись в реестре"
Quit
${EndIf}
none:
MessageBox MB_OK|MB_TOPMOST|MB_ICONSTOP "Нету нужной записи в реестре"
SetRegView 32

SectionEnd

Все предложенные вами варианты не работают. А последний пример даже не компилится.

iglezz
10-08-2023, 22:27
inco1,
Обновил своё первое сообщение и поудалял некорректные/ненужные
Пример компилируется и работает корректно.

Если вдруг будут ошибки компилятора, то нужно читать, что именно не так.

inco1
10-08-2023, 23:14
iglezz,

Огромнейшее спасибо за помощь.
В процессе проб и тестов присмотрелся к своему первоначальному коду и упростил его. Получился простой код и работает, как и раньше корректно. Вот, что получилось:

ClearErrors
EnumRegKey $0 HKLM "SOFTWARE\test" 0
${IfNot} ${Errors}
; Существует
${Else}
; Не существует
${EndIf}

iglezz
11-08-2023, 01:02
С помощью функций Win API возможна более корректная проверка ключей на не_существует/нет_доступа/другие_ошибки
ShowInstDetails show
InstallColors /windows
SetFont "Consolas" 10
AutoCloseWindow false
SetOverwrite on
RequestExecutionLevel user

!include LogicLib.nsh
!include RegistryFunc.nsh
!include SystemFunc.nsh

Section
${GetRegKeyStatus} $R0 HKLM 'Software\Microsoft' ; exist
${GetSystemErrorMessage} $R1 $R0
DetailPrint "Soft\MS: $R0: $R1"

${GetRegKeyStatus} $R0 HKLM 'qwertyuiop' ; not exist
${GetSystemErrorMessage} $R1 $R0
DetailPrint "qwertyu: $R0: $R1"

${GetRegKeyStatus} $R0 HKLM 'SAM\SAM' ; access denied
${GetSystemErrorMessage} $R1 $R0
DetailPrint "SAM\SAM: $R0: $R1"
SectionEnd

Section
${If} HKLM RegKeyExists 'Software\Microsoft'
DetailPrint "Soft\MS: exists"
${EndIf}
${If} HKLM RegKeyExists 'qwertyuiop'
DetailPrint "qwertyu: exists"
${EndIf}
${If} HKLM RegKeyExists 'SAM\SAM'
DetailPrint "SAM\SAM: exists"
${EndIf}

${If} HKLM RegKeyNotExists 'Software\Microsoft'
DetailPrint "Soft\MS: not exists"
${EndIf}
${If} HKLM RegKeyNotExists 'qwertyuiop'
DetailPrint "qwertyu: not exists"
${EndIf}
${If} HKLM RegKeyNotExists 'SAM\SAM'
DetailPrint "SAM\SAM: not exists"
${EndIf}

${If} HKLM RegKeyAccessDenied 'Software\Microsoft'
DetailPrint "Soft\MS: access denied"
${EndIf}
${If} HKLM RegKeyAccessDenied 'qwertyuiop'
DetailPrint "qwertyu: access denied"
${EndIf}
${If} HKLM RegKeyAccessDenied 'SAM\SAM'
DetailPrint "SAM\SAM: access denied"
${EndIf}
SectionEnd
!ifndef RegistryFunc.nsh
!define RegistryFunc.nsh

!include LogicLib.nsh
!include WinCore.nsh

!define KEY_QUERY_VALUE 0x0001
!define KEY_ENUMERATE_SUB_KEYS 0x0008

!macro Push_root_key root_key
!if ${root_key} == HKEY_CLASSES_ROOT
Push ${HKEY_CLASSES_ROOT}
!else if ${root_key} == HKCR
Push ${HKEY_CLASSES_ROOT}
!else if ${root_key} == HKEY_CURRENT_USER
Push ${HKEY_CURRENT_USER}
!else if ${root_key} == HKCU
Push ${HKEY_CURRENT_USER}
!else if ${root_key} == HKEY_LOCAL_MACHINE
Push ${HKEY_LOCAL_MACHINE}
!else if ${root_key} == HKLM
Push ${HKEY_LOCAL_MACHINE}
!else if ${root_key} == HKEY_USERS
Push ${HKEY_USERS}
!else if ${root_key} == HKU
Push ${HKEY_USERS}
!else if ${root_key} == HKEY_PERFORMANCE_DATA
Push ${HKEY_PERFORMANCE_DATA}
!else if ${root_key} == HKEY_CURRENT_CONFIG
Push ${HKEY_CURRENT_CONFIG}
!else if ${root_key} == HKCC
Push ${HKEY_CURRENT_CONFIG}
!else if ${root_key} == HKEY_DYN_DATA
Push ${HKEY_DYN_DATA}
!else
Push '${root_key}'
!endif
!macroend

!define GetRegKeyStatus `!insertmacro GetRegKeyStatus `
!macro GetRegKeyStatus result root_key sub_key
Push $0
Push '${sub_key}'
!insertmacro Push_root_key ${root_key}
System::Call "Advapi32::RegOpenKeyEx(is, ts, i0, i${KEY_QUERY_VALUE}|${KEY_ENUMERATE_SUB_KEYS}, *p.r0) i.s"
StrCmp $0 0 +2
System::Call "Advapi32::RegCloseKey(i r0) i"
Exch
Pop $0
Pop ${result}
!macroend

!define RegKeyExists `RegKeyExists`
!macro _RegKeyExists _a _b _t _f
!insertmacro _LOGICLIB_TEMP
ClearErrors
EnumRegKey $_LOGICLIB_TEMP ${_a} `${_b}` 1
IfErrors `${_f}` `${_t}`
!macroend

!define RegKeyNotExists `RegKeyNotExists`
!macro _RegKeyNotExists _a _b _t _f
!insertmacro _LOGICLIB_TEMP
${GetRegKeyStatus} $_LOGICLIB_TEMP ${_a} '${_b}'
StrCmp $_LOGICLIB_TEMP 2 `${_t}` `${_f}`
!macroend

!define RegKeyAccessDenied `RegKeyAccessDenied`
!macro _RegKeyAccessDenied _a _b _t _f
!insertmacro _LOGICLIB_TEMP
${GetRegKeyStatus} $_LOGICLIB_TEMP ${_a} '${_b}'
StrCmp $_LOGICLIB_TEMP 5 `${_t}` `${_f}`
!macroend

!endif
!ifndef SystemFunc.nsh
!define SystemFunc.nsh

!define GetSystemErrorMessage `!insertmacro GetSystemErrorMessage `
!macro GetSystemErrorMessage result error_code
System::Call 'kernel32::GetSystemDefaultUILanguage()i.s'
Push ${error_code}
System::Call "kernel32::FormatMessage(i0x1300, in, is, is, *t.s, i${NSIS_MAX_STRLEN}, in)i"
Pop ${result}
!macroend

!endif




© OSzone.net 2001-2012