Показать полную графическую версию : .: NSIS - все вопросы :. часть 2.
Для поиска файлов можно применить Locate (https://nsis.sourceforge.io/Docs/AppendixE.html#locate) из FileFunc.nsh
Для сопоставления имён файлов - WinAPI-функции PathMatchSpec (https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathmatchspecw)/PathMatchSpecEx (https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathmatchspecexw)
PathMatchSpecEx может сопоставлять строку с множеством шаблонов, разделяемых точкой с запятой (из-за чего ";" в шаблонах использовать нельзя).
!appendfile 'test ccc' ''
!appendfile 'test1234' ''
!system 'md "test"'
!system 'md " test2"'
!system 'md "test aaa"'
!system 'md "test bbb"'
!system 'md "test xxx"'
!system 'md "test yyy"'
!system 'md "test_xyz"'
ShowInstDetails show
RequestExecutionLevel user
SetFont 'Fira Code Retina' 9
InstallColors /windows
!include LogicLib.nsh
!include FileFunc.nsh
Section UseLocate
${Locate} $EXEDIR '/M=test *' DeleteFilesByMask
SectionEnd
Function DeleteFilesByMask
SetDetailsPrint both
System::Call 'shlwapi.dll::PathMatchSpecEx(tR7, ts, i1)p.R0' 'test xxx;test yyy'
${If} $R0 == 1
${If} $R6 == ''
DetailPrint 'RMDir $R7'
; RMDir /r '$R9'
${Else}
DetailPrint 'Delete $R7'
; Delete '$R9'
${EndIf}
${Else}
DetailPrint 'Skip $R7'
${EndIf}
Push ''
SetDetailsPrint textonly
FunctionEnd
AlekseyPopovv
26-04-2023, 05:20
Всем привет. Столкнулся недавно с файлами *.json.
Нашёл плагин NsJSON.
Как создать файл с данными я понял:
nsJSON::Set /file "$APPDATA\Prog\config.json"
nsJSON::Set /Value `{}`
nsJSON::Set `license_file` /value `"$APPDATA\\Prog\\license.lic",`
nsJSON::Serialize /format /file "$APPDATA\Prog\config.json"
а как потом из этого файла удалить строки не понял. Может кто знает?
а как потом из этого файла удалить строки не понял. »
nsJSON::Delete [NodePath] /end
У меня этот плагин работает некорректно на удаление и имеет проблемы с чтением некоторых файлов (например, при наличи пустого массива с них).
Автор плагина давно пропал, так что надеятся на исправление ошибок особо не стоит.
Лучше использовать более проверенный временем инструмент вроде jq (https://stedolan.github.io/jq/)
Всем хорошего дня и здоровья.
Помогите разобраться. Не могу разобраться с условиями, когда все последующие условия привязаны к первому условию, а в этих последующих условиях есть свои условия.... Правильно ли расставил ${EndIf} с такими условиями. По предварительным тестам работает, но не уверен в правильности кода. Последовательность действий изменять нельзя:
Section Run64
; если запущено на х64
${If} ${RunningX64}
; (здесь некое действие) ;; == произойдет некое действие
${If} ${FileExists} "$R1\A.exe"
; (здесь некое действие) ;; == если найден файл A.exe, то произойдет некое действие
${EndIf}
${IfNot} ${FileExists} "$R2\A.txt"
${AndIfNot} ${FileExists} "$R2\B.txt" ;; == если не найден файл A.txt и B.txt , то произойдет некое действие
; (здесь некое действие)
${EndIf}
${IfNot} ${FileExists} "$R3\B.exe" ;; == если не найден файл B.exe, то произойдет некое действие
; (здесь некое действие)
${EndIf}
${If} $R4 != 1234567890 ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
; (здесь некое действие)
${If} ${FileExists} "$R5\C.exe" ;; == если значение переменной $R4 не равно 1234567890, и найдены файлы C.exe и D.exe, то произойдет некое действие
${AndIf} ${FileExists} "$R5\D.exe"
; (здесь некое действие)
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf}
SectionEnd
Правильно ли расставил ${EndIf} с такими условиями. »
Для начала надо отформатировать код так, чтобы отступы отражали степень вложенности фрагментов этого кода.
Так будет легче увидеть логические ошибки, которые не ловятся компилятором.
Section Run64
; если запущено на х64
${If} ${RunningX64}
; (здесь некое действие) ;; == произойдет некое действие
${If} ${FileExists} "$R1\A.exe"
; (здесь некое действие) ;; == если найден файл A.exe, то произойдет некое действие
${EndIf}
${IfNot} ${FileExists} "$R2\A.txt"
${AndIfNot} ${FileExists} "$R2\B.txt" ;; == если не найден файл A.txt и B.txt , то произойдет некое действие
; (здесь некое действие)
${EndIf}
${IfNot} ${FileExists} "$R3\B.exe" ;; == если не найден файл B.exe, то произойдет некое действие
; (здесь некое действие)
${EndIf}
${If} $R4 != 1234567890 ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
; (здесь некое действие)
${If} ${FileExists} "$R5\C.exe" ;; == если значение переменной $R4 не равно 1234567890, и найдены файлы C.exe и D.exe, то произойдет некое действие
${AndIf} ${FileExists} "$R5\D.exe"
; (здесь некое действие)
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf}
SectionEnd
Далее нужно избавляться от избыточной вложенности и/или сложности, порой с изменением структуры проекта.
iglezz,
Для начала надо отформатировать код так, чтобы отступы отражали степень вложенности фрагментов этого кода
Да, так виднее. И сразу выплыла ошибка в конце кода:
Section Run64
; если запущено на х64
${If} ${RunningX64}
; (здесь некое действие) ;; == произойдет некое действие
${If} ${FileExists} "$R1\A.exe"
; (здесь некое действие) ;; == если найден файл A.exe, то произойдет некое действие
${EndIf}
${IfNot} ${FileExists} "$R2\A.txt"
${AndIfNot} ${FileExists} "$R2\B.txt" ;; == если не найден файл A.txt и B.txt , то произойдет некое действие
; (здесь некое действие)
${EndIf}
${IfNot} ${FileExists} "$R3\B.exe" ;; == если не найден файл B.exe, то произойдет некое действие
; (здесь некое действие)
${EndIf}
${If} $R4 != 1234567890 ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
; (здесь некое действие)
${If} ${FileExists} "$R5\C.exe" ;; == если значение переменной $R4 не равно 1234567890, и найдены файлы C.exe и D.exe, то произойдет некое действие
${AndIf} ${FileExists} "$R5\D.exe"
; (здесь некое действие)
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf}
; (здесь некое действие) ;; == если значение переменной $R4 не равно 1234567890, то произойдет некое действие
${EndIf} ;; == если запущено на х64, то произойдет некое действие
SectionEnd
И еще вопрос, обязательно ли прописывать к примеру условие: "если файл найден" если следует команда на удаление этого самого файла или что то похожее в этом роде? Это будет "легче" для кода или нейтрально?
И еще вопрос, обязательно ли прописывать к примеру условие: "если файл найден" если следует команда на удаление этого самого файла или что то похожее в этом роде? Это будет "легче" для кода или нейтрально? »
Проверять наличие файла перед удалением не обязательно, но имеет смысл результат, если файл существует, но не может быть удалёнClearErrors
Delete FILESPEC
${If} ${Errors}
MessageBox MB_OK "Хьюстон, у нас проблема"
Quit
${EndIf}
И еще вопрос, может кто знает, по каким параметрам некоторые разработчики прописывают проверку, что программа запущена на виртуалке?
VM обнаруживается по записям с аппаратной конфигурации/драйверов, специфическим записям в реестре, файлам, процессам, сервисам.
В случае универсального детектора требуется проверить множество позиций как минимум для HyperV, VirtualBox, VMWare.
AlekseyPopovv
01-06-2023, 15:08
Как удалить записи из реестра после работы приложения по путям:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\bam\State\UserSettings\S-1-5-21-1528902807-2110943787-476340328-1000
AlekseyPopovv,
В первом случае сложностей не вижу
Во втором случае вижу пару особенностей в виде необходимости получения SID и преобразования буквы диска в имя устройства
Для получения SID текущено пользователя можно применить макрос GetCurrentUserSID !define GetCurrentUserSID `!insertmacro GetCurrentUserSID `
!macro GetCurrentUserSID out_SID
Push $0 ; fn ret / out_SID
Push $1 ; SID struct
Push $2 ; tmp
System::Call "advapi32::GetUserName(t.s, *i${NSIS_MAX_STRLEN}) i.r0"
StrCmp $0 0 +5
System::Call 'advapi32::LookupAccountName(i0, ts, @r1, *i${NSIS_MAX_STRLEN}, t .r2, *i ${NSIS_MAX_STRLEN}, *i .r2 ) i.r0'
StrCmp $0 0 +3
System::Call 'advapi32::ConvertSidToStringSid(pr1, *t.r0 )'
Goto +2
StrCpy $0 ''
Pop $2
Pop $1
Exch $0
Pop ${out_SID}
!macroend
Пример использования:
${GetCurrentUserSID} $0
DetailPrint 'SID = [$0]'
Если надо пройтись по всем пользователям, то можно использовать макрос EnumUsersReg EnumUsersRegEx (https://github.com/iglezz/NSIS-examples/blob/master/Include/EnumUsersRegEx.nsh) (пример (https://github.com/iglezz/NSIS-examples/blob/master/Examples/EnumUsersRegEx.nsi)).
Для преобразования пути в простейшем случае (c:\path -> \Device\HarddiskVolume3\path) можно использовать такой макрос:!define GetPathWithDeviceName `!insertmacro GetPathWithDeviceName `
!macro GetPathWithDeviceName out_DevPath in_DOSPath
Push '${in_DOSPath}'
Exch $0
Push $1
Push $2
StrLen $1 $0
StrCmp $1 1 0 +3
StrCpy $1 $0:
Goto +2
StrCpy $1 $0 2
System::Call 'kernel32::QueryDosDevice(tr1, t.r2, i${NSIS_MAX_STRLEN} ) i.r3'
StrCmp $3 0 0 +3
StrCpy $0 ''
Goto +3
StrCpy $0 $0 '' 2
StrCpy $0 $2$0
Pop $2
Pop $1
Exch $0
Pop ${out_DevPath}
!macroend
Пример использования:
${GetPathWithDeviceName} $0 "C:\path\to\file"
DetailPrint 'path = [$0]'
AlekseyPopovv
02-06-2023, 18:36
Как покрасить эти места в белый?
Function MyGUIInit
System::Call "user32::GetWindowLong(i$HWNDPARENT,i-20)i.s"
System::Int64Op "0x80000" |
System::Call "user32::SetWindowLong(i$HWNDPARENT,i-20,is)"
System::Call "user32::SetLayeredWindowAttributes(i$HWNDPARENT,i,i243,i0x00000002)"
GetDlgItem $R0 $HWNDPARENT 1034
GetDlgItem $R1 $HWNDPARENT 1037
GetDlgItem $R2 $HWNDPARENT 1038
SetCtlColors $R0 000000 FFFFFF
SetCtlColors $R1 000000 FFFFFF
SetCtlColors $R2 000000 FFFFFF
FunctionEnd
Кроме замены цвета фона окна (в .onGUIInit) надо ещё поменять цвет фона каждой страницы и всех элементов в ней (в show-функции для каждой страницы)
!include WinMessages.nsh
RequestExecutionLevel user
InstallDir $TEMP
Page components "" cshow
Page directory "" dshow
Page instfiles "" ishow
; define background color
!define BACKGROUNDCOLOR 0xFFFFFF
Section `Dummy Section`
DetailPrint ...
SectionEnd
Function cshow
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1017
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1021
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1022
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1023
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1032
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
FunctionEnd
Function dshow
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1019
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
; ...
FunctionEnd
Function ishow
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
FunctionEnd
Function .onGUIInit
; repaint window
SetCtlColors $HWNDPARENT '' ${BACKGROUNDCOLOR}
; set BrandingText ${BACKGROUNDCOLOR} background
GetDlgItem $0 $HWNDPARENT 1028
SetCtlColors $0 '' transparent
FunctionEnd
Фон также можно задавать для каждой отдельной страницы
!include WinMessages.nsh
RequestExecutionLevel user
InstallDir $TEMP
Page components "" cshow
Page directory "" dshow
Page instfiles "" ishow
!define /ifndef RDW_INVALIDATE 0x0001
!define /ifndef RDW_ERASE 0x0004
; define background color
!define BACKGROUNDCOLOR 0xFFFFFF
Section `Dummy Section`
DetailPrint ...
SectionEnd
Function cshow
; repaint window
SetCtlColors $HWNDPARENT '' ${BACKGROUNDCOLOR}
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1017
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1021
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1022
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1023
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1032
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
System::Call "user32::RedrawWindow(i,i,i,i)i ($HWNDPARENT, 0, 0,${RDW_INVALIDATE}|${RDW_ERASE})"
FunctionEnd
Function dshow
; redefine page background
!define /redef BACKGROUNDCOLOR 0x88ff88
; repaint window
SetCtlColors $HWNDPARENT '' ${BACKGROUNDCOLOR}
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1019
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1020
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1023
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1024
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
System::Call "user32::RedrawWindow(i,i,i,i)i ($HWNDPARENT, 0, 0,${RDW_INVALIDATE}|${RDW_ERASE})"
FunctionEnd
Function ishow
; redefine page background
!define /redef BACKGROUNDCOLOR 0xabcdef
; repaint window
SetCtlColors $HWNDPARENT '' ${BACKGROUNDCOLOR}
; repaint page
FindWindow $1 "#32770" "" $HWNDPARENT
SetCtlColors $1 '' ${BACKGROUNDCOLOR}
; repaint page controls
GetDlgItem $0 $1 1031
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
GetDlgItem $0 $1 1006
SetCtlColors $0 '' ${BACKGROUNDCOLOR}
System::Call "user32::RedrawWindow(i,i,i,i)i ($HWNDPARENT, 0, 0,${RDW_INVALIDATE}|${RDW_ERASE})"
FunctionEnd
Function .onGUIInit
; set BrandingText${BACKGROUNDCOLOR} background
GetDlgItem $0 $HWNDPARENT 1028
SetCtlColors $0 '' transparent
FunctionEnd
AlekseyPopovv
03-06-2023, 16:20
Как переименовать кнопку отмена на кастомной странице ReadmePage?
Пример прямо в справке есть
GetDlgItem $1 $HWNDPARENT 2
SendMessage $1 ${WM_SETTEXT} 0 "STR:Goodbye"
id кнопок:
1 = next
2 = cancel
3 = back
AlekseyPopovv
04-06-2023, 11:41
Есть у кого ни будь пример кастомной страницы MUI_PAGE_INSTFILES?
AlekseyPopovv
04-06-2023, 16:43
Как убрать кнопку закрыть и сделать кнопку отмена активной?
Как убрать кнопку закрыть и сделать кнопку отмена активной? »
Инструкция ShowWindow с примером в справке, аналогично переименовыванию.
Отмену активной сделать мало, там ещё много чего написать надо для обработки этой отмены - InstFiles Cancel - Allowing a user to cancel installation during InstFiles (https://nsis.sourceforge.io/InstFiles_Cancel_-_Allowing_a_user_to_cancel_installation_during_InstFiles)
AlekseyPopovv
06-06-2023, 16:38
iglezz, как поменять шрифт над прогресс баром?
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC