|
My projects works with Unicode. It seems, like the class (and subclasses) don't like Unicode. I ll try to fix localy, but did you ever test it (or even think of it) ?
Would be a nice addition, that this could be checked (i think, it would be enough, if you are using CStringA instead of CString).
kind regards
|
|
|
|
|
Addition :
Most (not all) are in CShellFileOp class. Here my changes (as Quick Fix) :
SHFileOperation to SHFileOperationA
SHFILEOPSTRUCT to SHFILEOPSTRUCTA
void CShellFileOp::AddFile(const int iSrcDest, CStringA sFile) // changed const CString to CStringA
strcpy(m_pSrc, (char*)sFile.GetBuffer()); // instead of the both old strcpy lines in AddFile.
... And several other CString to CStringA.
I use also 64 Bit check. This generates several warnings, cause the size_t changes to a 64bit int. with some (int) (long) and (UINT) befor every strlen this could be fixed too.
kind regards
|
|
|
|
|
Hi, I'm not able to compile a release version, debug works fine.
I get this error when compiling:
c:\C_prog\VIKINGSELECT\self_extractor\Zlib\minigzip.c(323): fatal error C1010: unexpected end of file while looking for precompiled header directive...
|
|
|
|
|
Wow....
I am very impressed.
Thanks a lot.
|
|
|
|
|
Hi James,
your class depends on the file not being changed after you have written the data out. If I now digitally sign the file with a digital certificate, this adds data to the end of the file. Because your whole implementation depends on reading signatures and TOCs etc from the end of the file, errors are generated when we try to extract the files. I think this is a major problem as more and more software is getting distributed as digitally signed self extracting executables. I will modify your code to make it work for me without the end of file dependency, but it is something to keep in mind.
thanks
Douglas
|
|
|
|
|
I will modify your code to make it work for me
Thanks for contributing.
|
|
|
|
|
Douglas,
How do you compute the size of the digital signature info attached to the end of the executable? I am guessing you need to ignore the signature data to get to the pay load (attached data).
Thanks
SE
|
|
|
|
|
The number file is limited to 256, can it be set at runtime. So that user can select n number of files and create the archive.
|
|
|
|
|
Of course - the MAX_FILE limit was added for simplicity. If you wish to change it please do so, but please post your changes here or email them to me.
Cheers
James
|
|
|
|
|
Whenever you create a CFileExtractor object the MAX_FILE number is used to create File objects right..
This is a hard coded number, How can I use the file number so that it can set at run time.
Now it is set at compile time.
|
|
|
|
|
modify to dynamic MAX_FILE:
fixed project source (self_extractor120220_2.7z) uploaded to:
https://skydrive.live.com/redir.aspx?cid=c17d9b5257172422&resid=C17D9B5257172422!2159&parid=C17D9B5257172422!819&authkey=!AFysZDoThtTrK3k[^]
modify: SelfExtracter.h
#include <afxtempl.h>
//add typedef CArray:
typedef CArray<CSEFileInfo, CSEFileInfo> CSEFileInfoArray;
modify from: CSEFileInfo m_InfoArray[MAX_FILES]; to: CSEFileInfoArray m_InfoArray;
//CSEFileInfo m_InfoArray[MAX_FILES]; // Array of file information
CSEFileInfoArray m_InfoArray;
modify SelfExtracter.cpp: CSelfExtractor::AddFile() as follow:
BOOL CSelfExtractor::AddFile(CString File)
{
CSEFileInfo tmp;
//if(m_nFiles == m_InfoArray.GetSize()/*MAX_FILES*/)
// return FALSE;
//if(m_InfoArray[m_nFiles].SetData(File))
//if(m_InfoArray[m_nFiles].SetData(File, m_strAbsolutePath))
if (tmp.SetData(File, m_strAbsolutePath))
{
m_InfoArray.SetAtGrow(m_nFiles,tmp);
m_nFiles++;
return TRUE;
}
return FALSE;
}
in CSelfExtractor::ReadTOC()
before Read TOC loop, add: m_InfoArray.SetSize(m_nFiles);
m_InfoArray.SetSize(m_nFiles);
//Read the TOC in. The array is filled in reverse to ensure that it
//corresponds to the data segment
for(int i = (m_nFiles - 1); i >= 0 ; i--)
{ ...
modified 20-Feb-12 12:09pm.
|
|
|
|
|
Has anyone modified this code to support maintaining path information such that a person could extract files to a directory and it's subdirectories?
|
|
|
|
|
I haven't done this myself but it would be pretty easy. You could add two new items to the table of contents which are the directory path and length of the directory path. You would write these to the sfx in the same way as the filename. Then when you are extracting, use the Windows API MakeSureDirectoryPathExists() (if you are using Windows 2000 or later) to create the new directory structure. If you need to support older windows versions, there is some code on *the other site* to do the same thing.
Cheers
James
|
|
|
|
|
I have made some changes to accomplish this very thing. If you select Add Directory, all subdirectories will be traversed and relative path information is saved and stored in the TOC, then used in the extraction.
The changes that I made to your original files are as follows. As I don't know how similar my current codebase is to yours, I can't think of a better way of showing my changes.
Also, this currently only works when adding a directory from the SelfExtractor.exe, not when adding individual files.
The following changes to SEFileInfo ensure that we remember the relative path of each file.
SEFileInfo.h changes
==============================
BOOL SetData(CString File, CString szAbsolutePathSegment="");
public:
void SetRelatviePath(CString szRelativePath){m_strRelativePath = szRelativePath;};
CString GetRelativePath(){return m_strRelativePath;};
protected:
CString m_strRelativePath;
SEFileInfo.cpp changes
===============================
BOOL CSEFileInfo::SetData(CString Filename, CString szAbsolutePathSegment)
{
...original code...
// ensure trailing backslash
if ('\\' != szAbsolutePathSegment.Right(1))
szAbsolutePathSegment += "\\";
m_strRelativePath = m_strPathname;
m_strRelativePath.Replace(m_strFilename, "");
m_strRelativePath.Replace(szAbsolutePathSegment, "");
return TRUE;
}
SelfExtractor.h
===============================
public:
BOOL AddDirectory(LPCTSTR szDirectory);
void PutAbsolutePath(LPCTSTR lpszAbsolutePath){m_strAbsolutePath = lpszAbsolutePath;}
protected:
BOOL MakeSurePathExists(CString &Path)
{
int Pos=0;
while((Pos=Path.Find('\\',Pos+1))!=-1)
CreateDirectory(Path.Left(Pos),NULL);
CreateDirectory(Path,NULL);
// ensure we can access it
CFileFind finder;
return finder.FindFile(Path);
}
CString m_strAbsolutePath;
SelfExtractor.cpp
===============================
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::CreateArchive(CFile* pFile, funcPtr pFn, void* userData)
I added to the TOC loop.
//Now Write the TOC
for(int j = 0; j < m_nFiles; j++)
{
....Original Code....
//Write the relative path
len = m_InfoArray[j].GetRelativePath().GetLength();
strncpy(buffer, m_InfoArray[j].GetRelativePath(), len);
pFile->Write(buffer, len);
//Write the length of the relative path
pFile->Write(&len, sizeof(int));
}
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::ExtractOne(CFile* file, int index, CString Dir)
I added at the top of the method.
CString szRelativePath = m_InfoArray[index].GetRelativePath();
CString szAbsolutePath = Dir + szRelativePath;
MakeSurePathExists(szAbsolutePath);
I changed...
CString szFileName = Dir + m_InfoArray[index].GetFilename();
to be...
CString szFileName = szAbsolutePath + m_InfoArray[index].GetFilename();
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::ReadTOC(CString Filename)
I added to the beginning of the read TOC loop.
int lenRelPath = 0;
// Get Length of Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&lenRelPath, sizeof(int));
LastOffset += lenRelPath;
// Get Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, lenRelPath);
LastOffset += sizeof(int);
CString szRelativePath(buffer);
I added to the end of the read TOC loop.
m_InfoArray[i].SetRelatviePath(szRelativePath.Left(lenRelPath));
IN BOOL CSelfExtractor::AddFile(CString File)
I changed...
if(m_InfoArray[m_nFiles].SetData(File))
to...
if(m_InfoArray[m_nFiles].SetData(File, m_strAbsolutePath))
I added the method
/*******************************************************************************
*
* Function: CSelfExtractor::AddDirectory
*
* Author: Lee W. Spencer, 24/7 Systems, Inc.
* Date: 11/20/2003
* E-mail: spencer_tf7@hotmail.com
*
* Description:
* Add a subdirectory to traverse
*
* Parameters:
* szDirectory: Path to traverse
*
* Return:
* BOOL: Success or Failure
*******************************************************************************/
BOOL CSelfExtractor::AddDirectory(LPCTSTR lpszDirectory)
{
CString szDirectoryPath = lpszDirectory;
// ignore these special cases
if("." == szDirectoryPath.Mid(szDirectoryPath.ReverseFind('\\') + 1))
return FALSE;
if(".." == szDirectoryPath.Mid(szDirectoryPath.ReverseFind('\\') + 1))
return FALSE;
// find all files within this directory
CString szPath = szDirectoryPath + "\\*.*";
CFileFind finder;
BOOL bContinue = finder.FindFile(szPath);
while(bContinue)
{
bContinue = finder.FindNextFile();
CString szFoundFilePath = finder.GetFilePath();
if(!AddFile(szFoundFilePath))
{
// recurse
if(finder.IsDirectory())
AddDirectory(szFoundFilePath);
}
}
return TRUE;
}
Self ExtractorDlg.cpp changes
==============================
IN void CSelfExtractorDlg::OnAddDir()
I changed...
CString Path = dlg.GetPathname();
Path += "\\*.*";
to...
CString Path = dlg.GetPathname();
m_Extractor.PutAbsolutePath(Path);
Path += "\\*.*";
AND...
m_Extractor.AddFile(finder.GetFilePath());
to...
if(!m_Extractor.AddFile(finder.GetFilePath()))
{
if(finder.IsDirectory())
m_Extractor.AddDirectory(finder.GetFilePath());
}
|
|
|
|
|
fix: must make ascii-z c-string:
modify: SelfExtracter.cpp
CSelfExtractor::CreateArchive() and CSelfExtractor::ReadTOC():
fixed project source (self_extractor120220_2.7z) uploaded to :
https://skydrive.live.com/redir.aspx?cid=c17d9b5257172422&resid=C17D9B5257172422!2159&parid=C17D9B5257172422!819&authkey=!AFysZDoThtTrK3k[^]
int CSelfExtractor::CreateArchive(CFile& File, funcPtr pFn, void* userData)
{
char buffer[1000]; // Buffer for data
CFile data; // Input file
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 | CFile::shareDenyNone))
{
// Call the user defined CallBack
if(pFn != NULL)
pFn(SFX_FILE_START, static_cast<void*>(&m_InfoArray[i]), userData);
// Record Start Offset
m_InfoArray[i].SetOffset(File.GetPosition());
// Zlib Stuff
int err = Z_OK;
avail_in = 0;
avail_out = ZLibOutputLength;
next_out = m_ZLibOutputBuffer;
m_ZLibFileLength = data.GetLength();
int level = 6;
deflateInit(this, level);
for ( ; ; )
{
// Load input data
if(!ZLibLoadInput(data))
break;
err = deflate(this, Z_NO_FLUSH);
ZLibFlushOutput(File);
if(err != Z_OK)
break;
// Call the user defined CallBack
if(pFn != NULL)
{
int nPercent = Percent();
pFn(SFX_ZIP_INFO, &nPercent, userData);
}
}
// Close this input file
data.Close();
for ( ; ; )
{
err = deflate(this, Z_FINISH);
// Write the output
if (!ZLibFlushOutput(File))
break;
if(err != Z_OK)
break;
}
deflateEnd(this);
// Update the info array with the new compressed size
m_InfoArray[i].SetCompressedSize(total_out);
// Call the user defined CallBack
if(pFn != NULL)
pFn(SFX_FILE_END, static_cast<void*>(&m_InfoArray[i]), userData);
}
else
return INPUT_FILE_ERROR;
}
//Now Write the TOC //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
for(int j = 0; j < m_nFiles; j++)
{
//Write the File Offset
int Offset = m_InfoArray[j].GetFileOffset();
File.Write(&Offset, sizeof(int));
//Write the File Size
int len = m_InfoArray[j].GetFileSize();
File.Write(&len, sizeof(int));
//Write the Compressed File Size
len = m_InfoArray[j].GetCompressedSize();
File.Write(&len, sizeof(int));
//Write the filename
len = m_InfoArray[j].GetFilename().GetLength();
strncpy(buffer, m_InfoArray[j].GetFilename(), len);
File.Write(buffer, len);
//Write the length of the filename
File.Write(&len, sizeof(int));
//Write the relative path //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
len = m_InfoArray[j].GetRelativePath().GetLength();
strncpy(buffer, m_InfoArray[j].GetRelativePath(), len);
if (len) buffer[len]=0;
if (!len)
{
strcpy(buffer,".\\");
len=2;
}
CString tmp;
tmp.Format("[%s][%d]",buffer,len);
//AfxMessageBox(tmp);
if (len) /*pFile->*/File.Write(buffer, len);
else
{
strcpy(buffer,".\\");
len=2;
}
//Write the length of the relative path
/*pFile->*/File.Write(&len, sizeof(int));
}
//Write the total number of files
File.Write((void*)&m_nFiles, sizeof(int));
//Write the vesion
strcpy(buffer, SFX_VERSION);
File.Write(buffer, strlen(SFX_VERSION));
//Write the SIG
strcpy(buffer, SIGNATURE);
File.Write(buffer, strlen(SIGNATURE));
}
catch(CFileException* e)
{
//Got sick of seeing 'unreferenced local variable'
e->m_cause;
return OUTPUT_FILE_ERROR;
}
return UNKNOWN_ERROR;
}
int CSelfExtractor::ReadTOC(CString Filename)
{
CFile Thisfile; //Archive file
char buffer[1000]; //Buffer to read and write with
//Clear the CSEFileInfo class array
Reset();
//Open the archive
if(!Thisfile.Open(Filename, CFile::modeRead | CFile::shareDenyNone))
return NO_SOURCE;
else
{
//Read in the signature
Thisfile.Seek(- static_cast<int>(strlen(SIGNATURE)), CFile::end);
Thisfile.Read(buffer, strlen(SIGNATURE));
// Check that it matches
buffer[strlen(SIGNATURE)]=0;
CString tmp;
tmp.Format("[%s][%s]",buffer, SIGNATURE);
//AfxMessageBox(tmp);
if(strncmp(buffer, SIGNATURE, strlen(SIGNATURE)) != 0)
{
return INVALID_SIG;
}//else AfxMessageBox("SIGNATURE ok");
// Read in the version
int LastOffset = strlen(SIGNATURE) + strlen(SFX_VERSION);
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, strlen(SFX_VERSION));
// Check that the version matches
buffer[strlen(SFX_VERSION)]=0;
CString tmp2;
tmp2.Format("[%s][%s]",buffer, SFX_VERSION);
//AfxMessageBox(tmp2);
if(strncmp(buffer, SFX_VERSION, strlen(SFX_VERSION)) != 0)
{
return INVALID_SIG;
}//else AfxMessageBox("SFX_VERSION ok");
// Read Number of files
LastOffset += sizeof(int);
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&m_nFiles, sizeof(int));
//If there are no files in the archive, there is nothing to extract
if(m_nFiles == 0)
{
AfxMessageBox("m_nFiles == 0");
return NOTHING_TO_DO;
}else
{
CString tmp5;
tmp5.Format("m_nFiles=%d,",m_nFiles);
// AfxMessageBox(tmp5);
}
//Read the TOC in. The array is filled in reverse to ensure that it
//corresponds to the data segment
for(int i = (m_nFiles - 1); i >= 0 ; i--)
{
int lenRelPath = 0;
// Get Length of Relative Path
LastOffset += sizeof(int); //<<
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&lenRelPath, sizeof(int));
CString tmp6;
tmp6.Format("lenRelPath=%d,",lenRelPath);
//AfxMessageBox(tmp6);
LastOffset += lenRelPath;
// Get Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, lenRelPath);
//LastOffset += sizeof(int);
buffer[lenRelPath]=0;
CString tmp4;
tmp4.Format("[%s]",buffer);
//AfxMessageBox(tmp4);
CString szRelativePath(buffer); //<<<<<<<<<<<<<<<<<<<<<<<<<<<
int nSize = 0;
int nCompSize = 0;
int nOffset = 0;
int len = 0;
LastOffset += sizeof(int);
// Get Length of Pathname
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&len, sizeof(int));
LastOffset += len;
// Get Path Name
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, len);
LastOffset += sizeof(int);
buffer[len]=0;
CString tmp3;
tmp3.Format("[%s]",buffer);
// AfxMessageBox(tmp3);
// Get Compressed File Size
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nCompSize, sizeof(int));
LastOffset += sizeof(int);
// Get File Size
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nSize, sizeof(int));
LastOffset += sizeof(int);
// Get File Offset
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nOffset, sizeof(int));
//Set the data in the array
m_InfoArray[i].SetSize(nSize);
m_InfoArray[i].SetCompressedSize(nCompSize);
CString Temp(buffer);
m_InfoArray[i].SetFilename(Temp.Left(len));
m_InfoArray[i].SetOffset(nOffset);
m_InfoArray[i].SetRelatviePath(szRelativePath.Left(lenRelPath));//<<<<<<<<<<<<<<<<
}
//Record the total size of the TOC for use
//when extracting the data segment
m_nTOCSize = LastOffset;
}
//Close the archive
Thisfile.Close();
return SUCCESS;
}
|
|
|
|
|
hi. i wanted to ask how do you add the zlib to your project? i asked this because when i try to add the zlib to my project and buil my project, it give mi 3 errors like this:
LockUpBuilder error LNK2019: unresolved external symbol _deflateEnd referenced in function "public: int __thiscall CSelfExtractor::CreateArchive(class CFile &)" (?CreateArchive@CSelfExtractor@@QAEHAAVCFile@@@Z)
LockUpBuilder error LNK2019: unresolved external symbol _deflate referenced in function "public: int __thiscall CSelfExtractor::CreateArchive(class CFile &)" (?CreateArchive@CSelfExtractor@@QAEHAAVCFile@@@Z)
LockUpBuilder error LNK2019: unresolved external symbol _deflateInit_ referenced in function "public: int __thiscall CSelfExtractor::CreateArchive(class CFile &)" (?CreateArchive@CSelfExtractor@@QAEHAAVCFile@@@Z)
May I know what is wrong?
|
|
|
|
|
Hi,
Can I execute some exe file without extract ?
Rogerio Silva
|
|
|
|
|
Hi Rogerio,
I'm not sure I understand what you are trying to do. Are you saying you want to be able to execute an exe file programatically? If this is the case look for ShellExecuteEx() in MSDN. If you trying to do something else can you give me some more detail.
Cheers
James
|
|
|
|
|
Hi,
I see in your code that you use ExtractAll or ExtractOne to extract a file. Then after extract I can run with ShellExecute.
But I would like to run this app without extract. Run directly from the Self-Extracting file.
It is possible ?
thank you!
|
|
|
|
|
Rogerio Silva wrote:
Run directly from the Self-Extracting file.
It is possible ?
No. The data is compressed in the archive so it would like trying to run a file in a zip file without extracting the zip. The only thing you could do is extract the file in memory but then you wouldn't be able to use ShellExecute with it.
The only solution is to extract it to some temporary directory and run it from there. Why can't you do it like this?
Cheers
James
|
|
|
|
|
I'd like to create a app that protect the software.
This app will check the serial first, then IF correct, execute the app.
But if I copy this file to a temporary folder, someone can get this file without the protection.
|
|
|
|
|
even if you extract it to the memory someone could get the file without the protection...
|
|
|
|
|
And even if you don't extract it a all, someone could get the file from the excutable, or wathever the file is stored to...
|
|
|
|
|
Hello!
First of all i want to say that this SE it's a very good sample for programmers!
Is somebody know how to execute for example "myapp.exe" from WINDIR\Temp? And close self extractor later?
Thanks!
Lukas
|
|
|
|
|
Hey James,
Nice class. I like the way you've implemented it and the TOC setup seems interesting. Mind if I use some of the code in a project I'm doing.. .I'll give you full credit for it
Regards,
Brian Dela
|
|
|
|
|