制作NSIS命令行窗口输出插件


在上一篇中,介绍了如何让NSIS生成的安装包在静默安装时从命令行窗口输出安装信息,但是产生了很多问题,于是我们想换一个实现方法,毕竟静默安装时的输出信息并不需要那么多,多了反而让人眼花。静默安装时,只要输出生成还是失败,失败了有个失败原因就可以了。所以另一个解决方案就是自己写个插件,向CMD窗口输出一些信息就是了。这篇文章就是要介绍一下如何自己编写这样的一个NSIS插件。

很奇怪的是,NSIS的官方网站上居然没有介绍如何自己编写Plugin的文章,搜索到在OpenWatcom有一篇介绍了NSIS插件要符合的要求。按照它给出的描述——“NSIS plugins are simply DLLs. The functions provided by these functions are exported functions that have a specific array of parameters. That signature is as follows.”NSIS插件不过是简单的DLL,只要是符合下面参数列表的函数,就会被认为是合法的NSIS插件。
__declspec(dllexport) void __cdecl TestFunc(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)

好啊。那就照葫芦画瓢写个DLL喽。Hello world级的。下面是hello.cpp的源代码。
#include <windows.h>
#include <stdio.h>

#define NSISAPI __declspec(dllexport) void __cdecl

NSISAPI TestFunc(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
printf("Hello");
}
很简单吧。用下面的命令编译一下。
CL /LD Hello.cpp

编译不过啊!
error C2061: syntax error : identifier 'stack_t'

stack_t未定义!这让我去哪里找啊?只当是外面的吧。把代码改成下面的样子。
#include <windows.h>
#include <stdio.h>
#define NSISAPI __declspec(dllexport) void __cdecl

struct stack_t;

NSISAPI TestFunc(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
printf("Hello");
}


这下就过了。把这个DLL放到NSIS的Plugins文件夹中,写一个最简单的NSIS脚本测试一下。

OutFile "Test.exe"
Section
Hello::TestFunc
SectionEnd

结果发现脚本Build不过啊。错误为“Invalid command: Hello::TestFunc”
Command找不到。

看看MakeNSISW上完整的输出信息。列出了NSIS找到的所有Plugin里的可作为Command的函数。如下
Processing config:
Processing plugin dlls: "D:\Program Files\NSIS\Plugins\*.dll"
- AdvSplash::show
……
- Hello::?TestFunc@@YAXPAUHWND__@@HPADPAPAUstack_t@@@Z
的确是有我们刚加入的DLL的,不过函数名不对啊。“?TestFunc@@YAXPAUHWND__@@HPADPAPAUstack_t@@@Z”怎么会有这么个恶心的函数名?

也许有人已经猜到了,由于使用的是C++,而C++是支持函数重载的,但是导出函数表的函数名不能重名啊。所以CL在编译C++的时候,会自动对函数名进行修饰。这个恶心的名字就是修饰过的函数名。有没有办法不让CL修饰呢?一个办法就是告诉CL我们的代码是C代码,不支持重载,CL就不会修饰了。代码再改如下。
#include <windows.h>
#include <stdio.h>

#define NSISAPI extern "C" __declspec(dllexport) void __cdecl

struct stack_t;

NSISAPI TestFunc(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
printf("Hello");
}

再把编译好的DLL复制到插件文件夹,再编译Test.nsi,这次就编译过了。

双击运行Test.exe,不会看到任何Hello,因为printf是输出到Console的。
从命令行运行Test.exe,也不会在控制台看到”Hello”,因为这个Test.exe是个GUI程序,是没有Console的Output的。寒。那怎么才能有呢?有三个办法,NSIS也是都可以做到了。三种方法可以参考我的另一篇文章让WPF窗体程序支持命令行方式运行的三种方式。方法是通用的。“| more”的方法就不用解释了。让NSIS生成一个CUI程序,可以参考让NSIS生成的安装包在静默安装时从命令行窗口输出安装信息,但是这种方法弊端多多,不然也就不会有这篇文章了。最后一种方法就是AttachConsole了,这种方法也有不好的地方,不过比较而言,还是可以的。

这个DLL的代码很简单,只实现了最基本的功能,大家有需要可以自己添加。


#include <windows.h>
#include <stdio.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")

#define NSISAPI extern "C" __declspec(dllexport) void __cdecl

HANDLE hOutput;

typedef struct _stack_t {
struct _stack_t *next;
char text[1024];
} stack_t;


NSISAPI Attach(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
if (AttachConsole(-1) == 0)
printf("failed to attach parent console.");
else
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
}

NSISAPI Show(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
if (hOutput == NULL)
printf((*stacktop)->text);
else
WriteConsole(hOutput, (*stacktop)->text, strlen((*stacktop)->text), NULL, NULL);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值