QT在Windows中的技术总结(三):从生成exe到NSIS初级自定义打包详述

    这主题本应该是最后才写的,但是这两天确实被它折磨得不行,所以忍不住先写了,所谓打铁趁热嘛。
    其它的关于编程方面的总结,由于之前项目很赶,等之后我给程序写注释的时候再相应补上。

    由于对Windows的体系什么的一窍不通,虽然之前在开项之前有对NSIS做了点功课,但实际打包起来却问题多多。昨天一整天绕了一个大大的弯子,只能说,不懂一个体系架构就直接编软件是真心伤不起啊。


    之前对NSIS的一些初步了解,写了一篇博的,还记录了一下看到的几篇好东西。不过不知道为啥,现在却完全看不懂以前写的东西= =只好又去别人那些那翻了一遍。。。

    今天来个深刻的总结,下次再看又看不懂我就撞豆腐去。。。

    先了解一下整体步骤:生成exe→寻找依赖的dll→确定依赖关系→NSIS向导打包→NSIS自定义强化

    由于我的程序是用usb转串口驱动,所以NSIS自定义里我加了安装inf驱动。

首先是生成exe

    据说动态链接的各种好处,当然这也是相对的,影响中是说,小程序的话,静态链接会比较好,大程序的话动态链接会比较好,这个好是说节省空间吧好像,详细的去问度娘,这个太理论性我真不太懂,总之看了很多之后就觉得动态链接优点还挺多的。

     点击在QT左边Project,在Build Settings下的 Edith build configuration选择Release。然后重新编译运行。

寻找依赖的dll

    之前试验的时候是用一个小程序,用的就几个dll,试一两下就试出来了,不行就会报错,但大程序就不是那么回事了。

    刚开始的时候我复制了必须的四个库【QtCore4.dll、QtGui4.dll、mingwm10.dll、libgcc_s_dw2-1.dll】,然后打算运行下看它报错什么找什么,于是,我的电脑就光荣卡机了。程序直接报错说内存错误,我按了取消,倒没什么弹出来,但那个进程就连任务管理器都杀不死,开那个软件的文件夹也卡死,杀了资源管理器也不行,注销了也不行,于是只好重启了。

    搜了下找依赖关系的方法,没想到居然还真的有。据说VC有个工具叫depend的,但我不是用VC编译。

    后来在网上发现了一个超好用的东东【 ProcessExplorer】下载地址: http://www.51gugu.com/file/599511

     不用安装直接双击就可以使用了,方便哈!设置好后直接点击就可以查得到相关依赖的所以dll~

    首先是设置显示DLL:View→Lower Pane View→DLLs



     然后在QT中运行软件,在ProcessExplorer中点击查看依赖的dll


    看到吧,一大堆都是来自qt那个文件夹里面的依赖,那么我们就新建一个目录,把需要用到的dll和刚生成的exe文件拷贝到目录下。如果你的程序有调用到数据库和文件,那么也要把他们一同拷到目录中。

注意:拷贝的时候要注意qt\bin下的文件和mingw\下的文件,必须和exe文件在同一目录,否则,程序是跑不起来的。至于plugins\的文件,就需要新建一个plugins目录,再按原结构放置,否则后面是无法连接到目录下的。

确定依赖关系
    
   此时双击目录中的exe,发现它真的能运行了。如果你此时马上去打包,那你就真真被它给骗了!因为打包出来的东西也只能在你电脑使用,在别的电脑用会报错的。今天我给别的工程师测试的时候就出现问题了。


    我看到的时候郁闷了一下,怎么提示那么奇怪,想了想,才想起这个框不是系统提示,是我自己给自己的messagebox。

QSqlDatabase Db=QSqlDatabase::database();
if(!Db.open())//打开数据库
{
     emit Data_ErrorReturn(QString("DataBase Open Error:%1").arg(Db.lastError().text()));
}

    我跟那工程师的电脑唯一的区别就是,他电脑里没有QT,所以问题就出现在依赖上,看到网上有位大神说,想知道程序是不是依赖你的QT,你把QT程序的安装文件夹名字改一下,看它报不报错,我还真去试了下,还真的错了。。。其实还有个方法,就是用到上面说得软件ProcessExplorer,再看看依赖关系就知道了。



   因为我的程序是做好安装包安装出来的,那四个基本的依赖都是正确的,但是其他的依赖plugins的依赖就都跑回QT上了。

    这个错误我找了好久,因为网上貌似不多人即是在Windows又是用SQLite,然后还是菜鸟的,像我这样的奇葩。

    先po上大神的博客:【QT 程序打包部署】 http://blog.sina.com.cn/s/blog_4c8529bb0100ujx7.html
    
    这篇文章一共介绍了三种方法,有在QT程序中加 QApplication::addLibraryPath() 或 QApplication::addLibraryPaths(). 如:qApp->addLibraryPath(”c:/some/path”);但我并不想动我的QT程序,所以不选这种。
    
    另一种是使用第三方的工具修改QtCore库里写入的路径,这个看着就觉得麻烦,也放弃了。

    于是我选择了最后一种方法,就是制作一个qt.conf文件,我的理解就是相当于写一个配置文件,告诉exe到指定地方找dll。

    用这个方法的前提条件是按照之前所说的,dll按照原来在qt里的层次 结构放好在plugins文件夹内,然后在exe所在目录下,创建一个文本,并且在里面写三行东东:

[Paths]
Prefix=.
Plugins=plugins

    然后保存文件,并且重命名为 qt.conf,这样再 运行的时候,exe就会找到目录下的东西啦~再来看下它们的依赖关系:


NSIS向导打包

    为什么看中NSIS而不是其他,我也忘了,但我印象中NSIS是支持编程,能定制比较多的,对于程序员来说应该是个很不错的选择吧。

    NSIS有自己的一套语言和语法规则,看到别的大神形容它很像高级语言,因为它对段的先后顺序都非常严格。那么这么高级的语言,没必要重新从0开始学它吧,所以最开始先用向导去生成一个脚本,再对脚本做细微的修改,达到我们想要的效果。

    给一个有足够插件的NSIS中文安装包【 http://zy.51gugu.com/1485021.html
    打开NSIS,选择VNISEdit。


     选择使用向导创建文本,或者文件→新建脚本:向导。
        


    点击下一步后会出现一个添信息的界面,而界面的各项信息与之后安装程序的关联如下图所示。名称和版本会组合起来,成为你安装时的一个代号,如果填了网站,就会生成一个网页的快捷方式,程序标志则会出现在安装程序的左下方。不过那个出版人,我貌似找不到任何显示它的地方。。。


    再点击下一步,就到了基本设置界面,选择图标,可以更改安装程序的图标,不过这个图标指的是setup.exe的图标,而不是之前生成exe的图标哦!更改安装程序文件,修改的是setup的名字。安装语言不选的话默认是简体中文,图形界面和压缩算法我都没换过,有兴趣的童鞋可以试下~


    再按下一步,就是设置安装包启动的“欢迎界面”,就是安装前显示一张图,可以设计显示时间和渐现渐隐,挺高级的,还可以设置播放音乐什么的,觉得挺土的就没用。



    再按下一步,是选择默认安装目录和授权文件的设置。如图所示,默认目录下的‘$xxx’会对应一个系统的位置。选择一个授权文件,将会显示在安装包的方框中,三种授权按钮,个人觉得第一种真的很丑,第二第三种是比较多人使用的类型。


    再按下一步,是 定制组件的界面,也就是选择安装的文件啦!这是最重要的部分,你的程序会有什么东西,就完全靠这里的添加啦。
     如果这里的最下面不选择“允许用户选择要安装的组件 ”,那么在运行安装程序的时候,选择完安装文件夹就会直接进行安装。左边的是组件部件,如果不需要用户选择的话,添加多个也没啥意思。
    我这里就使用了主组件和串口驱动两个组件,如果不进行后期编辑的话,两个都是可选择的,而不会出现主组件必选的 ,这个设置在后面再说。
    组件的内容,有单独添加一个文件和添加整个目录,推荐使用后面一个。因为添加目录里面,勾选“ 包含子目录” ,可以把之前生成exe和搞好dll依赖关系的文件夹直接打包到程序包,到时候程序安装好也就会是那个样子。而如果你单独一个一个文件添加,之前做好的架构(plugins等文件夹的层次 )就没办法在安装好之后体现出来,会不会不能用我就不清楚了,谁无聊可以去试下。
    另外,“
单独添加每个文件”,也需要勾选的,虽然选择与否对包含的文件没有影响,但是不选此项,在下一步中,将无法自动生成快捷方式,要么你手动输入,要么就没有快捷方式生成了。至于原因,其实也不难懂,只是我不知道怎么表达,在脚本的时候更容易看出来,等下会提一下



    再下一步,就到了创建各种快捷方式了 ,如果上面不选择“单独添加每个文件 ”下面快捷方式就什么都没有,要你自己添加咯~
    快捷方式中,上面那个是在开始菜单里的快捷方式,下面那个是桌面的。
    不是写这个博客我都不知道原来问题出在这,刚刚工程师还跟我提过我的安装包有这个bug = =。


    再下一步就是参数填写啦,自述那里貌似可以选择一个txt,不过我就这样空着。另外,如果刚刚没选 “单独添加每个文件 ”,程序这里就会空了,安装完成后就没有那个选项问你是否立即启动软件,不过这对软件是没有任何影响的。安装完成后的那个选项也是可以通过之后对脚本进行编辑而修改的。



    最后一步就是进行卸载程序定制了,就是改那些文字和图标而已。另外简易方式和安全方式,我感觉不到有啥本质上的区别,可能我的安装程序比较简单吧。安全方式会把安装目录也删了,简易方式就留下了目录和一个空的plugins = =。哦对了,简易方式的时候我的Avast杀毒软件警告过说我软件不安全,安全方式的时候则木有。。。


    好了,终于到最后一步了,由于我们等下还要编辑,当然需要保存脚本啦,也方便以后使用,不保存的我没试过,不想白费心机。第二个是我点第一个的时候它自动勾上的,我就没理它,第三个,如果不勾选的话,默认保存为.ini格式的配置文件,这种格式貌似是通用格式吧,总之你关了NSIS再双击那个文件,它默认是文本格式打开的,并且在nsis中打开也无法打开。如果勾选编译脚本,就会生成.nsi格式的NSIS专用文件,以后双击就直接在NSIS中打开,很方便的。不过ini和nsi格式貌似是一样的,自己手动换个后缀也是可以的。


    好了,一个基本的NSIS包就生成了!

NSIS自定义强化

    能被大神们成为高级语言的,完全学会它是需要时间的,只是偶尔打包一个程序,那就用到哪学到哪好了。

    首先,说说上面提到的,把“主组件”设为默认必选项,其实就一句话的事情。把这句话 【SectionIn RO】添加到该组件的段内就可以了。

Section "主组件" SEC01
SectionIn RO ;此组件为必选组件
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
File /r "..\新建文件夹\*.*"
SectionEnd

    这里顺便说一下,这里是没有勾选“单独添加每个文件”的脚本,所以它的添加文件命令就只有短短的一句话,命令添加这个目录下的所有文件。
    而如果勾选了“单独添加每个文件”这里就会有一大串文件的地址。一个个文件的添加。这就是为什么它不能创建快捷方式的原因了!
    只有一句话,软件就只会寻找这个文件夹,是对文件夹操作,不会找这些文件。而如果每个文件都添加,编译器知道这些文件,才会发现到.exe文件,才能提醒你生成这个.exe文件的快捷方式。这个是在学Linux的时候对文件操作的看法引申得来,如果不对请告诉我。

    接下来这个问题,纠结了我整整一天,对Windows体系不熟的祸害啊!!!!!
    因为我的程序有串口通信的,要安装USB转串口驱动。因为我有那个驱动的安装包,但是是需要点击一个按钮的那种,所以我想到了用一个脚本,打开脚本,运行完再把脚本给关了。
    在网上找到了一个叫《按键精灵》的东东。说实话那东西确实好用,特别如果以后要做什么重复性操作的话,也绝对用它。它可以录制下鼠标和键盘等等所有的操作,实在太方便了。但是在我千辛万苦定制好之后发现,这个东西生成的脚本,运行的时候居然是需要先运行按键精灵软件的 = =,超级无语啊。后来想不如直接写个批处理文件启动,运行完之后把按键精灵给杀了,但是,结果发现按键精灵启动之后,我的批处理压根就不能动了,亏我还浪费时间去学批处理的语言。

    后来打算直接用批处理运行那个驱动软件,然后批处理自杀,可是,怎么也想不到怎么去给命令按那个按钮,想想貌似Linux也不能给点击命令吧= =。

    在找资料的过程中,发现了静默安装这个词。很多软件都有静默安装的选项,NSIS调用的时候可以给相应的参数,使软件静默安装。不过要根据这个软件不同的打包方式,给出不同的参数,具体那个参数可以google。

    我试了几个都不行但是就被我发现那个驱动软件是可以解压缩的!直接解压出来是一堆配置文件,还有一个.INF的安装信息,google了一下,这个东西是可以直接用NSIS直接安装的!!!!!

    外行就是外行啊~绕了半辈子才找到路T T~ inf的安装也是一句话的事啊~~~~混蛋。。。

    NSIS运行外部程序的时候的命令有两个,Exec和ExecWait,差别就是Exec只是调用,而ExecWait会等待返回。不过 ExecWait 这等待返回并不是绝对的,具体Windows的体制我并不太清楚。我调用的驱动软件.exe的时候,那个exe弹出来,安装就在继续进行了,而如果我调用的是安装.inf,那么就会等.inf安装完之后再继续之前的安装。

    由于我的串口驱动是选择组件,我的这句话也是写在串口驱动段下的。

Section "串口驱动" SEC02
    File /r "HL-340_3.1.2009.06\*.*"
    ExecWait "RunDll32 advpack.dll,LaunchINFSection CH341SER.INF,CH341SER_Install"
SectionEnd

    其中CH341SER.INF是我那个INF的文件名,而“CH341SER_Install”是。INF文件里的一个段,网上很多人说的“ DefaultInstall ”段我在我的inf文件里并没有看到,所以就选择了这个。
    而卸载方面,由于我的INF没有卸载段,但我看到了注释,就分出来了一个段,就能用了。

原代码:
[CH341SER.AddReg]
HKLM, SOFTWARE\WinChipHead\IC\CH341SER, WDM, 0x00010001, 0x00000031
HKLM, SOFTWARE\WinChipHead\IC\CH341PORT, DLL, 0x00010001, 0x00000010
HKLM, SOFTWARE\WinChipHead\IC\CH341SER, Function, , "USB=>Serial"
;HKLM, SYSTEM\CurrentControlSet\Services\CH341SER, UserRemoval, 0x00010001, 0x00000001
;上面这行用于在系统托盘中显示“安全删除USB转SERIAL硬件设备”,便于用户手工删除硬件

后两行被我独立分成了一段:
[CH341SER.Remove]
HKLM, SYSTEM\CurrentControlSet\Services\CH341SER, UserRemoval, 0x00010001, 0x00000001
;上面这行用于在系统托盘中显示“安全删除USB转SERIAL硬件设备”,便于用户手工删除硬件

在NSIS中卸载命令如下:
Section Uninstall
    ExecWait "RunDll32 advpack.dll,LaunchINFSection $INSTDIR\CH341SER.INF,CH341SER.Remove"
    Delete "$INSTDIR\${PRODUCT_NAME}.url"

    网上99.9%都是写 $windir\INF\XXX.INF,结果说没找到这个INF,去掉直接写INF也不行,明明INF和卸载程序同目录啊,这个我比较不解。在写这个博客之前我已经打算放弃卸载了,刚刚甚至已经把那个警告窗贴出来了,结果不甘心试了几次,居然还真成功了。我的是用$INSTDIR\XXX.INF,可能不同驱动复制到的位置不同吧,我找不到它放哪里,就用回最原始的本身那个了(前提是之前做安装包的时候有把这个INF包含进去)。
    
    不过,至于这样运行inf是不是真的能成功我也不知道,我电脑本身装了usb转串口驱动,而安装的时候也确实有看到它左上角弹出按键复制的窗口,应该是安装成功了吧~

几个简单的自定义美化方法

    在原来的预定义常量添加上
; MUI 预定义常量
!define MUI_WELCOMEFINISHPAGE_BITMAP "F:\素材库\00.bmp"
;引号内为位图的路径,位图大小大约为  165*298
!define MUI_WELCOMEPAGE_TITLE "\r\n AD-104 听力计安装程序"
;\r\n 为换行标志
!define MUI_WELCOMEPAGE_TEXT "此系统用于与听力计AD-104进行联机测试,可数据记录,进行数据分析,保存测试结果等功能,方便各医院等听力测试机构进行听力测试及分析 \r\n\r\n 广州麦力声医疗器械有限公司\r\n\r\n$_CLICK"
!define MUI_PAGE_HEADER_TEXT "111 "
!define MUI_PAGE_HEADER_SUBTEXT "222"


; 安装完成页面
!define MUI_FINISHPAGE_RUN "$INSTDIR\Audiometer.exe"
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\汉化说明.txt"
!define MUI_FINISHPAGE_SHOWREADME_TEXT "汉化说明"
!insertmacro MUI_PAGE_FINISH



    至此这篇博就编写完毕了~整整写了一天半,在写的过程中对整个过程都加深了认识,绝对不算浪费时间。而且很久以后再去打包忘光了也能记起来了。如果以后再对NSIS有更深的认识,再写一篇吧~

End
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值