vc
2007-04-10 10:10
基本构成思想:其实,其中的构成思想非常简单。合并文件时:建立一个新的二进制文件,先写入你的自身捆绑程序的数据和其文件长度,再写入你要捆绑的第一个文件的数据和其文件长度,后再直接写入你要捆绑的第二个文件的数据和文件长度……,最后可直接写入你要捆绑的最后一个文件的数据(不需其文件长度)。分解释放最终合成文件时,也就是将上面的方法思想倒过来既可:打开最终合成文件,读取源自身捆绑程序文件长度,将文件指针移到自身捆绑程序数据后,读取第一个被绑定文件的长度,接着读取其长度的文件数据并写入到一新建文件1中,再读取第二个被绑定文件的长度,接着读取其长度的数据并写入到新建文件2中……,直到最后直接读取最后一个被绑定文件的数据并将其写入到最后一个新建文件中既可。(下面实例仅告诉你如何实现二个文件的捆绑,至于多个文件的捆绑,读者只需略加改动既可,详情请查看下载后的实例代码。)
下面我来讲讲文件捆绑最核心的部分,以及如何具体将其用代码来实现的方法: 1、捆绑多个文件为一个可执行程序 先得到自身捆绑程序的文件长度和第一个要捆绑文件的文件长度,枚举第一个要捆绑文件有无图标,有的话就用它做为最终生成文件的图标,否则用自身捆绑程序所带默认图标做最终生成文件的图标。在新建二进制文件中写入自身捆绑程序的数据和其文件长度,再写入第一个要捆绑文件的数据及其文件长度,最后直接写入第二个文件的数据既可。 合并程序涵数的具体代码实现如下: //定义要使用到的捆绑程序自身文件信息的结构体 structMODIFY_DATA{ unsignedintfinder;//常量(定位自身) _off_tmy_length;//文件长度(自身) }modify_data={0x12345678,0}; //绑定二个文件为一个可执行文件 boolCBindFileDlg::Bind_Files() { FILE*myself;//自身文件 FILE*out;//最终合成文件 FILE*in;//待绑定文件 intbytesin;//一次读文件字节数 inttotalbytes=0;//读出文件总字节数 struct_statST;//文件的状态信息(如文件长度等) unsignedintfinder=0x12345678;//自身文件定位 unsignedinti,k; intl=1;//进度条状态显示变量 charbuff[20];//进度条状态显示变量 his_name=strFirstFilePath;//第一个绑定的文件名 _stat(my_name,&ST);//获取自身捆绑文件信息 modify_data.my_length=ST.st_size;//得到自身文件长度 if(modify_data.my_length==0) { MessageBox("绑定文件中,自身文件长度为零时出错!","错误"); returnfalse; } buf=(BYTE*)malloc(modify_data.my_length);//分配一定大小缓冲区 if(buf==NULL) { MessageBox("绑定文件中,分配自身文件长度时出错!","错误"); returnfalse; } myself=fopen(my_name,"rb");//打开自身文件 if(myself==NULL) { free(buf); MessageBox("绑定文件中,打开自身文件时出错!","错误"); returnfalse; } //先读取捆绑程序自身文件数据 bytesin=fread(buf,1,modify_data.my_length,myself); fclose(myself); if(bytesin!=modify_data.my_length) { free(buf); MessageBox("绑定文件中,不能完全读取自身文件内容时出错!","错误"); returnfalse; } //存储自身文件信息到缓冲区(如长度) for(i=0;i<modify_data.my_length-sizeof(finder);i+=sizeof(finder)) { for(k=0;k<sizeof(finder);k++) { if(buf[i+k]!=((BYTE*)&finder)[k]) break; } if(k==sizeof(finder))//定位并保存自身数据文件信息 { memcpy(buf+i,&modify_data,sizeof(modify_data)); break; } } if(i>=modify_data.my_length-sizeof(finder)) { free(buf); MessageBox("绑定文件中,不能定位自身文件时出错!","错误"); returnfalse; } //获取第一个要绑定文件的信息(文件长度) if(_stat(strFirstFilePath,&ST)!=0||ST.st_size==0) { free(buf); MessageBox("绑定文件中,读取第一个要绑定文件时出错!","错误"); returnfalse; } //获取自身文件图标及第一个要绑定文件的图标(如第一个要绑定文件没有图标, //则用自身文件图标。其涵数实现请参看例程) list_my_icons(); out=fopen(strFinalFilePath,"wb");//创建最终合成文件 if(out==NULL) { free(buf); MessageBox("绑定文件中,创建绑定后生成的合成文件时出错!","错误"); returnfalse; } //先将前面读出的自身捆绑程序的数据写入最终合成文件中 totalbytes+=fwrite(buf,1,bytesin,out); in=fopen(strFirstFilePath,"rb");//打开第一个要绑定的文件 if(in==NULL) { free(buf); MessageBox("绑定文件中,打开第一个要绑定文件时出错!","错误"); returnfalse; } //写入第一个要绑定文件的长度到最终合成文件中 totalbytes+=fwrite(&ST.st_size,1,sizeof(ST.st_size),out); //写入最终分解后文件执行方式的标志位(同步或异步执行) UpdateData(TRUE);//传控件值到变量m_Sync中 totalbytes+=fwrite(&m_Sync,1,sizeof(int),out); //写入第一个要绑定文件的数据到最终合成文件中 while(bytesin=fread(buf,1,modify_data.my_length,in)) { totalbytes+=fwrite(buf,1,bytesin,out); } fclose(in);//关闭第一个绑定文件句柄 //设置进度条显示 m_Progress.SetRange(0,500); for(intm=0;m<500;m++) m_Progress.SetPos(m); m_Parts=_ltoa(l,buff,10); m_Parts+=_T("个文件已绑定"); UpdateData(FALSE); l++; in=fopen(strSecondFilePath,"rb");//打开第二个要绑定的文件 if(in==NULL) { free(buf); MessageBox("绑定文件中,打开第二个要绑定文件时出错!","错误"); returnfalse; } //直接写入第二个要绑定文件的数据到最终合成文件中 while(bytesin=fread(buf,1,modify_data.my_length,in)) { totalbytes+=fwrite(buf,1,bytesin,out); } //设置进度条显示 m_Progress.SetRange(0,500); for(intn=0;n<500;n++) m_Progress.SetPos(n); m_Parts=_ltoa(l,buff,10); m_Parts+=_T("个文件已绑定"); UpdateData(FALSE); l++; fclose(in);//关闭第二个绑定文件句柄 fclose(out);//关闭最终合成文件句柄 free(buf);//释放缓冲区 returntrue; } 2、释放最终合成文件并同3、时运行它们。 打开自身文件,从中得到自身捆绑程序的文件长度,便可将文件指针定位到第一个被捆绑文件的位置,读取其文件长度和其数据,将其读出数据写入第一个新建文件中。同样,通过已读取的自身捆绑程序文件长度和第一个被捆绑文件的文件长度加上其保存这两个文件长度值的字节数,既可准确定位第二个被捆绑文件的位置,读取其数据,写入到第二个新建文件中。同时,运行这两个文件,最后再删除这两个文件既可。 释放最终合成文件的代码具体实现如下: //创建分解文件后,运行各分解文件时的进程 voidCBindFileDlg::Create_Process(constchar*temp_exe,BOOLasync) { HANDLEhProcess;//进程句柄 HANDLEhThread;//线程句柄 PROCESS_INFORMATIONPI;//进程信息 STARTUPINFOSI;//启动信息 memset(&SI,0,sizeof(SI));//分配一定的内存 SI.cb=sizeof(SI);//大小赋给启动信息内CB CreateProcess(temp_exe,NULL,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&SI,&PI); /*---暂不用,否则需要保存原始绑定的文件名称 //如果分解后的文件不是执行文件的话,则直接打开它 if(!CreateProcess(temp_exe,NULL,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&SI,&PI)) HINSTANCEresult=ShellExecute(NULL,_T("open"),temp_exe,NULL,NULL,SW_SHOW); ---*/ hProcess=PI.hProcess; hThread=PI.hThread; //异步执行时,执行后不删除分解后的文件;同步执行时,执行后删除分解后的文件 if(!async)//当同步执行时 { //一直等待,直到当前程序运行进程结束 WaitForSingleObject(hProcess,INFINITE); unlink(temp_exe);//删除temp.exe文件 } } //分解已合并的文件,同时运行它们 voidCBindFileDlg::Unbind() { FILE*myself;//自身文件 FILE*out;//分解后文件 intbytesin;//一次读出文件的字节数 inttotalbytes=0;//读出文件的总字节数 chartemp_exe1[]="temp1.exe";//分解后的绑定文件名一(可任意取) chartemp_exe2[]="temp2.exe";//分解后的绑定文件名二(可任意取) intSyncFlag;//文件最终执行标志(同步或异步) //先分配一定大小的缓冲区(大小等于捆绑程序长度) buf=(BYTE*)malloc(modify_data.my_length); myself=fopen(my_name,"rb");//打开最终合成文件 if(myself==NULL) { free(buf); MessageBox("分离文件中,打开自身文件时出错!","错误"); return; } out=fopen(temp_exe1,"wb");//创建第一个绑定的文件 if(out==NULL) { free(buf); MessageBox("分离文件中,创建第一个被绑定文件时出错!","错误"); return; } //将文件指针定位到捆绑器程序长度尾部 fseek(myself,modify_data.my_length,SEEK_SET); //读取第一个绑定文件的长度 if(fread(&prog1_length,sizeof(prog1_length),1,myself)==0) { free(buf); MessageBox("分离文件中,读取第一个被绑定文件长度时出错!","错误"); return; } //读取最终文件执行方式(同步或异步执行) if(fread(&SyncFlag,sizeof(int),1,myself)==0) { free(buf); MessageBox("分离文件中,读取第一个被绑定文件长度时出错!","错误"); return; } //读取第一个文件内容并写入到新建的temp1.exe文件中 while(bytesin=fread(buf,1,sizeof(buf),myself)) { if(totalbytes+bytesin>prog1_length) bytesin=prog1_length-totalbytes; totalbytes+=fwrite(buf,1,bytesin,out); } fclose(out);//关闭第一个绑定文件句柄 #ifdefDEBUG_PRINT fprintf(stderr,"已复制%d字节! ",totalbytes); #endifDEBUG_PRINT totalbytes=0; out=fopen(temp_exe2,"wb");//创建第二个绑定的文件 if(out==NULL) { free(buf); MessageBox("分离文件中,创建第二个被绑定文件时出错!","错误"); return; } //将文件指针定位到最终合成文件中的第二个绑定文件头部,偏移量== //(捆绑器自身文件长度+保存第一个绑定文件长度所占字节数+保存最终文件执行标志所占字节数+第一个绑定文件长度) fseek(myself,modify_data.my_length+sizeof(modify_data.my_length)+sizeof(int)+prog1_length,SEEK_SET); //读取第二个绑定文件内容并写入到新建的temp2.exe文件中 while(bytesin=fread(buf,1,sizeof(buf),myself)) { totalbytes+=fwrite(buf,1,bytesin,out); } fclose(out);//关闭第二个绑定文件句柄 #ifdefDEBUG_PRINT fprintf(stderr,"已复制%d字节 ",totalbytes); #endifDEBUG_PRINT fclose(myself);//关闭最终合成文件句柄 if(totalbytes==0) { free(buf); MessageBox("分离文件中,在自身文件中没有被分离的对象!","错误"); return; } free(buf);//释放缓冲区 //判断前面读取的最终文件执行标志,来决定以何种方式运行它 if(!SyncFlag)//(0--同步执行,1--异步执行) { //置为分解后,为同步执行方式 Create_Process(temp_exe1,false); Create_Process(temp_exe2,false); } else { //置为分解后,为异步执行方式 Create_Process(temp_exe1,true); Create_Process(temp_exe2,true); } } 3、判断何时捆绑程序,何时又分解最终合成程序。 由于本程序是将自身捆绑程序作为文件头,要绑定文件附加其后方式生成最终合成文件的。所以,只要知道自身捆绑程序的文件长度,再在初始化对话框涵数OnInitDialog()加以判断及可知道是否是最终合成文件(要不要释放内部绑定文件)。本例程用VC6.0采用静态连接方式生成的Release版,文件大小为184K。 故判断是捆绑还是释放文件的代码具体实现如下: BOOLCBindFileDlg::OnInitDialog() { CDialog::OnInitDialog(); //Add"About..."menuitemtosystemmenu. //IDM_ABOUTBOXmustbeinthesystemcommandrange. ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX<0xF000); CMenu*pSysMenu=GetSystemMenu(FALSE); if(pSysMenu!=NULL) { CStringstrAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if(!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu); } } //Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE);//Setbigicon SetIcon(m_hIcon,FALSE);//Setsmallicon //在此初始化渐变色进度条 m_Progress.SetRange32(1,500); m_Progress.SetBkColor(RGB(160,180,220)); m_Progress.ShowPercent(true); m_Progress.SetPos(500); //初始置各文件名变量为空 strFirstFilePath="";//要绑定第一个文件名 strSecondFilePath="";//要绑定第二个文件名 strFinalFilePath="";//最终合成文件名 //初始化变量 prog1_length=0;//文件长度 his_name="";//绑定文件名 buf=NULL;//缓冲区置空 //获取自身文件名到my_mane变量中 ::GetModuleFileName(0,my_name,sizeof(my_name)); struct_statST; _stat(my_name,&ST);//获取自身文件信息(长度) //在此加入捆绑器程序的最终大小,来判断是绑定文件还是分解执行文件 //当发现自身文件大小大于原大小184K时,为释放内部合成文件 if(ST.st_size>184*1024) { Unbind();//分离文件并运行 exit(0);//直接退出程序,不显示捆绑程序画面 } returnTRUE;//returnTRUEunlessyousetthefocustoacontrol } 其中具体实现细节问题,可在下载实例代码后,仔细查看既可(内有详细注释)。 |