把资源文件如zip、png等编译进EXE文件内,最常见的是资源法:在工程的.rc文件内定义,这里不再细说,如果有疑问,可以看看把zip编译进
EXE是怎样做的。
duilib把ZIP皮肤编译进EXE
但是这样做容易被360杀毒误报,所以就来研究一下第二种方法:Qt Rcc.exe资源编译的实现。
Qt有自己的资源管理系统,它并不是把资源文件放进.rc中,而是自己做了转换处理,且生成的文件不会被误报,且细看是如何实现的:
这里用qt-all-opensource-src-4.5.2做演示,它在我的D盘下,进入到:D:\qt-all-opensource-src-4.5.2\src\tools\rcc目录。
当然,主文件就是main.cpp,它的main函数会交给
int runRcc(int argc, char *argv[])
这个函数来接管,只分析主要的代码实现。
先建立一个11.txt,内容如下:
Hello Qt Rcc!
建立一个11.qrc文件,内容如下:
11.txt
使用rcc.exe 11.qrc -o out.cpp 命令编译资源,打开out.cpp,可以看到字符串编译成如下数组:
static const unsigned char qt_resource_data[] = {
0x0,0x0,0x0,0xd,
0x48,
0x65,0x6c,0x6c,0x6f,0x20,0x51,0x74,0x20,0x52,0x63,0x63,0x21,
原来Rcc.exe源文件里使用
void RCCResourceLibrary::writeNumber4(quint32 number)
这个函数编译输出资源的大小,其中第一行,前四个字节,0xd便是字符串的大小,十进制为13,
Rcc.exe使用了
qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
QString *errorMessage)
这个成员函数来把数据做16进制输出处理,这个过程中可能会使用libzip对资源文件进行压缩,函数内可以看到有这句:
#ifndef QT_NO_COMPRESS
// Check if compression is useful for this file
if (m_compressLevel != 0 && data.size() != 0) {
QByteArray compressed =
qCompress(reinterpret_cast(data.data()), data.size(), m_compressLevel);
void RCCResourceLibrary::writeHex(quint8 tmp)
{
const char * const digits = "0123456789abcdef";
writeChar('0');
writeChar('x');
if (tmp < 16) {
writeChar(digits[tmp]);
} else {
writeChar(digits[tmp >> 4]);
writeChar(digits[tmp & 0xf]);
}
writeChar(',');
}
Hello Qt Rcc!
便是Rcc.exe编译输出对应的字节数组罢了:
0x48,0x65,0x6c,0x6c,0x6f,0x20,0x51,0x74,0x20,0x52,0x63,0x63,0x21
来试验一下,为了验证我们的想法。
新建控制台工程,代码输出如下:
char s[] = { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x51, 0x74, 0x20, 0x52, 0x63, 0x63, 0x21 ,'\0'};
printf("--s:%s\n", s);
编译运行一下,就可以看到结果了。
实际上对二进制资源的编译,如png的处理也是一样,这里不再实验。
这就是Qt Rcc处理资源的核心秘密 - 将文件编译成字节数组!
我把rcc.exe和源文件等打包了,下载地址:
http://download.csdn.net/detail/hats8888/9738585