NSIS 问题汇总

594次阅读

!include “LogicLib.nsh”
; 激活安装日志记录,该日志文件将会作为卸载文件的依据
; (注意,本区段必须放置在所有区段之前)
Section “-LogSetOn”
LogSet on
SectionEnd
未定义 NSIS_CONFIG_LOG
Section: “-LogSetOn”
错误: 已指定 LogSet , 但未定义 NSIS_CONFIG_LOG .

代码是用HM VNISEdit 脚本编辑器向导产生
代码里都有:

 

根据你的 NSIS 版本下载开启安装 log 的文件覆盖你原来的 NSIS 文件夹中同名文件:
http://sourceforge.net/projects/nsis/files/
比如 NSIS 2.51,就下载 nsis-2.51-log.zip 覆盖你 NSIS 中同名文件。

编译支持Log功能的Unicode NSIS

 

对于开发多语言版本的安装包来说,使用Unicode NSIS就成了一个比较自然的选择。然而Unicode Nsis属于官方NSIS的衍生版,开发进度势必落后于官方的NSIS,主要由Jim一个人进行维护。现在官方最新版本是2.45,而Unicode版还停留在2.42。

用过NSIS的都知道,NSIS的默认方式是手写卸载脚本的。如果使用了支持LOG功能的特殊版NSIS(也是官方的)。使用这个版本的NSIS生成的安装包可以在安装过程中生成日志文件,再加上网友提供的现成脚本,就可以比较方便地实现用日志文件进行卸载的功能。实现方式可以参考NSIS的基本结构一文。

然而,Unicode NSIS的作者没有提供支持LOG功能的NSIS的下载。而只提供了源代码下载。这样我们就不得不自己重新编译NSIS。编译过程很简单,加上一个NSIS_CONFIG_LOG编译参数就可以。但是如果问题这么简单就没有必要写个文章专门介绍一下了。

问题就在于,用自己编译出来的NSIS生成的安装包生成的LOG文件有错误!什么错误呢?在网上没有搜到任何线索,只能自己分析一下LOG文件,自己找错误了。(昨天给Jim发了邮件,不过没有时间等他的回复了)

查看了Unicode NSIS的相关源代码和《Windows核心编程》,发现最有可能出问题的就是WriteFile函数的问题。相关源代码如下。

if (g_log_file[0] && fp == INVALID_HANDLE_VALUE)
{
fp = myOpenFile(g_log_file, GENERIC_WRITE, OPEN_ALWAYS);
if (fp != INVALID_HANDLE_VALUE)
SetFilePointer(fp, 0, NULL, FILE_END);
}
if (fp != INVALID_HANDLE_VALUE)
{
DWORD d;
mystrcat(log_text, _T("\r\n"));
WriteFile(fp, log_text, mystrlen(log_text), &d, NULL);
}

Unicode NSIS生成的所有字符串都是Unicode编码的,写到这个文件里的字符串也是。那么上面的代码有两个问题。

1. 作者在创建这个文件的时候,没有声明这个文件是Unicode文件,使得记事本在打开文件时,以ANSI编码打开,从而产生错误。这个声明就是Byte Order Mark,只是针对Windows平台的部分Unicode文件有这个约束。(比如VS就可以选择是否在源代码文件中加入BOM。)

2. WriteFile时,第三个参数不正确。第三个参数的单位是字节,但是mystrlen函数返回的是log_text的字符数。而Unicode的一个字符有sizeof(TCHAR)个字节。所以实际写入文件中的字符串,只是log_text的前sizeof(TCHAR)分之一。

好了,问题找到了,着手修改源代码吧。先加上BOM,再把第三个参数乘以sizeof(TCHAR)。编译很顺利地完成。生成的LOG文件也是完整的了并能用记事本打开了。

但是,卸载功能无效。把生成的Unicode编码的Log文件另存为ANSI编码的。能卸载了~~~~看来这个Unicode NSIS的卸载包不是很完美啊。想必要让Uninstaller支持Unicode又要改不少代码。一想还有另一种可能是Uninstaller不认识BOM,毕竟NSIS是跨平台的,但是如果记事本不可读也是不能接受的。后来试了一下,果然不能有BOM。把BOM去掉,Uninstaller就正常工作了。

最终代码修改如下:

if (fp != INVALID_HANDLE_VALUE)
{
DWORD d;
mystrcat(log_text, _T("\r\n"));
#ifdef UNICODE
WriteFile(fp, log_text, mystrlen(log_text) * sizeof(TCHAR), &d, NULL);
#else
WriteFile(fp, log_text, mystrlen(log_text), &d, NULL);
#endif
}

然后用下面的指令Build一下,

scons UNICODE=yes NSIS_CONFIG_LOG=yes SKIPUTILS=”NSIS Menu” PREFIX=”Your Install Folder” install

支持Log的Unicode版NSIS就生成好了。

另外附上自己编译好的补丁,覆盖现有安装即可。

更新:

这时生成的Log文件是Unicode编码,而FileRead指令是不能正确读取Unicode文件的。这样就导致Uninstall By Log功能无法正常运行。

解决方法也很简单,把读取Unicode文件的FileRead指令替换成Unicode NSIS所特有的FileReadUTF16LE就可以了。

yiywain
版权声明:本文于2021-09-15转载自编译支持Log功能的Unicode NSIS,共计2343字。
转载提示:此文章非本站原创文章,若需转载请联系原作者获得转载授权。