多个文件的捆绑,为了实现上述功能,可以将主程序中加入分解功能,或者使用一个自解压的控制程序来进行文件的分解。下面以一个自解压控制程序来说明问题:
捆绑之后的程序结构如下所示:
自解压控制程序
|
文件原始信息1
|
文件原始内容1
|
文件原始信息2
|
文件原始内容2
|
解压控制信息
|
每一个捆绑的文件都使用一个结构储存信息,添加到自解压控制程序后面,分解时再由控制程序读出信息并解出文件。
该结构信息如下:
typedef struct _SELF_EXTRACT_INFO //每个被捆绑的文件信息
{
TCHAR cFileName[50]; //文件名
DWORD nFileSize; //文件长度
BOOL bExecute; //是否解出后运行
}SELF_EXTRACT_INFO, *PSELF_EXTRACT_INFO;
可视情况自行增加存储信息,在控制程序中进行对应操作。
在所有捆绑的文件以及文件信息都加到自解压文件后,在最后写入一个控制信息结构,记录文件数量等的控制信息。控制信息结构如下:
typedef struct _CONTROL_INFO //控制体信息结构
{
DWORD nObjectSize; //母体程序文件长度
DWORD nBindNum; //被捆绑文件个数
DWORD nFileSize; //捆绑后文件长、用于校验
DWORD nBindType; //捆绑方式、压缩、不压缩
DWORD nExecuteType; //指定文件执行方式,等待、立即返回
}CONTROL_INFO, *PCONTROL_INFO;
相应的,增加控制功能可以在此结构中增加对应的成员,并在自解压程序中加入对应控制功能。
下面首先完成自解压控制程序的母体。生成一个完整的程序,之后完成一个捆绑程序,用于生成一个新的程序,内容如文章开头表格所示。
自解压控制程序主要代码:
BOOL TForm1::ExtractFiles()
... {
CONTROL_INFO KeyInfo;
SELF_EXTRACT_INFO BindFile;
TCHAR szModule[MAX_PATH];
DWORD Count;
FILE *pfread, *pfwrite;
//
if(GetModuleFileName(NULL,szModule,MAX_PATH)==0)
return FALSE;
//
if((pfread = fopen(szModule,"rb"))==NULL)
return FALSE;
//by jingzhongrong
//获取自身文件长度
struct _stat st;
_stat(szModule,&st);
DWORD FileSize = st.st_size;
//
//控制体信息结构位置
DWORD Offset = FileSize-sizeof(CONTROL_INFO);
if(Offset<0) return FALSE;
//
//读取信息
fseek(pfread,Offset,SEEK_SET);
fread(&KeyInfo,1,sizeof(CONTROL_INFO),pfread);
//校验文件长度
//Extract file
DWORD pos = KeyInfo.nObjectSize;
for(DWORD i=1; i<KeyInfo.nBindNum; i++)
...{
//read
fseek(pfread,pos,SEEK_SET);
fread(&BindFile,1,sizeof(SELF_EXTRACT_INFO),pfread);
//
//分解出文件
if((pfwrite = fopen(BindFile.cFileName,"wb"))==NULL)
...{
fclose(pfread);
return FALSE;
}
int c;
pos = pos + sizeof(SELF_EXTRACT_INFO);
fseek(pfread,pos,SEEK_SET);
//by jingzhongrong
Count = 0;
while((c=fgetc(pfread))!=EOF)
...{
fputc(c,pfwrite);
Count++;
if(Count == BindFile.nFileSize)
break;
}
pos = pos + BindFile.nFileSize;
fclose(pfwrite);
//
if(BindFile.bExecute == TRUE)
...{
this->ExecuteFiles->Add(AnsiString(BindFile.cFileName));
}
}
//
fclose(pfread);
return TRUE;
}
... {
CONTROL_INFO KeyInfo;
SELF_EXTRACT_INFO BindFile;
TCHAR szModule[MAX_PATH];
DWORD Count;
FILE *pfread, *pfwrite;
//
if(GetModuleFileName(NULL,szModule,MAX_PATH)==0)
return FALSE;
//
if((pfread = fopen(szModule,"rb"))==NULL)
return FALSE;
//by jingzhongrong
//获取自身文件长度
struct _stat st;
_stat(szModule,&st);
DWORD FileSize = st.st_size;
//
//控制体信息结构位置
DWORD Offset = FileSize-sizeof(CONTROL_INFO);
if(Offset<0) return FALSE;
//
//读取信息
fseek(pfread,Offset,SEEK_SET);
fread(&KeyInfo,1,sizeof(CONTROL_INFO),pfread);
//校验文件长度
//Extract file
DWORD pos = KeyInfo.nObjectSize;
for(DWORD i=1; i<KeyInfo.nBindNum; i++)
...{
//read
fseek(pfread,pos,SEEK_SET);
fread(&BindFile,1,sizeof(SELF_EXTRACT_INFO),pfread);
//
//分解出文件
if((pfwrite = fopen(BindFile.cFileName,"wb"))==NULL)
...{
fclose(pfread);
return FALSE;
}
int c;
pos = pos + sizeof(SELF_EXTRACT_INFO);
fseek(pfread,pos,SEEK_SET);
//by jingzhongrong
Count = 0;
while((c=fgetc(pfread))!=EOF)
...{
fputc(c,pfwrite);
Count++;
if(Count == BindFile.nFileSize)
break;
}
pos = pos + BindFile.nFileSize;
fclose(pfwrite);
//
if(BindFile.bExecute == TRUE)
...{
this->ExecuteFiles->Add(AnsiString(BindFile.cFileName));
}
}
//
fclose(pfread);
return TRUE;
}
程序由BCB完成,带有一些BCB特有的VCL类型,如TStringList、AnsiString。
下面是捆绑的程序,使用该程序进行捆绑生成一个新的程序,该程序便是可以进行自动分解的程序了。还可以加入分解后运行某一个文件的功能。
下面是主要实现代码:
BOOL TForm1::DoBind(BOOL self, AnsiString filename) //自解压
... {
int ExecuteFileNum = strExecuteFile->Count;
int NonExecuteFileNum = strNonExecuteFile->Count;
AnsiString strSelfExtFile = filename;
int FileNum = ExecuteFileNum + NonExecuteFileNum;
//CONTROL_INFO SELF_EXTRACT_INFO
SELF_EXTRACT_INFO *pBind = new SELF_EXTRACT_INFO[FileNum+1];
CONTROL_INFO KeyInfo;
DWORD nFileSize;
struct _stat st;
//
FILE *fpread, *fpwrite;
//
if((fpwrite = fopen(strSelfExtFile.c_str(),"wb"))==NULL)
...{
delete []pBind;
return FALSE;
}
if(self == TRUE) //自解压
...{
FileNum++;
AnsiString matrix = ExtractFilePath(Application->ExeName);
matrix = matrix + "MatrixFile.exe";
_stat(matrix.c_str(),&st);
pBind[0].nFileSize = st.st_size;
//此处加入母体程序
if((fpread = fopen(matrix.c_str(),"rb"))==NULL)
...{
delete []pBind;
fclose(fpwrite);
return FALSE;
}
int c;
while((c = fgetc(fpread))!=EOF)
...{
fputc(c,fpwrite);
}
fclose(fpread);
}
else
...{
_stat(strExecuteFile->Strings[0].c_str(),&st);
pBind[0].nFileSize = st.st_size;
}
//by jingzhongrong
int i;
for(i=0; i<ExecuteFileNum; i++)
...{
strcpy(pBind[i+1].cFileName,strExecuteFile->Strings[i].c_str());
_stat(strExecuteFile->Strings[i].c_str(),&st);
pBind[i+1].nFileSize = st.st_size;
nFileSize += st.st_size;
pBind[i+1].bExecute = TRUE;
}
for(i=0; i<NonExecuteFileNum; i++)
...{
strcpy(pBind[i+1+ExecuteFileNum].cFileName,strNonExecuteFile->Strings[i].c_str());
_stat(strNonExecuteFile->Strings[i].c_str(),&st);
pBind[i+1+ExecuteFileNum].nFileSize = st.st_size;
nFileSize += st.st_size;
pBind[i+1+ExecuteFileNum].bExecute = TRUE;
}
KeyInfo.nBindNum = FileNum;
KeyInfo.nObjectSize = pBind[0].nFileSize;
if(self==TRUE)
...{
nFileSize += pBind[0].nFileSize;
}
else
...{
}
KeyInfo.nFileSize = nFileSize + sizeof(CONTROL_INFO) + (FileNum-1)*sizeof(SELF_EXTRACT_INFO);
KeyInfo.nBindType = 0;
KeyInfo.nExecuteType = 1;
//
FileNum = ExecuteFileNum + NonExecuteFileNum + 1;
for(i=1;i<FileNum;i++)
...{
if((fpread = fopen(pBind[i].cFileName,"rb"))==NULL)
...{
delete []pBind;
return FALSE;
}
strcpy(pBind[i].cFileName,ExtractFileName(AnsiString(pBind[i].cFileName)).c_str());
fwrite(&pBind[i],1,sizeof(SELF_EXTRACT_INFO),fpwrite);
int c;
while((c = fgetc(fpread)) != EOF)
...{
fputc(c,fpwrite);
}
fclose(fpread);
}
fwrite(&KeyInfo,1,sizeof(CONTROL_INFO),fpwrite);
fclose(fpwrite);
delete []pBind;
//
return TRUE;
}
... {
int ExecuteFileNum = strExecuteFile->Count;
int NonExecuteFileNum = strNonExecuteFile->Count;
AnsiString strSelfExtFile = filename;
int FileNum = ExecuteFileNum + NonExecuteFileNum;
//CONTROL_INFO SELF_EXTRACT_INFO
SELF_EXTRACT_INFO *pBind = new SELF_EXTRACT_INFO[FileNum+1];
CONTROL_INFO KeyInfo;
DWORD nFileSize;
struct _stat st;
//
FILE *fpread, *fpwrite;
//
if((fpwrite = fopen(strSelfExtFile.c_str(),"wb"))==NULL)
...{
delete []pBind;
return FALSE;
}
if(self == TRUE) //自解压
...{
FileNum++;
AnsiString matrix = ExtractFilePath(Application->ExeName);
matrix = matrix + "MatrixFile.exe";
_stat(matrix.c_str(),&st);
pBind[0].nFileSize = st.st_size;
//此处加入母体程序
if((fpread = fopen(matrix.c_str(),"rb"))==NULL)
...{
delete []pBind;
fclose(fpwrite);
return FALSE;
}
int c;
while((c = fgetc(fpread))!=EOF)
...{
fputc(c,fpwrite);
}
fclose(fpread);
}
else
...{
_stat(strExecuteFile->Strings[0].c_str(),&st);
pBind[0].nFileSize = st.st_size;
}
//by jingzhongrong
int i;
for(i=0; i<ExecuteFileNum; i++)
...{
strcpy(pBind[i+1].cFileName,strExecuteFile->Strings[i].c_str());
_stat(strExecuteFile->Strings[i].c_str(),&st);
pBind[i+1].nFileSize = st.st_size;
nFileSize += st.st_size;
pBind[i+1].bExecute = TRUE;
}
for(i=0; i<NonExecuteFileNum; i++)
...{
strcpy(pBind[i+1+ExecuteFileNum].cFileName,strNonExecuteFile->Strings[i].c_str());
_stat(strNonExecuteFile->Strings[i].c_str(),&st);
pBind[i+1+ExecuteFileNum].nFileSize = st.st_size;
nFileSize += st.st_size;
pBind[i+1+ExecuteFileNum].bExecute = TRUE;
}
KeyInfo.nBindNum = FileNum;
KeyInfo.nObjectSize = pBind[0].nFileSize;
if(self==TRUE)
...{
nFileSize += pBind[0].nFileSize;
}
else
...{
}
KeyInfo.nFileSize = nFileSize + sizeof(CONTROL_INFO) + (FileNum-1)*sizeof(SELF_EXTRACT_INFO);
KeyInfo.nBindType = 0;
KeyInfo.nExecuteType = 1;
//
FileNum = ExecuteFileNum + NonExecuteFileNum + 1;
for(i=1;i<FileNum;i++)
...{
if((fpread = fopen(pBind[i].cFileName,"rb"))==NULL)
...{
delete []pBind;
return FALSE;
}
strcpy(pBind[i].cFileName,ExtractFileName(AnsiString(pBind[i].cFileName)).c_str());
fwrite(&pBind[i],1,sizeof(SELF_EXTRACT_INFO),fpwrite);
int c;
while((c = fgetc(fpread)) != EOF)
...{
fputc(c,fpwrite);
}
fclose(fpread);
}
fwrite(&KeyInfo,1,sizeof(CONTROL_INFO),fpwrite);
fclose(fpwrite);
delete []pBind;
//
return TRUE;
}
上面代码是我直接从程序中复制过来的,没有去修改,程序功能比这篇文章中所写要复杂一点,所以下面说一下代码的主要流程。
先读取自解压控制程序然后写入一个指定的文件中,之后读取要捆绑的文件的文件信息,填充SELF_EXTRACT_INFO结构,之后写入文件,再把捆绑的文件内容接着写入文件,重复知道所有要捆绑的文家全部写入完成,在最后,程序填充控制信息CONTROL_INFO结构,写在文件最后,这是为了自解压控制程序可以读出有关的控制信息。
读出写入文件的主要代码如下:
fwrite(&pBind[i],1,sizeof
(SELF_EXTRACT_INFO),fpwrite);
int c;
while((c = fgetc(fpread)) != EOF)
{
fputc(c,fpwrite);
}
fclose(fpread);
int c;
while((c = fgetc(fpread)) != EOF)
{
fputc(c,fpwrite);
}
fclose(fpread);
//write by jingzhongrong
last edit by jingzhongrong at 17:51 2007/2/24