zoukankan      html  css  js  c++  java
  • 编译支持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就可以了。

  • 相关阅读:
    #JVM方法区、堆、栈’#
    #前端# 解决前端页面滑动不顺畅的问题
    【Web协议】服务器推送浏览器:Server-Sent Events(SSE)
    【性能调优】Java程序CPU高定位
    转载 I/O模型:BIO/NIO/AIO 学习
    【性能调优】Java程序内存高定位
    算法--字符串:最长回文子序列
    算法--字符串:最长递增子序列LIS
    算法--字符串:最长回文子串
    算法--字符串:最长公共子序列LCS
  • 原文地址:https://www.cnblogs.com/nankezhishi/p/unicodensislog.html
Copyright © 2011-2022 走看看