#nsis
Вопрос:
У меня есть строка ANSI в ресурсе RCData, и я хотел бы сохранить эту строку в переменной. Я дошел до того, что могу получить указатель на ресурс и размер данных:
; HMODULE GetModuleHandle(LPCSTR lpModuleName);
System::Call "kernel32::GetModuleHandle(i 0) i.r0"
; HRSRC FindResource(HMODULE hModule, LPCSTR lpName, LPCSTR lpType);
System::Call "kernel32::FindResource(i 0, t 'DATA', i 10) i.r1"
; HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);
System::Call "kernel32::LoadResource(i r0, p r1) i.r2"
; LPVOID LockResource(HGLOBAL hResData);
System::Call "kernel32::LockResource(i r2) p.r3"
; DWORD SizeofResource(HMODULE hModule, HRSRC hResInfo);
System::Call "kernel32::SizeofResource(i r0, i r1) i.r4"
Теперь я не совсем уверен, что мне делать. Я совсем новичок в NSIS, и я думаю, что моя проблема в том, что я действительно не понимаю, как переменные работают в NSIS и что происходит (какое значение они имеют), когда переменная используется в качестве вывода системного вызова с разными типами. Что (я думаю) мне нужно, так это скопировать $4
байты с адреса, хранящегося в $3
новом буфере, и (возможно?) Завершить его нулем. Я думал, что что-то подобное может сработать:
System::Alloc ${NSIS_MAX_STRLEN}
Pop $5
System::Copy /$4 $5 $3
Но это не так. После некоторых экспериментов я дошел до того, что это работает:
System::Call "*$3(amp;m$4.r5)"
Но я действительно не очень хорошо представляю, почему это работает, правильно ли следует решать эту задачу и почему вышеприведенная версия копии не сработала.
Ответ №1:
В коде System::Copy $5 содержит адрес памяти выделенного буфера (в виде строки, как если бы кто-то это сделал sprintf(reg5, "%i", address)
). Если вы это сделаете MessageBox mb_ok $5
, вы просто увидите этот адрес. Однако, если вы это сделаете System::Call user32::MessageBoxA(p0,pr5,p0,i0)
, вы должны увидеть свою строку.
Система::Код вызова преобразует источник и/или пункт назначения, используя указанный вами тип. Это совершенно правильный способ сделать это и требует меньше работы, чем копирование кода.
Возможно, это было бы легче визуализировать, если бы у нас было что-то, что требовало преобразования типов, а не просто байтовой копии в вашем конкретном случае.
Представьте, если бы в C у нас было
typedef struct { int foo, bar; } MyS;
MyS*ptr = allocandfill();
а в NSIS $1-это значение ptr:
System::Call '*$1(i.r2,i1234)'
мы часто называем это синтаксисом системной структуры, и * можно рассматривать как удаление ссылки на память, начиная с 1 доллара, и интерпретацию памяти как структуры на основе указанных нами типов.
В моем конкретном примере здесь мы говорим, что первый элемент-это int, и я не хочу изменять значение/источник (точка), но я хочу, чтобы текущее значение в качестве вывода хранилось в r2 ($2). Это в основном будет выполняться itoa
там, где 2 доллара-это пункт назначения. Второй элемент-это другой int, и я перезаписываю его текущее значение числом 1234. В C это было бы исполнением ptr->bar = atoi("1234")
.
Третий способ выполнить вашу задачу-вызвать функцию Windows и заставить ее выполнить работу:
System::Call `kernel32::lstrcpyA(m.r5,pr3)' ; or lstrcpynA if the string is not zero-terminated or you want to chop it to n characters
Комментарии:
1. Это потрясающе, теперь многое имеет гораздо больше смысла, большое вам спасибо! 🙂 Может быть, еще один вопрос —
amp;m$4.r5
добавляет ли завершающее «» к$5
? Строка в$3
не заканчивается нулем. Поскольку переменные содержат только строки, а также результирующая строка, по$5
-видимому, отображается правильно, я полагаю, что это так, я просто хотел бы убедиться, что ноль там не случайно. Кстати. было бы разумно думать о переменных как оchar[NSIS_MAX_STRLEN]
?2. После некоторых экспериментов кажется, что результат
$5
действительно заканчивается нулем, и это здорово. 🙂