Показать полную графическую версию : .: NSIS - все вопросы :. часть 2.
Пример из справочника плох тем, что он немного неправильный по части реализации и устаревший (${NSIS_VERSION} < 3 && ANSI).
Базовый пример для проверки на запуск копии приложения есть в базовой справке.
Более правильный пример с автопереключеніем на уже запущенную копию есть на сайте - Allow only one installer instance (https://nsis.sourceforge.io/Allow_only_one_installer_instance).
iglezz, приветствую.
Простейший цикл последовательного чтения файла:
Код
FileOpen $handle $filename R
${Do}
FileRead $handle $fileread
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
DetailPrint '[$fileread]'
${Loop}
FileClose $handle
Ничего не получается. Можете показать пример поиска конкретной записи, вот как в этом цикле:
FileOpen $0 "test.txt" R
${LineSum} "test.txt" $R0
StrCpy $R1 0
readnext:
IntOp $R1 $R1 + 1
IntCmp $R1 $R0 0 0 end
${LineRead} "test.txt" "$R1" $R3
${WordFind} "$R3" "test-test" "E+1{" $R2
IfErrors readnext 0
MessageBox MB_OK "Найдена фраза ( test-test )"
end:
FileClose $0
Пример под спойлером годится для извлечения/поиска информации, для [пере]записи будет несколько по другому.
ShowInstDetails show
RequestExecutionLevel user
!include Util.nsh
!include LogicLib.nsh
!include StrFunc.nsh
${Using:StrFunc} StrLoc
!define FileReadAuto `!insertmacro FileReadAuto`
!macro FileReadAuto ISUTF16LE HANDLE READLINE
StrCmp ${ISUTF16LE} 0 0 +3
FileRead ${HANDLE} ${READLINE}
Goto +2
FileReadUTF16LE ${HANDLE} ${READLINE}
!macroend
!define FileFindStrStruct `(i, i, &t${NSIS_MAX_STRLEN}) p`
/* {
номер строки (начинается с 1),
позиция искомого в строке (начинается с 0),
строка, содержащая искомую строку
}
*/
!define FileFindStr `!insertmacro FileFindStr`
!macro FileFindStr OUTPUT FILENAME STRTOFIND
Push '${STRTOFIND}'
Push '${FILENAME}'
${CallArtificialFunction} FileFindStr_macro
Pop ${OUTPUT}
!macroend
!macro FileFindStr_macro
Exch $0 ; [in] FileName / [out] ReturnStructAddr
Exch
Exch $1 ; StrToFind
Push $2 ; FileHandle
Push $3 ; ISUTF16LEFlag
Push $4 ; ReadData
Push $5 ; StrToFindLine
Push $6 ; StrToFindPosInLine
Push $7 ; ReturnStructAddr
; инициализация переменных
StrCpy $5 0 ; Reset Line counter
StrCpy $7 0 ; Reset ReturnStructAddr
FileOpen $2 $0 R
IfErrors FileFindStr_macro_end
; определение читающей инструкции (FileRead | FileReadUTF16LE)
FileReadWord $2 $4
${If} $4 = 0xFEFF
StrCpy $3 1
${Else}
StrCpy $3 0
${EndIf}
FileSeek $2 0 SET
; основной цикл построчного чтения файла
${Do}
${FileReadAuto} $3 $2 $4
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
IntOp $5 $5 + 1
${StrLoc} $6 $4 $1 >
${If} $6 != ''
; если строка найдена -> пишем результат в структуру ..
System::Call '*${FileFindStrStruct} (r5, r6, r4) .r7'
; .. и выходим
${ExitDo}
${EndIf}
${Loop}
FileClose $2
FileFindStr_macro_end:
StrCpy $0 $7
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
!macroend
Section
${FileFindStr} $0 '${NSISDIR}\Include\StrFunc.nsh' 'macro '
${If} $0 <> 0
; распаковка структуры
System::Call '*$0${FileFindStrStruct} (.r1, .r2, .r3)'
DetailPrint 'Line: $1'
DetailPrint 'Pos: $2'
DetailPrint 'Str: $3'
${EndIf}
SectionEnd
iglezz, Спасибо за пример, но я так вообще и не понял, как к этому примеру прикрутить мой файл "test.txt" и искомую фразу "test-test", как в моём примере выше.
inco1,
В этом примере
${FileFindStr} результат файл строка
если строка найдена, то результат будет отличен от нуля
iglezz, еще раз благодарю. Долго же до меня доходят очевидные вещи. Видать возраст.
Еще такой интересный вопрос. Как правильно сравнить две переменные?
Например, есть переменные $R5 и $R6. В обеих есть некое значение из цифр и английских букв. Это неизвестное значение может быть, как одинаковым, так и разным.
Код, что ниже не работает, хотя я для теста специально ставил в переменные одинаковые значения - "0x03e700ff" , а показывало $R5 != "0x03e700ff", а когда менял местами $R5 и $R6, то показывало $R6 != "0x03e700ff". Что подтверждает, что значения в переменных одинаковы.
StrCmp $R5 "$R6" 0 +3
DetailPrint '$$R5 == "$R6"'
Goto +2
DetailPrint '$$R5 != "$R6"'
Что еще можно использовать для данной ситуации?
Код, что ниже не работает, хотя ..»
Должен работать. Если не работает, значит есть малозаметная ошибка/опечатка.
Как правильно сравнить две переменные? »
В NSIS любая переменная хранится как строка, для для манипуляций с числами эта строка преобразуется в число.
StrCmp для чисел подходит только в случае, когда гарантированно совпадёт система счисления. Число 16 (десятичное) может быть записано как 0x10 (шестнадцатеричная) или 020 (восьмеричная) и для IntCmp все эти формы одинаковы.
iglezz,
Ну да, должен работать, но не работает. Вот с этого кода скомпилите экзешник и сами убедитесь:
RequestExecutionLevel user
OutFile "test.exe"
!include "LogicLib.nsh"
!include "WordFunc.nsh"
!include "TextFunc.nsh"
Function .onInit
StrCpy $R6 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$R6",t.r3,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t.r2,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
IntFmt $1 "%#.8x" $1
StrCpy $R7 "$1"
${EndIf}
${LineSum} "Info.txt" $R0
StrCpy $R1 0
IntOp $R1 $R1 + 1
IntCmp $R1 $R0 0 0 end
${LineRead} "Info.txt" "$R1" $R3
end:
StrCpy $R8 "$R3"
FunctionEnd
Section Message
MessageBox MB_OK " 1значение $R7 - 2значение $R8 "
StrCmp $R7 "$R8" Well Unequal
Well:
MessageBox MB_OK "Значения равны"
Goto Next
Unequal:
MessageBox MB_OK "Значения не равны"
Next:
StrCmp $R7 '$R8' 0 +3
DetailPrint '$$R7 == "$R8"'
Goto +2
DetailPrint '$$R7 != "$R8"'
SectionEnd
Section File
FileOpen $0 "Info.txt" w
FileWrite $0 "$R7$\r$\n"
FileClose $0
SectionEnd
Первый запуск не считается, потому что еще не будет файла Info.txt. А вот второй запуск в сообщении визуально покажет, что переменные бы равны, но по двум кодам сравнения через StrCmp $R7 '$R8' покажет, что совсем не равны.
inco1, Достаточно заменить MessageBox на такой MessageBox MB_OK "[$R7]$\n[$R8]"
и сразу станет видна причина - строка считывается с файла вместе с символами окончания строки (\r\n)
Прочитанную из файла строку надо чистить от них (TrimNewLines в TextFunc.nsh)
Вот спасибо. Пол дня пытался понять, что не так. Я и подозревал, что что то считывается невидимое, потому что, если напрямую присваивал любые одинаковые значения, то было всё правильно.
Начну знакомство с очисткой.
P.S. Я так понял, что нельзя в моём конкретном примере обойтись как нибудь без $\n и неизвестной для меня очистки? Ведь будет только одна строка.
Самый простой способ хранения значений в файле - использовать ini-файл (ReadINIStr/WriteINIStr)
Попробую.
Добавлено:
Всё получилось и работает как надо. Это я так хочу использовать "уникальную метку" системы. Но не уверен, что данные, те что я использую будут уникальными для всех систем:
StrCpy $R6 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$R6",t.r3,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t.r2,i ${NSIS_MAX_STRLEN})i.r0'
В связи с этим еще один вопрос, откуда в системе виндовс можно взять "метку", чтобы на 100 процентов или почти на 100 процентов эти данные были "уникальными" для каждой системы?
откуда в системе виндовс можно взять "метку", чтобы на 100 процентов или почти на 100 процентов эти данные были "уникальными" для каждой системы? »
Кроме ID винта, используют MAC сетевухи, время создания системных каталогов или всё это в совокупности + иногда математика с этими данными...
MKN, приветствую.
Как записать ID винта? Или ID винта это его серийный номер?
inco1,
есть миниатюрный плагин для определения инфы о HDD (см. прикреплённый файл)
или
OutFile "GetVolumeInformation.exe"
; под серийным номером подразумевается "Volume ID"
var ser
var ser1
var disk
!define GetVolumeInformation "Kernel32::GetVolumeInformation(t,t,i,*i,*i,*i,t,i) i"
Section
; определяем системный диск
StrCpy $disk $windir
StrCpy $disk $windir 3
MessageBox MB_OK $disk
System::Call '${GetVolumeInformation} ("$disk",,${NSIS_MAX_STRLEN},.r0,,,,${NSIS_MAX_STRLEN})'
IntFmt $ser "%08X" $0 ; из цифрового - HEX
; стандартное представление: 4 символа-4символа
StrCpy $ser1 $ser 4 ; берём первые 4 символа
StrCpy $ser $ser "" 4 ; отсекаем первые 4 символа
StrCpy $ser "$ser1-$ser"
MessageBox MB_OK "VolumeID $ser"
SectionEnd
iglezz, Доброго вам дня и здоровья.
Походу в вашем коде поиска строки баг. Вчера целый день потратил, чтобы найти проблему. Я то ведь сразу вставлял ваш код в мой огромный код и строку не искало. А экзешник с одного вашего кода четко и быстро находит. Я потом давай убирать с моего кода по строкам всё, пока не нашел причину.
Вот экзешник с вашим кодом, который прекрасно находит слово "Word.com" в файле hosts:
RequestExecutionLevel user
SilentInstall silent
!include Util.nsh
!include LogicLib.nsh
!include StrFunc.nsh
${Using:StrFunc} StrLoc
!define FileReadAuto `!insertmacro FileReadAuto`
!macro FileReadAuto ISUTF16LE HANDLE READLINE
StrCmp ${ISUTF16LE} 0 0 +3
FileRead ${HANDLE} ${READLINE}
Goto +2
FileReadUTF16LE ${HANDLE} ${READLINE}
!macroend
!define FileFindStrStruct `(i, i, &t${NSIS_MAX_STRLEN}) p`
!define FileFindStr `!insertmacro FileFindStr`
!macro FileFindStr OUTPUT FILENAME STRTOFIND
Push '${STRTOFIND}'
Push '${FILENAME}'
${CallArtificialFunction} FileFindStr_macro
Pop ${OUTPUT}
!macroend
!macro FileFindStr_macro
Exch $0
Exch
Exch $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
StrCpy $5 0
StrCpy $7 0
FileOpen $2 $0 R
IfErrors FileFindStr_macro_end
FileReadWord $2 $4
${If} $4 = 0xFEFF
StrCpy $3 1
${Else}
StrCpy $3 0
${EndIf}
FileSeek $2 0 SET
${Do}
${FileReadAuto} $3 $2 $4
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
IntOp $5 $5 + 1
${StrLoc} $6 $4 $1 >
${If} $6 != ''
System::Call '*${FileFindStrStruct} (r5, r6, r4) .r7'
${ExitDo}
${EndIf}
${Loop}
FileClose $2
FileFindStr_macro_end:
StrCpy $0 $7
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
!macroend
Section
${FileFindStr} $0 '$SYSDIR\drivers\etc\hosts' 'Word.com'
${If} $0 <> 0
MessageBox MB_OK " Нужное слово найдено "
${Else}
MessageBox MB_OK " Нужное слово НЕ найдено "
${EndIf}
SectionEnd
А вот в код добавлена функция с двумя строчками и он перестал искать.
RequestExecutionLevel user
SilentInstall silent
!include Util.nsh
!include LogicLib.nsh
!include StrFunc.nsh
${Using:StrFunc} StrLoc
!define FileReadAuto `!insertmacro FileReadAuto`
!macro FileReadAuto ISUTF16LE HANDLE READLINE
StrCmp ${ISUTF16LE} 0 0 +3
FileRead ${HANDLE} ${READLINE}
Goto +2
FileReadUTF16LE ${HANDLE} ${READLINE}
!macroend
!define FileFindStrStruct `(i, i, &t${NSIS_MAX_STRLEN}) p`
!define FileFindStr `!insertmacro FileFindStr`
!macro FileFindStr OUTPUT FILENAME STRTOFIND
Push '${STRTOFIND}'
Push '${FILENAME}'
${CallArtificialFunction} FileFindStr_macro
Pop ${OUTPUT}
!macroend
!macro FileFindStr_macro
Exch $0
Exch
Exch $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
StrCpy $5 0
StrCpy $7 0
FileOpen $2 $0 R
IfErrors FileFindStr_macro_end
FileReadWord $2 $4
${If} $4 = 0xFEFF
StrCpy $3 1
${Else}
StrCpy $3 0
${EndIf}
FileSeek $2 0 SET
${Do}
${FileReadAuto} $3 $2 $4
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
IntOp $5 $5 + 1
${StrLoc} $6 $4 $1 >
${If} $6 != ''
System::Call '*${FileFindStrStruct} (r5, r6, r4) .r7'
${ExitDo}
${EndIf}
${Loop}
FileClose $2
FileFindStr_macro_end:
StrCpy $0 $7
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
!macroend
Section
${FileFindStr} $0 '$SYSDIR\drivers\etc\hosts' 'Word.com'
${If} $0 <> 0
MessageBox MB_OK " Нужное слово найдено "
${Else}
MessageBox MB_OK " Нужное слово НЕ найдено "
${EndIf}
SectionEnd
Function .onInit
Var /GLOBAL Proga
ReadRegStr $Proga HKLM "SOFTWARE\Test" "Test"
FunctionEnd
inco1, да, в nsis вечно забываю сбрасывать error флаг
в макросе FileFindStr_macro перед
FileOpen $2 $0 R надо добавить
ClearErrors
iglezz,
Теперь заработало, как надо. Спасибо за оперативный отклик.
P.S. Сравнивал скорость поиска по ${LineRead} и вашим кодом. Брал 400 строк и нужная вконце, одна строка - одно слово. Ваш код находит мгновенно, а через ${LineRead} около 8-10 секунд.
Всем доброго дня.
Помогите, пожалуйста с такой проблемой. В одной из папок имеются одна папка с известным названием и несколько неизвестных папок ("Test kkkkkk", "Test ххх", "Test yyyyyyyy", "Test zzzz", ....). Во всех папок первое слово одинаковое. Нужно удалить неизвестные папки, у которых значения k, x, Y, z, ... непостоянные (неизвестные).
Как вариант подойдет что нибудь типа "удалить все папки, кроме одной с известным названием".
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.