Part - 4

How to build the merge data file
At this stage, you have gain all the minimum knowledge on accessing the file I/O. Also, you get the idea how the final merge data file being structure. So, it is the big time for the core task of the entire project... building the merge data file. Before I start explain the most interesting part (program code) step by step, let recap some of the important step to build the merge data file.



NOTE:
In the following code snippet, I was filter out those code related to GUI update. These GUI update is mainly to keep the user inform about the status of the entire building self-extract executable file process. If you wish to get more about this GUI update code, you can always refer to the full source code enclosed together with this article.

Basically, the following code snippet will cover from step #1 and #4. Which is a do... while... loop to scan through the folder.

PHP Code:
// Get the current user define source folder
GetDlgItemText(hWndIDC_EDIT1szBuffer1sizeof(szBuffer1));

// Format the full path for the source folder
sprintf(szBuffer2,
        
"%s\\*.*",
        
szBuffer1);

// Start scaning the directory
hFile FindFirstFile(szBuffer2, &wfs);

// Check the return handle value
do
{
    
// Check is the current found file is directory?
    
if (!(FILE_ATTRIBUTE_DIRECTORY wfs.dwFileAttributes))
    {
        
// Save the information into data file
        
WriteSelfExtractHeader (hWnd, &wfs);
        
// Save the information into data file
        
WriteSelfExtractBinData (hWnd, &wfs);
    }

    
// Scan the next match item in the directory
    
if (!FindNextFile(hFile, &wfs))
    {
        if (
ERROR_NO_MORE_FILES == GetLastError()) {break;}
    }

} while (
NULL != hFile || INVALID_HANDLE_VALUE != hFile);

// Close the search handle
if (NULL != hFile) {FindClose(hFile);}
hFile NULL
Next block of code snippet will cover the reading & writing the file information into the header block. As well as the code for reading & writing the content of the current file.

NOTE:
The file size informatin is very important in the (SetupEx.exe) module, because this will be the key information that instruct the SetupEx.exe how much it should move the file pointer in order to get back to the original staring point of the each individual distributed file.

PHP Code:
void WriteSelfExtractHeader (HWND hWndLPWIN32_FIND_DATA lpFindFileData)
{
    
EXTRACTFILEINFO    efi = {NULL};
    
    
HANDLE    hFile        NULL;
    
DWORD     dwByteWrite  0;

    
__try
    
{
        
// Open the existing temporary data file
        
hFile CreateFile(szTmpBinFile1,
                           
GENERIC_WRITE,
                           
FILE_SHARE_WRITE,
                           
NULL,
                           
OPEN_EXISTING,
                           
FILE_ATTRIBUTE_NORMAL,
                           
NULL);

        
// Check the return handle value
        
if (NULL == hFile || INVALID_HANDLE_VALUE == hFile)
        {
            
// Open the existing temporary data file
            
hFile CreateFile(szTmpBinFile1,
                               
GENERIC_WRITE,
                               
FILE_SHARE_WRITE,
                               
NULL,
                               
CREATE_NEW,
                               
FILE_ATTRIBUTE_NORMAL,
                               
NULL);            
        }

        
// Check the return handle value
        
if (NULL != hFile && INVALID_HANDLE_VALUE != hFile)
        {
            
// Reset the local EXTRACTFILEINFO structure
            
ZeroMemory(&efisizeof(EXTRACTFILEINFO));

            
// Initialize the EXTRACTFILEINFO structure
            
efi.dwIndex dwFileCount;
            
CopyMemory(&efi.CreateTime,     &lpFindFileData->ftCreationTime,   sizeof(FILETIME));
            
CopyMemory(&efi.LastAcessTime,  &lpFindFileData->ftLastAccessTimesizeof(FILETIME));
            
CopyMemory(&efi.LastWriteTime,  &lpFindFileData->ftLastWriteTime,  sizeof(FILETIME));
            
CopyMemory(&efi.dwFileSizeHigh, &lpFindFileData->nFileSizeHigh ,   sizeof(DWORD));
            
CopyMemory(&efi.dwFileSizeLow,  &lpFindFileData->nFileSizeLow,     sizeof(DWORD));
            
CopyMemory(&efi.szBinFileName,  &lpFindFileData->cFileName,        strlen(lpFindFileData->cFileName));

            
// Check current file count & move the file pointer
            
if (== dwFileCount)
                
SetFilePointer(hFilesizeof(UPDATEINFO), 0FILE_BEGIN);
            else
                
SetFilePointer(hFile00FILE_END);

            
// Write the data into setup list file
            
WriteFile(hFile,
                      &
efi,
                      
sizeof(EXTRACTFILEINFO),
                      &
dwByteWrite,
                      
NULL);

            
// Increate the counter
            
dwFileCount++;
        }
    }
    
__except (EXCEPTION_EXECUTE_HANDLER)
    {
        
// PUT YOUR ERROR HANDLING CODE HERE

    
}

    
// Close the open file handle
    
if (NULL != hFile) {CloseHandle(hFile);}
    
hFile NULL;
}


void WriteSelfExtractBinData (HWND hWndLPWIN32_FIND_DATA lpFindFileData)
{
    
HANDLE    hFile         NULL;
    
LPBYTE    lpData        NULL;
    
DWORD     dwSize        0;
    
DWORD     dwByteRead    0;
    
DWORD     dwByteWrite   0;

    
char    szBuffer1[MAX_PATH] = {NULL};
    
char    szBuffer2[MAX_PATH] = {NULL};

    
__try
    
{
        
// Get the user define source folder
        
GetDlgItemText(hWndIDC_EDIT1szBuffer1sizeof(szBuffer1));
        
// Format the full file path
        
sprintf(szBuffer2
            
"%s\\%s",
            
szBuffer1lpFindFileData->cFileName); 
        
        
// STAGE #1
        // Read the current binary file data
        
hFile CreateFile(szBuffer2,
                           
GENERIC_READ,
                           
FILE_SHARE_READ,
                           
NULL,
                           
OPEN_EXISTING,
                           
FILE_ATTRIBUTE_NORMAL,
                           
NULL);
        
// Check the return handle value
        
if (NULL != hFile && INVALID_HANDLE_VALUE != hFile)
        {
            
// Get the current file size
            
dwSize = (lpFindFileData->nFileSizeHigh*(MAXDWORD+1)) + 
                      
lpFindFileData->nFileSizeLow;
            
// Allocate local data buffer
            
lpData = (LPBYTE)LocalAlloc(LPTRdwSize);
            
// Reset local data buffer
            
ZeroMemory(lpDatadwSize);
            
            
// Move the file pointer to the begining
            
SetFilePointer(hFile00FILE_BEGIN);
            
// Read the binary data
            
ReadFile(hFilelpDatadwSize, &dwByteReadNULL);
        }

        
// Close the open file handle
        
if (NULL != hFile) {CloseHandle(hFile);}
        
hFile NULL;


        
// STAGE #2
        // WRITE THE READ BINDARY DATA INTO THE TEMPORARY FILE
        // Open the existing setup data file (szTmpBinFile2)
        
hFile CreateFile(szTmpBinFile2,
                           
GENERIC_WRITE,
                           
FILE_SHARE_WRITE,
                           
NULL,
                           
OPEN_EXISTING,
                           
FILE_ATTRIBUTE_NORMAL,
                           
NULL);

        
// Check the return handle value
        
if (NULL == hFile || INVALID_HANDLE_VALUE == hFile)
        {
            
// Open the existing setup.lst data file
            
hFile CreateFile(szTmpBinFile2,
                               
GENERIC_WRITE,
                               
FILE_SHARE_WRITE,
                               
NULL,
                               
CREATE_NEW,
                               
FILE_ATTRIBUTE_NORMAL,
                               
NULL);            
        }

        
// Check the return handle value
        
if (NULL != hFile && INVALID_HANDLE_VALUE != hFile)
        {
            
// Move the file pointer
            
SetFilePointer(hFile00FILE_END);

            
// Write the data into setup list file
            
WriteFile(hFile,
                      
lpData,
                      
dwSize,
                      &
dwByteWrite,
                      
NULL);
        }
    }
    
__except (EXCEPTION_EXECUTE_HANDLER)
    {
        
// PUT YOUR ERROR HANDLING CODE HERE

    
}

    
// Release the allocated data buffer
    
if (NULL != lpData){LocalFree((LPBYTE)lpData);}
    
lpData NULL;

    
// Close the open file handle
    
if (NULL != hFile) {CloseHandle(hFile);}
    
hFile NULL;