PDA

Показать полную графическую версию : .: 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
02-04-2023, 18:39
Пример из справочника плох тем, что он немного неправильный по части реализации и устаревший (${NSIS_VERSION} < 3 && ANSI).

Базовый пример для проверки на запуск копии приложения есть в базовой справке.
Более правильный пример с автопереключеніем на уже запущенную копию есть на сайте - Allow only one installer instance (https://nsis.sourceforge.io/Allow_only_one_installer_instance).

inco1
07-04-2023, 03:22
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

iglezz
07-04-2023, 13:09
Пример под спойлером годится для извлечения/поиска информации, для [пере]записи будет несколько по другому.

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

inco1
07-04-2023, 16:42
iglezz, Спасибо за пример, но я так вообще и не понял, как к этому примеру прикрутить мой файл "test.txt" и искомую фразу "test-test", как в моём примере выше.

iglezz
07-04-2023, 17:09
inco1,
В этом примере
${FileFindStr} результат файл строка
если строка найдена, то результат будет отличен от нуля

inco1
07-04-2023, 17:37
iglezz, еще раз благодарю. Долго же до меня доходят очевидные вещи. Видать возраст.

inco1
07-04-2023, 20:10
Еще такой интересный вопрос. Как правильно сравнить две переменные?
Например, есть переменные $R5 и $R6. В обеих есть некое значение из цифр и английских букв. Это неизвестное значение может быть, как одинаковым, так и разным.
Код, что ниже не работает, хотя я для теста специально ставил в переменные одинаковые значения - "0x03e700ff" , а показывало $R5 != "0x03e700ff", а когда менял местами $R5 и $R6, то показывало $R6 != "0x03e700ff". Что подтверждает, что значения в переменных одинаковы.

StrCmp $R5 "$R6" 0 +3
DetailPrint '$$R5 == "$R6"'
Goto +2
DetailPrint '$$R5 != "$R6"'

Что еще можно использовать для данной ситуации?

iglezz
07-04-2023, 21:58
Код, что ниже не работает, хотя ..»
Должен работать. Если не работает, значит есть малозаметная ошибка/опечатка.

Как правильно сравнить две переменные? »
В NSIS любая переменная хранится как строка, для для манипуляций с числами эта строка преобразуется в число.
StrCmp для чисел подходит только в случае, когда гарантированно совпадёт система счисления. Число 16 (десятичное) может быть записано как 0x10 (шестнадцатеричная) или 020 (восьмеричная) и для IntCmp все эти формы одинаковы.

inco1
07-04-2023, 22:54
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' покажет, что совсем не равны.

iglezz
07-04-2023, 23:10
inco1, Достаточно заменить MessageBox на такой MessageBox MB_OK "[$R7]$\n[$R8]"
и сразу станет видна причина - строка считывается с файла вместе с символами окончания строки (\r\n)
Прочитанную из файла строку надо чистить от них (TrimNewLines в TextFunc.nsh)

inco1
07-04-2023, 23:28
Вот спасибо. Пол дня пытался понять, что не так. Я и подозревал, что что то считывается невидимое, потому что, если напрямую присваивал любые одинаковые значения, то было всё правильно.
Начну знакомство с очисткой.

P.S. Я так понял, что нельзя в моём конкретном примере обойтись как нибудь без $\n и неизвестной для меня очистки? Ведь будет только одна строка.

iglezz
07-04-2023, 23:35
Самый простой способ хранения значений в файле - использовать ini-файл (ReadINIStr/WriteINIStr)

inco1
07-04-2023, 23:39
Попробую.

Добавлено:

Всё получилось и работает как надо. Это я так хочу использовать "уникальную метку" системы. Но не уверен, что данные, те что я использую будут уникальными для всех систем:

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 процентов эти данные были "уникальными" для каждой системы?

MKN
08-04-2023, 09:24
откуда в системе виндовс можно взять "метку", чтобы на 100 процентов или почти на 100 процентов эти данные были "уникальными" для каждой системы? »
Кроме ID винта, используют MAC сетевухи, время создания системных каталогов или всё это в совокупности + иногда математика с этими данными...

inco1
08-04-2023, 09:37
MKN, приветствую.
Как записать ID винта? Или ID винта это его серийный номер?

MKN
08-04-2023, 12:04
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

inco1
09-04-2023, 14:46
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

iglezz
09-04-2023, 15:22
inco1, да, в nsis вечно забываю сбрасывать error флаг
в макросе FileFindStr_macro перед
FileOpen $2 $0 R надо добавить
ClearErrors

inco1
09-04-2023, 15:44
iglezz,

Теперь заработало, как надо. Спасибо за оперативный отклик.

P.S. Сравнивал скорость поиска по ${LineRead} и вашим кодом. Брал 400 строк и нужная вконце, одна строка - одно слово. Ваш код находит мгновенно, а через ${LineRead} около 8-10 секунд.

inco1
25-04-2023, 19:30
Всем доброго дня.
Помогите, пожалуйста с такой проблемой. В одной из папок имеются одна папка с известным названием и несколько неизвестных папок ("Test kkkkkk", "Test ххх", "Test yyyyyyyy", "Test zzzz", ....). Во всех папок первое слово одинаковое. Нужно удалить неизвестные папки, у которых значения k, x, Y, z, ... непостоянные (неизвестные).
Как вариант подойдет что нибудь типа "удалить все папки, кроме одной с известным названием".




© OSzone.net 2001-2012