本文主要介绍在Windows 7 64bit操作系统下,利用Visual Studio 2010,如何安装,生成,并使用zlib 1.2.5。
(1). 首先,使用Visual Studio 2010编译生成zlib 1.2.5版本的静态和动态链接库。
(2). 然后,通过加载静态链接库zlibstat.lib,实现对简单txt文档的压缩与解压缩。
(3). 最后,通过调用动态链接库zlibwapi.lib,实现对简单txt文档的压缩与解压缩。
1. 使用Visual Studio 2010编译生成zlib 1.2.5版本
1). 从zlib官网 "http://zlib.net/"
下载最新版本的zlib "http://zlib.net/zlib-1.2.5.tar.gz"
解压,展开到系统盘。
2). 在编译前,首先开启VS2010的Command Prompt (32bit)
3). 进入到zlib-1.2.5contrib\masmx86目录 "zlib-1.2.5\contrib\masmx86",执行bld_ml32.bat。
4). 这一步运行bld_ml32批处理文件,里面调用ml命令编译inffas32.asm和match686.asm,生成inffas32.obj和match686.obj。这两个文件在zlibvc中用到。
5). 若是准备生成64位库,则进入到zlib-1.2.5contrib\masmx64目录 "zlib-1.2.5\contrib\masmx64",执行bld_ml64.bat。注意ml64.exe在vs2010的"Microsoft Visual Studio 10.0/VC/bin"下面找不到。我们需要使用"Microsoft Visual Studio 10.0/VC/bin/amd64/"下面的ml64.exe。这里可以简单将其复制到"Microsoft Visual Studio 10.0/VC/bin"下面。
这一步运行bld_ml64批处理文件,里面调用ml命令编译gvmat64.asm和inffasx64.asm,生成gvmat64.obj和inffasx64.obj。这两个文件在zlibvc中用到。
6). zlib的vs sln解决方案文件可以在如下路径中找到 "zlib-1.2.5\contrib\vstudio\vc10\zlibvc.sln"
在工具栏中将“解决方案平台”改为“x64”,编译即可
这个解决方案中包含6个工程。其中:
(1). zlibvc生成动态链接库zlibwapi.dll和对应的导入库zlibwapi.lib
注意:如果出现zlibvc.def(4): fatal error LNK1118: “VERSION”语句中的语法错误,将VERSION删除再编译一次即可!
如果出现 VS2012:error LNK2026: 模块对于 SAFESEH 映像是不安全的
解决方法:打开该项目的“属性页”对话框-->单击“链接器”节点-->单击“命令行”属性页-->将 /SAFESEH:NO 键入“附加选项”框中,然后点击应
(2). zlibstat生成静态链接库zlibstat.lib
(3). testzlibdll测试生成的动态链接库zlibwapi.dll
(4). testzlib测试生成的静态链接库zlibstat.lib
最后我们在debug模式下编译整个解决方案。生成的dll和lib文件可在如下文件夹中找到
"zlib-1.2.5\contrib\vstudio\vc10\x86"
为了随后的调试方便,在随后的例子中,我们把头文件zconf.h,zlib.h放到如下文件夹
"C:\MANUS\CommonSpace\zlib 1.2.5"
库文件zlibwapi.dll,zlibwapi.lib,zlibstat.lib放到如下文件夹
"C:\MANUS\CommonSpace\zlib 1.2.5\Lib Debug"
2. 通过加载静态链接库zlibstat.lib使用zlib
1). 打开Visual Studio 2010,建立一个Win32 Console Application工程,假设名字是test
2). 打开"zlib-1.2.5-2\contrib\testzlib\testzlib.c",打开,将其内容复制到新建工程的test.cpp中。
注意保留 #include "stdafx.h"
将"if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0)"改为
"if (ReadFileMemory(argv[1],&lFileSize,(void**)&FilePtr)==0)"
3). 打开Project -> Property (Alt+F7),在Configuration Properties -> C/C++ -> General -> Additional Include Directories 中增加 "C:\MANUS\CommonSpace\zlib 1.2.5"。我们已经把头文件zconf.h,zlib.h放到这个文件夹中。
4). 在Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions 中增加 "ASMV, ASMINF, ZLIB_WINAPI"。根据官方文档,1.2.5版本需要定义ZLIB_WINAPI。
5). 在Configuration Properties -> Linker -> General -> Additional Include Directories 中增加 "C:\MANUS\CommonSpace\zlib 1.2.5\Lib Debug"。我们已经把库文件zlibwapi.dll,zlibwapi.lib,zlibstat.lib放到这个文件夹中。
6). 在Configuration Properties -> Linker -> Input -> Additional Dependencies 中增加 "zlibstat.lib"。这个是静态链接库。
7). 编译,生成exe文件。
3. 通过加载动态链接库zlibwapi.lib使用zlib
1). 同2-1)。
2). 同2-2)。
3). 同2-3)。
4). 在Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions 中增加 "_CRT_NONSTDC_NO_DEPRECATE,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI"。根据官方文档,1.2.5版本需要定义ZLIB_WINAPI。
5). 同2-5)。
6). 在Configuration Properties -> Linker -> Input -> Additional Dependencies 中增加 "zlibwapi.lib"。这个是配合动态链接库"zlibwapi.dll"静态导出库 。
7). 编译,生成exe文件。
4. 测试
1). 首先测试使用静态链接库的版本。将生成的test.exe文件复制到测试文件夹中。并新建一个test.txt文档,在里面输入大量字符。
2). 通过cmd进入此测试文件夹。输入命令test.exe test.txt
3). 观察压缩,解压结果。
4). 然后测试使用动态链接库的版本。将生成的test.exe文件和zlibwapi.dll文件复制到同一测试文件夹中。并新建一个test.txt文档,在里面输入大量字符。
5). 通过cmd进入此测试文件夹。输入命令test.exe test.txt
6). 观察压缩,解压结果。
http://www.helyar.net/2010/compiling-zlib-lib-on-windows/
http://forum.filezilla-project.org/viewtopic.php?f=3&t=7493
http://topic.csdn.net/u/20100711/19/4a3f45e9-b743-48d1-abac-f8e6d493f330.html
http://blog.sina.com.cn/s/blog_5325b5f90100rvbl.html
test.cpp代码如下
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "zlib.h"
void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B)
{
R->HighPart = A.HighPart - B.HighPart;
if (A.LowPart >= B.LowPart)
R->LowPart = A.LowPart - B.LowPart;
else
{
R->LowPart = A.LowPart - B.LowPart;
R->HighPart --;
}
}
#ifdef _M_X64
// see http://msdn2.microsoft.com/library/twchhe95(en-us,vs.80).aspx for __rdtsc
unsigned __int64 __rdtsc(void);
void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
{
// printf("rdtsc = %I64x\n",__rdtsc());
pbeginTime64->QuadPart=__rdtsc();
}
LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
{
LARGE_INTEGER LIres;
unsigned _int64 res=__rdtsc()-((unsigned _int64)(beginTime64.QuadPart));
LIres.QuadPart=res;
// printf("rdtsc = %I64x\n",__rdtsc());
return LIres;
}
#else
#ifdef _M_IX86
void myGetRDTSC32(LARGE_INTEGER * pbeginTime64)
{
DWORD dwEdx,dwEax;
_asm
{
rdtsc
mov dwEax,eax
mov dwEdx,edx
}
pbeginTime64->LowPart=dwEax;
pbeginTime64->HighPart=dwEdx;
}
void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
{
myGetRDTSC32(pbeginTime64);
}
LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
{
LARGE_INTEGER LIres,endTime64;
myGetRDTSC32(&endTime64);
LIres.LowPart=LIres.HighPart=0;
MyDoMinus64(&LIres,endTime64,beginTime64);
return LIres;
}
#else
void myGetRDTSC32(LARGE_INTEGER * pbeginTime64)
{
}
void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
{
}
LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
{
LARGE_INTEGER lr;
lr.QuadPart=0;
return lr;
}
#endif
#endif
void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf)
{
if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64)))
{
pbeginTime64->LowPart = GetTickCount();
pbeginTime64->HighPart = 0;
}
}
DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
{
LARGE_INTEGER endTime64,ticksPerSecond,ticks;
DWORDLONG ticksShifted,tickSecShifted;
DWORD dwLog=16+0;
DWORD dwRet;
if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64)))
dwRet = (GetTickCount() - beginTime64.LowPart)*1;
else
{
MyDoMinus64(&ticks,endTime64,beginTime64);
QueryPerformanceFrequency(&ticksPerSecond);
{
ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog);
tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog);
}
dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted));
dwRet *=1;
}
return dwRet;
}
int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr)
{
FILE* stream;
void* ptr;
int retVal=1;
stream=fopen(filename, "rb");
if (stream==NULL)
return 0;
fseek(stream,0,SEEK_END);
*plFileSize=ftell(stream);
fseek(stream,0,SEEK_SET);
ptr=malloc((*plFileSize)+1);
if (ptr==NULL)
retVal=0;
else
{
if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize))
retVal=0;
}
fclose(stream);
*pFilePtr=ptr;
return retVal;
}
int main(int argc, char *argv[])
{
int BlockSizeCompress=0x8000;
int BlockSizeUncompress=0x8000;
int cprLevel=Z_DEFAULT_COMPRESSION ;
long lFileSize;
unsigned char* FilePtr;
long lBufferSizeCpr;
long lBufferSizeUncpr;
long lCompressedSize=0;
unsigned char* CprPtr;
unsigned char* UncprPtr;
long lSizeCpr,lSizeUncpr;
DWORD dwGetTick,dwMsecQP;
LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc;
printf("test zlib 1.2.5 using dynamic library.\n");
printf("Zhao Wang, June 1st, 2011.\n");
printf("press any key to start.");;
getchar();
if (argc<=1)
{
printf("run TestZlib <File> [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n");
return 0;
}
if (ReadFileMemory(argv[1],&lFileSize,(void**)&FilePtr)==0)
{
printf("error reading %s\n",argv[1]);
return 1;
}
else printf("file %s read, %u bytes\n",argv[1],lFileSize);
if (argc>=3)
BlockSizeCompress=atol(argv[2]);
if (argc>=4)
BlockSizeUncompress=atol(argv[3]);
if (argc>=5)
cprLevel=(int)atol(argv[4]);
lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200;
lBufferSizeUncpr = lBufferSizeCpr;
CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress);
BeginCountPerfCounter(&li_qp,TRUE);
dwGetTick=GetTickCount();
BeginCountRdtsc(&li_rdtsc);
{
z_stream zcpr;
int ret=Z_OK;
long lOrigToDo = lFileSize;
long lOrigDone = 0;
int step=0;
memset(&zcpr,0,sizeof(z_stream));
deflateInit(&zcpr,cprLevel);
zcpr.next_in = FilePtr;
zcpr.next_out = CprPtr;
do
{
long all_read_before = zcpr.total_in;
zcpr.avail_in = min(lOrigToDo,BlockSizeCompress);
zcpr.avail_out = BlockSizeCompress;
ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH);
lOrigDone += (zcpr.total_in-all_read_before);
lOrigToDo -= (zcpr.total_in-all_read_before);
step++;
} while (ret==Z_OK);
lSizeCpr=zcpr.total_out;
deflateEnd(&zcpr);
dwGetTick=GetTickCount()-dwGetTick;
dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE);
dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE);
printf("total compress size = %u, in %u step\n",lSizeCpr,step);
printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.);
printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.);
printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart);
}
CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr);
UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress);
BeginCountPerfCounter(&li_qp,TRUE);
dwGetTick=GetTickCount();
BeginCountRdtsc(&li_rdtsc);
{
z_stream zcpr;
int ret=Z_OK;
long lOrigToDo = lSizeCpr;
long lOrigDone = 0;
int step=0;
memset(&zcpr,0,sizeof(z_stream));
inflateInit(&zcpr);
zcpr.next_in = CprPtr;
zcpr.next_out = UncprPtr;
do
{
long all_read_before = zcpr.total_in;
zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress);
zcpr.avail_out = BlockSizeUncompress;
ret=inflate(&zcpr,Z_SYNC_FLUSH);
lOrigDone += (zcpr.total_in-all_read_before);
lOrigToDo -= (zcpr.total_in-all_read_before);
step++;
} while (ret==Z_OK);
lSizeUncpr=zcpr.total_out;
inflateEnd(&zcpr);
dwGetTick=GetTickCount()-dwGetTick;
dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE);
dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE);
printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step);
printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.);
printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.);
printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart);
}
if (lSizeUncpr==lFileSize)
{
if (memcmp(FilePtr,UncprPtr,lFileSize)==0)
printf("compare ok\n");
}
printf("press any key to exit the program.");
getchar();
return 0;
}