📄 selfextractor.cpp
字号:
/*************************************************************************************
*
* File: SelfExtracter.cpp
* Version: 1.0
*
* Author: James Spibey
* Date: 04/08/1999
* E-mail: spib@bigfoot.com
*
* Implementation of the CSelfExtracter class
*
* You are free to use, distribute or modify this code
* as long as this header is not removed or modified.
*
*
*************************************************************************************/
#include "stdafx.h"
#include "SelfExtractor.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/*******************************************************************************
*
* Function: CSelfExtractor::CSelfExtractor
*
* Description:
* Default Constructor
*
* Parameters:
* None
*
* Return:
* None
*******************************************************************************/
CSelfExtractor::CSelfExtractor()
{
m_nFiles = 0;
m_nTOCSize = 0;
m_dCurReadSize = 0;
}
/*******************************************************************************
*
* Function: CSelfExtractor::~CSelfExtractor
*
* Description:
* Destructor
*
* Parameters:
* None
*
* Return:
* None
*******************************************************************************/
CSelfExtractor::~CSelfExtractor()
{
}
/*******************************************************************************
*
* Function: CSelfExtractor::Create
*
* Description:
* Creates the Self-extracting executable
*
* Parameters:
* CString ExtractorPath: Path to the Extractor Executable
* CString Filename: Filename of the Self Extracting Archive to create
* funcPtr pFn: Pointer to a user defined callback function
* void* UserData: User defined data to pass to the callback function
*
* Return:
* int: Error Code
* NOTHING_TO_DO - No files have been selected to be archived
* COPY_FAILED - Failed to copy the extractor
* OUTPUT_FILE_ERROR - Failed to open the copied file for appending
* INPUT_FILE_ERROR - Failed to open an input file
*******************************************************************************/
int CSelfExtractor::Create(CString ExtractorPath, CString Filename, funcPtr pFn /* = NULL */, void* userData /*=NULL*/)
{
//Make sure we have some files to add
if(m_nFiles < 1)
return NOTHING_TO_DO;
//Copy the extractor to the new archive
CShellFileOp shOp;
shOp.SetFlags(FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT);
shOp.AddFile(SH_SRC_FILE, ExtractorPath);
shOp.AddFile(SH_DEST_FILE, Filename);
if(shOp.CopyFiles() != 0)
return COPY_FAILED;
//Open the archive
CFile file;
if(!file.Open(Filename, CFile::modeWrite))
return OUTPUT_FILE_ERROR;
else
{
//Start at the end of the archive
file.SeekToEnd();
CreateArchive(&file, pFn, userData);
//Close the archive
file.Close();
}
return SUCCESS;
}
/*******************************************************************************
*
* Function: CSelfExtractor::Create
*
* Description:
* Creates the Self-extracting executable from an extractor in resources.
* Simply import the exe into your resources, making sure you specify the type
* as "SFX_EXE". Then just past the resource ID as the first parameter
*
* Parameters:
* UINT resource: Resource ID (eg IDR_SFX_EXE)
* CString Filename: Filename of the Self Extracting Archive to create
* funcPtr pFn: Pointer to a user defined callback function
* void* UserData: User defined data to pass to the callback function
*
* Return:
* int: Error Code
* NOTHING_TO_DO - No files have been selected to be archived
* COPY_FAILED - Failed to copy the extractor
* OUTPUT_FILE_ERROR - Failed to open the copied file for appending
* INPUT_FILE_ERROR - Failed to open an input file
*******************************************************************************/
int CSelfExtractor::Create(UINT resource, CString Filename, funcPtr pFn /* = NULL */, void* userData /*=NULL*/)
{
//Make sure we have some files to add
if(m_nFiles < 1)
return NOTHING_TO_DO;
//Load the extractor from resources
HRSRC hrSrc = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(resource), "SFX_EXE");
if(hrSrc == NULL)
return RESOURCE_ERROR;
HGLOBAL hGlobal = LoadResource(AfxGetResourceHandle(), hrSrc);
if(hGlobal == NULL)
return RESOURCE_ERROR;
LPVOID lpExe = LockResource(hGlobal);
if(lpExe == NULL)
return RESOURCE_ERROR;
//Create the new archive from the extractor in the resources
CFile file;
if(!file.Open(Filename, CFile::modeCreate | CFile::modeWrite))
return OUTPUT_FILE_ERROR;
else
{
//Write the extractor exe
file.Write(lpExe, (UINT)SizeofResource(AfxGetResourceHandle(), hrSrc));
//Do the rest
CreateArchive(&file, pFn, userData);
//Close the archive
file.Close();
}
return SUCCESS;
}
int CSelfExtractor::CreateArchive(CFile* pFile, funcPtr pFn, void* userData)
{
DWORD dwRead = 0; //Total Data read from input file
DWORD dw = 0; //Last amount read from input file
char buffer[1000]; //Buffer for data
CFile data; //Input file
m_dCurReadSize = 0;
try
{
//Copy all the inout files into the archive
for(int i = 0; i < m_nFiles; i++)
{
//Open the input file
if(data.Open(m_InfoArray[i].GetPathname(), CFile::modeRead))
{
dwRead = 0;
m_InfoArray[i].SetOffset(pFile->GetPosition());
//Read data in and write it out until the end of file
while(static_cast<int>(dwRead) < m_InfoArray[i].GetFileSize())
{
dw = data.Read(buffer, 1000);
pFile->Write(buffer, dw);
dwRead += dw;
m_dCurReadSize = dwRead;
//Call the user defined CallBack
if(pFn != NULL)
pFn(static_cast<void*>(&m_InfoArray[i]), userData);
}
//Close this input file
data.Close();
}
else
return INPUT_FILE_ERROR;
}
//Now Write the TOC
for(int j = 0; j < m_nFiles; j++)
{
//Write the File Size
int Offset = m_InfoArray[j].GetFileOffset();
pFile->Write(&Offset, sizeof(int));
//Write the File Size
int len = m_InfoArray[j].GetFileSize();
pFile->Write(&len, sizeof(int));
//Write the filename
len = m_InfoArray[j].GetFilename().GetLength();
strncpy(buffer, m_InfoArray[j].GetFilename(), len);
pFile->Write(buffer, len);
//Write the length of the filename
pFile->Write(&len, sizeof(int));
}
//Write the total number of files
pFile->Write((void*)&m_nFiles, sizeof(int));
//Write the SIG
strcpy(buffer, SIGNATURE);
pFile->Write(buffer, strlen(SIGNATURE));
}
catch(CFileException* e)
{
//Got sick of seeing 'unreferenced local variable'
e->m_cause;
return OUTPUT_FILE_ERROR;
}
return SUCCESS;
}
/*******************************************************************************
*
* Function: CSelfExtractor::ExtractAll
*
* Description:
* Extract the current archive to the specified directory
*
* Parameters:
* CString Dir: Destination Directory
* funcPtr pFn: Pointer to a user defined callback function
* void* UserData: User defined data to pass to the callback function
*
* Return:
* int: Error Code
* INPUT_FILE_ERROR - Failed to open the input file
* OUTPUT_FILE_ERROR - Failed to create an output file
*******************************************************************************/
int CSelfExtractor::ExtractAll(CString Dir, funcPtr pFn /*= NULL*/, void * userData /*= NULL*/)
{
//Make sure the directory name has a trailing backslash
EnsureTrailingBackSlash(Dir);
CFile Thisfile; //Archive (Usually itself)
//Read the Table of Contents
int res = ReadTOC(GetThisFileName());
if(res != SUCCESS)
return res;
//Open the archive
if(!Thisfile.Open(GetThisFileName(), CFile::modeRead))
return INPUT_FILE_ERROR;
else
{
m_dCurReadSize = 0;
//Get the files out in reverse order so we can work out the offsets
//Subtract 1 from the filecount as we are zero-based
for(int i = (m_nFiles - 1); i >= 0 ; i--)
{
ExtractOne(&Thisfile, i, Dir, pFn, userData);
}
//Close the archive
Thisfile.Close();
}
return SUCCESS;
}
/*******************************************************************************
*
* Function: CSelfExtractor::Extract
*
* Description:
* Extract a single file from the current archive to the specified directory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -