 |
|
 |
Why isn't the project link in the article a self extracting archive?!
-bruce
|
|
|
|
 |
|
|
 |
|
 |
It could use, for example, the env. var. %ProgramFiles% to give an extract dir.
|
|
|
|
 |
|
 |
Hi,
I used the code from this thread (below) to modify this app to include subdirs. The filelist after AddDirectory is ok and it makes .exe. But running .exe gives a "An unknown error occurred while accessing .. .exe". It's built VS 2005 on Vista. Any ideas?
|
|
|
|
 |
|
 |
Hai this is very good work from you.But i need to have the SFX with my given icon.Is there solution?
|
|
|
|
 |
|
 |
Hello,
I tried to run your extractor exe in vista but it says that this exe has stopped working.
How o fix this problem...
|
|
|
|
 |
|
 |
it works fine for me both in 64 bit as well as 32 bit versions of vista
|
|
|
|
 |
|
 |
Thanks so much for putting this together, James, nice work. Really came in handy as I needed to create a self-extracting archive programmatically in a hurry. I like the simplicity of your code examples, the projects -overall the best I have seen on the web and you did this nearly five years ago. Well done!
|
|
|
|
 |
|
 |
Wow, what a great comment - thank you very much. To be honest I'd forgotten all about this article and I'm surprised that people are still using the code now we're in the .NET world, but it's really great to see that people are getting benefit out of it all the same
Cheers
James
|
|
|
|
 |
|
 |
...yeah, not all of us are in the .NET world yet, unfortunately, and in fact we're kind of in this VC6 migration to .NET and Java now, yet we cannot fully migrate over, so these kinds of VC6 MFC tools are still very valuable in-house and in the field.
|
|
|
|
 |
|
 |
I am trying out his utility and one thing I don't understand.
I have a SETUP.EXE program that changes for external files in the same location which the SETUP.EXE started. So if I used WINZIPSE for example
to compress and create a SFX with 4 files:
FILE1.INI
FILE2.DLL
FILE3.EXE
SETUP.EXE
to create the SFX
SETUP-SFX.EXE
when this starts, then it will decompress all these files into the TEMP Folder, run SETUP.EXE and SETUP.EXE will see the 3 additional files.
With this UTILITY, it seems to only decompress the SETUP.EXE. Not the othe r files so SETUP.EXE never sees the 3 FILE*.* files.
What I am missing? Or this utility not one I can use for what I want?
Thanks
---
HLS
|
|
|
|
 |
|
 |
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.
|
|
|
|
 |
|
 |
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()); }
|
|
|
|
 |