mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 11:40:13 +01:00
1075 lines
27 KiB
C++
1075 lines
27 KiB
C++
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
* March 31, 1998.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Troy Chevalier <troy@netscape.com>
|
|
* Sean Su <ssu@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include <windows.h>
|
|
|
|
// stdlib.h and malloc.h are needed to build with WIN32_LEAN_AND_MEAN
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <ctype.h>
|
|
|
|
#include "resource.h"
|
|
#include "zlib.h"
|
|
|
|
#define BAR_MARGIN 1
|
|
#define BAR_SPACING 0
|
|
#define BAR_WIDTH 6
|
|
#define MAX_BUF 4096
|
|
|
|
/* Mode of Setup to run in */
|
|
#define NORMAL 0
|
|
#define SILENT 1
|
|
#define AUTO 2
|
|
|
|
/* PP: Parse Path */
|
|
#define PP_FILENAME_ONLY 1
|
|
#define PP_PATH_ONLY 2
|
|
#define PP_ROOT_ONLY 3
|
|
|
|
#define CLASS_NAME_SETUP "MozillaSetup"
|
|
#define CLASS_NAME_SETUP_DLG "MozillaSetupDlg"
|
|
|
|
char szTitle[MAX_BUF];
|
|
char szCmdLineToSetup[MAX_BUF];
|
|
BOOL gbUncompressOnly;
|
|
DWORD dwMode;
|
|
HINSTANCE hInst;
|
|
char gszWizTempDir[20] = "ns_temp";
|
|
char gszFileToUncompress[MAX_BUF];
|
|
BOOL gbAllowMultipleInstalls = FALSE;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Global Declarations
|
|
|
|
static DWORD nTotalBytes = 0; // sum of all the FILE resources
|
|
|
|
struct ExtractFilesDlgInfo {
|
|
HWND hWndDlg;
|
|
int nMaxBars; // maximum number of bars that can be displayed
|
|
int nBars; // current number of bars to display
|
|
} dlgInfo;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Utility Functions
|
|
|
|
// This function is similar to GetFullPathName except instead of
|
|
// using the current drive and directory it uses the path of the
|
|
// directory designated for temporary files
|
|
static BOOL
|
|
GetFullTempPathName(LPCTSTR lpszFileName, DWORD dwBufferLength, LPTSTR lpszBuffer)
|
|
{
|
|
DWORD dwLen;
|
|
|
|
dwLen = GetTempPath(dwBufferLength, lpszBuffer);
|
|
if (lpszBuffer[dwLen - 1] != '\\')
|
|
strcat(lpszBuffer, "\\");
|
|
strcat(lpszBuffer, gszWizTempDir);
|
|
|
|
dwLen = lstrlen(lpszBuffer);
|
|
if (lpszBuffer[dwLen - 1] != '\\')
|
|
strcat(lpszBuffer, "\\");
|
|
strcat(lpszBuffer, lpszFileName);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Function to remove quotes from a string */
|
|
void RemoveQuotes(LPSTR lpszSrc, LPSTR lpszDest, int iDestSize)
|
|
{
|
|
char *lpszBegin;
|
|
|
|
if(lstrlen(lpszSrc) > iDestSize)
|
|
return;
|
|
|
|
if(*lpszSrc == '\"')
|
|
lpszBegin = &lpszSrc[1];
|
|
else
|
|
lpszBegin = lpszSrc;
|
|
|
|
lstrcpy(lpszDest, lpszBegin);
|
|
|
|
if(lpszDest[lstrlen(lpszDest) - 1] == '\"')
|
|
lpszDest[lstrlen(lpszDest) - 1] = '\0';
|
|
}
|
|
|
|
/* Function to locate the first non space character in a string,
|
|
* and return a pointer to it. */
|
|
LPSTR GetFirstNonSpace(LPSTR lpszString)
|
|
{
|
|
int i;
|
|
int iStrLength;
|
|
|
|
iStrLength = lstrlen(lpszString);
|
|
|
|
for(i = 0; i < iStrLength; i++)
|
|
{
|
|
if(!isspace(lpszString[i]))
|
|
return(&lpszString[i]);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/* Function to return the argument count given a command line input
|
|
* format string */
|
|
int GetArgC(LPSTR lpszCommandLine)
|
|
{
|
|
int i;
|
|
int iArgCount;
|
|
int iStrLength;
|
|
LPSTR lpszBeginStr;
|
|
BOOL bFoundQuote;
|
|
BOOL bFoundSpace;
|
|
|
|
iArgCount = 0;
|
|
lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
|
|
|
|
if(lpszBeginStr == NULL)
|
|
return(iArgCount);
|
|
|
|
iStrLength = lstrlen(lpszBeginStr);
|
|
bFoundQuote = FALSE;
|
|
bFoundSpace = TRUE;
|
|
|
|
for(i = 0; i < iStrLength; i++)
|
|
{
|
|
if(lpszCommandLine[i] == '\"')
|
|
{
|
|
if(bFoundQuote == FALSE)
|
|
{
|
|
++iArgCount;
|
|
bFoundQuote = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bFoundQuote = FALSE;
|
|
}
|
|
}
|
|
else if(bFoundQuote == FALSE)
|
|
{
|
|
if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
|
|
{
|
|
++iArgCount;
|
|
bFoundSpace = FALSE;
|
|
}
|
|
else if(isspace(lpszCommandLine[i]))
|
|
{
|
|
bFoundSpace = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(iArgCount);
|
|
}
|
|
|
|
/* Function to return a specific argument parameter from a given command line input
|
|
* format string. */
|
|
LPSTR GetArgV(LPSTR lpszCommandLine, int iIndex, LPSTR lpszDest, int iDestSize)
|
|
{
|
|
int i;
|
|
int j;
|
|
int iArgCount;
|
|
int iStrLength;
|
|
LPSTR lpszBeginStr;
|
|
LPSTR lpszDestTemp;
|
|
BOOL bFoundQuote;
|
|
BOOL bFoundSpace;
|
|
|
|
iArgCount = 0;
|
|
lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
|
|
|
|
if(lpszDest)
|
|
*lpszDest = '\0';
|
|
if(lpszBeginStr == NULL)
|
|
return(NULL);
|
|
|
|
lpszDestTemp = (char *)calloc(iDestSize, sizeof(char));
|
|
if(lpszDestTemp == NULL)
|
|
{
|
|
MessageBox(NULL, "Out of memory", NULL, MB_OK | MB_ICONEXCLAMATION);
|
|
exit(1);
|
|
}
|
|
|
|
iStrLength = lstrlen(lpszBeginStr);
|
|
bFoundQuote = FALSE;
|
|
bFoundSpace = TRUE;
|
|
j = 0;
|
|
|
|
for(i = 0; i < iStrLength; i++)
|
|
{
|
|
if(lpszCommandLine[i] == '\"')
|
|
{
|
|
if(bFoundQuote == FALSE)
|
|
{
|
|
++iArgCount;
|
|
bFoundQuote = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bFoundQuote = FALSE;
|
|
}
|
|
}
|
|
else if(bFoundQuote == FALSE)
|
|
{
|
|
if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
|
|
{
|
|
++iArgCount;
|
|
bFoundSpace = FALSE;
|
|
}
|
|
else if(isspace(lpszCommandLine[i]))
|
|
{
|
|
bFoundSpace = TRUE;
|
|
}
|
|
}
|
|
|
|
if((iIndex == (iArgCount - 1)) &&
|
|
((bFoundQuote == TRUE) || (bFoundSpace == FALSE) ||
|
|
((bFoundQuote == FALSE) && (lpszCommandLine[i] == '\"'))))
|
|
{
|
|
if(j < iDestSize)
|
|
{
|
|
lpszDestTemp[j] = lpszCommandLine[i];
|
|
++j;
|
|
}
|
|
else
|
|
{
|
|
lpszDestTemp[j] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
RemoveQuotes(lpszDestTemp, lpszDest, iDestSize);
|
|
free(lpszDestTemp);
|
|
return(lpszDest);
|
|
}
|
|
|
|
// this function appends a backslash at the end of a string,
|
|
// if one does not already exists.
|
|
void AppendBackSlash(LPSTR szInput, DWORD dwInputSize)
|
|
{
|
|
if(szInput != NULL)
|
|
{
|
|
if(szInput[strlen(szInput) - 1] != '\\')
|
|
{
|
|
if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
|
|
{
|
|
lstrcat(szInput, "\\");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CreateDirectoriesAll(char* szPath)
|
|
{
|
|
int i;
|
|
int iLen = lstrlen(szPath);
|
|
char szCreatePath[MAX_BUF];
|
|
HRESULT hrResult;
|
|
|
|
ZeroMemory(szCreatePath, MAX_BUF);
|
|
memcpy(szCreatePath, szPath, iLen);
|
|
for(i = 0; i < iLen; i++)
|
|
{
|
|
if((iLen > 1) &&
|
|
((i != 0) && ((szPath[i] == '\\') || (szPath[i] == '/'))) &&
|
|
(!((szPath[0] == '\\') && (i == 1)) && !((szPath[1] == ':') && (i == 2))))
|
|
{
|
|
szCreatePath[i] = '\0';
|
|
hrResult = CreateDirectory(szCreatePath, NULL);
|
|
szCreatePath[i] = szPath[i];
|
|
}
|
|
}
|
|
return(hrResult);
|
|
}
|
|
|
|
// This function removes a directory and its subdirectories
|
|
HRESULT DirectoryRemove(LPSTR szDestination, BOOL bRemoveSubdirs)
|
|
{
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA fdFile;
|
|
char szDestTemp[MAX_BUF];
|
|
BOOL bFound;
|
|
|
|
if(GetFileAttributes(szDestination) == -1)
|
|
return(0);
|
|
|
|
if(bRemoveSubdirs == TRUE)
|
|
{
|
|
lstrcpy(szDestTemp, szDestination);
|
|
AppendBackSlash(szDestTemp, sizeof(szDestTemp));
|
|
lstrcat(szDestTemp, "*");
|
|
|
|
bFound = TRUE;
|
|
hFile = FindFirstFile(szDestTemp, &fdFile);
|
|
while((hFile != INVALID_HANDLE_VALUE) && (bFound == TRUE))
|
|
{
|
|
if((lstrcmpi(fdFile.cFileName, ".") != 0) && (lstrcmpi(fdFile.cFileName, "..") != 0))
|
|
{
|
|
/* create full path */
|
|
lstrcpy(szDestTemp, szDestination);
|
|
AppendBackSlash(szDestTemp, sizeof(szDestTemp));
|
|
lstrcat(szDestTemp, fdFile.cFileName);
|
|
|
|
if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
DirectoryRemove(szDestTemp, bRemoveSubdirs);
|
|
}
|
|
else
|
|
{
|
|
DeleteFile(szDestTemp);
|
|
}
|
|
}
|
|
|
|
bFound = FindNextFile(hFile, &fdFile);
|
|
}
|
|
|
|
FindClose(hFile);
|
|
}
|
|
|
|
RemoveDirectory(szDestination);
|
|
return(0);
|
|
}
|
|
|
|
void RemoveBackSlash(LPSTR szInput)
|
|
{
|
|
int iCounter;
|
|
DWORD dwInputLen;
|
|
|
|
if(szInput != NULL)
|
|
{
|
|
dwInputLen = lstrlen(szInput);
|
|
|
|
for(iCounter = dwInputLen -1; iCounter >= 0 ; iCounter--)
|
|
{
|
|
if(szInput[iCounter] == '\\')
|
|
szInput[iCounter] = '\0';
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParsePath(LPSTR szInput, LPSTR szOutput, DWORD dwOutputSize, DWORD dwType)
|
|
{
|
|
int iCounter;
|
|
DWORD dwCounter;
|
|
DWORD dwInputLen;
|
|
BOOL bFound;
|
|
|
|
if((szInput != NULL) && (szOutput != NULL))
|
|
{
|
|
bFound = TRUE;
|
|
dwInputLen = lstrlen(szInput);
|
|
ZeroMemory(szOutput, dwOutputSize);
|
|
|
|
if(dwInputLen < dwOutputSize)
|
|
{
|
|
switch(dwType)
|
|
{
|
|
case PP_FILENAME_ONLY:
|
|
for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
|
|
{
|
|
if(szInput[iCounter] == '\\')
|
|
{
|
|
lstrcpy(szOutput, &szInput[iCounter + 1]);
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(bFound == FALSE)
|
|
lstrcpy(szOutput, szInput);
|
|
|
|
break;
|
|
|
|
case PP_PATH_ONLY:
|
|
for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
|
|
{
|
|
if(szInput[iCounter] == '\\')
|
|
{
|
|
lstrcpy(szOutput, szInput);
|
|
szOutput[iCounter + 1] = '\0';
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(bFound == FALSE)
|
|
lstrcpy(szOutput, szInput);
|
|
|
|
break;
|
|
|
|
case PP_ROOT_ONLY:
|
|
if(szInput[1] == ':')
|
|
{
|
|
szOutput[0] = szInput[0];
|
|
szOutput[1] = szInput[1];
|
|
AppendBackSlash(szOutput, dwOutputSize);
|
|
}
|
|
else if(szInput[1] == '\\')
|
|
{
|
|
int iFoundBackSlash = 0;
|
|
for(dwCounter = 0; dwCounter < dwInputLen; dwCounter++)
|
|
{
|
|
if(szInput[dwCounter] == '\\')
|
|
{
|
|
szOutput[dwCounter] = szInput[dwCounter];
|
|
++iFoundBackSlash;
|
|
}
|
|
|
|
if(iFoundBackSlash == 3)
|
|
break;
|
|
}
|
|
|
|
if(iFoundBackSlash != 0)
|
|
AppendBackSlash(szOutput, dwOutputSize);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParseCommandLine(LPSTR lpszCmdLine)
|
|
{
|
|
char szArgVBuf[MAX_BUF];
|
|
int i;
|
|
int iArgC;
|
|
|
|
*szCmdLineToSetup = '\0';
|
|
*gszFileToUncompress = '\0';
|
|
dwMode = NORMAL;
|
|
gbUncompressOnly = FALSE;
|
|
iArgC = GetArgC(lpszCmdLine);
|
|
i = 0;
|
|
while(i < iArgC)
|
|
{
|
|
GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
|
|
if((lstrcmpi(szArgVBuf, "-ms") == 0) || (lstrcmpi(szArgVBuf, "/ms") == 0))
|
|
{
|
|
dwMode = SILENT;
|
|
}
|
|
else if((lstrcmpi(szArgVBuf, "-u") == 0) || (lstrcmpi(szArgVBuf, "/u") == 0))
|
|
{
|
|
gbUncompressOnly = TRUE;
|
|
GetArgV(lpszCmdLine, i + 1, szArgVBuf, sizeof(szArgVBuf));
|
|
if((*szArgVBuf != '\0') && (*szArgVBuf != '-'))
|
|
{
|
|
lstrcpy(gszFileToUncompress, szArgVBuf);
|
|
++i; // found filename to uncompress, update 'i' for the next iteration
|
|
}
|
|
}
|
|
else if((lstrcmpi(szArgVBuf, "-mmi") == 0) || (lstrcmpi(szArgVBuf, "/mmi") == 0))
|
|
{
|
|
gbAllowMultipleInstalls = TRUE;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
lstrcpy(szCmdLineToSetup, " ");
|
|
lstrcat(szCmdLineToSetup, lpszCmdLine);
|
|
}
|
|
|
|
// Centers the specified window over the desktop. Assumes the window is
|
|
// smaller both horizontally and vertically than the desktop
|
|
static void
|
|
CenterWindow(HWND hWndDlg)
|
|
{
|
|
RECT rect;
|
|
int iLeft, iTop;
|
|
|
|
GetWindowRect(hWndDlg, &rect);
|
|
iLeft = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
|
|
iTop = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
|
|
|
|
SetWindowPos(hWndDlg, NULL, iLeft, iTop, -1, -1,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Extract Files Dialog
|
|
|
|
// This routine processes windows messages that are in queue
|
|
void ProcessWindowsMessages()
|
|
{
|
|
MSG msg;
|
|
|
|
while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
// This routine updates the status string in the extracting dialog
|
|
static void
|
|
SetStatusLine(LPCTSTR lpszStatus)
|
|
{
|
|
HWND hWndLabel;
|
|
|
|
if(dwMode != SILENT)
|
|
{
|
|
hWndLabel = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS);
|
|
SetWindowText(hWndLabel, lpszStatus);
|
|
UpdateWindow(hWndLabel);
|
|
}
|
|
}
|
|
|
|
// This routine will update the progress bar to the specified percentage
|
|
// (value between 0 and 100)
|
|
static void
|
|
UpdateProgressBar(unsigned value)
|
|
{
|
|
int nBars;
|
|
|
|
if(dwMode != SILENT)
|
|
{
|
|
// Figure out how many bars should be displayed
|
|
nBars = dlgInfo.nMaxBars * value / 100;
|
|
|
|
// Only paint if we need to display more bars
|
|
if (nBars > dlgInfo.nBars)
|
|
{
|
|
HWND hWndGauge = GetDlgItem(dlgInfo.hWndDlg, IDC_GAUGE);
|
|
RECT rect;
|
|
|
|
// Update the gauge state before painting
|
|
dlgInfo.nBars = nBars;
|
|
|
|
// Only invalidate the part that needs updating
|
|
GetClientRect(hWndGauge, &rect);
|
|
InvalidateRect(hWndGauge, &rect, FALSE);
|
|
|
|
// Update the whole extracting dialog. We do this because we don't
|
|
// have a message loop to process WM_PAINT messages in case the
|
|
// extracting dialog was exposed
|
|
UpdateWindow(dlgInfo.hWndDlg);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Window proc for dialog
|
|
BOOL APIENTRY
|
|
DialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(dwMode != SILENT)
|
|
{
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
// Center the dialog over the desktop
|
|
CenterWindow(hWndDlg);
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
DestroyWindow(hWndDlg);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE; // didn't handle the message
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Resource Callback Functions
|
|
|
|
BOOL APIENTRY
|
|
DeleteTempFilesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
|
|
{
|
|
char szTmpFile[MAX_PATH];
|
|
|
|
// Get the path to the file in the temp directory
|
|
GetFullTempPathName(lpszName, sizeof(szTmpFile), szTmpFile);
|
|
|
|
// Delete the file
|
|
DeleteFile(szTmpFile);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
SizeOfResourcesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
|
|
{
|
|
HRSRC hResInfo;
|
|
|
|
// Find the resource
|
|
hResInfo = FindResource((HINSTANCE)hModule, lpszName, lpszType);
|
|
|
|
#ifdef _DEBUG
|
|
if (!hResInfo) {
|
|
char buf[512];
|
|
|
|
wsprintf(buf, "Error '%d' when loading FILE resource: %s", GetLastError(), lpszName);
|
|
MessageBox(NULL, buf, szTitle, MB_OK | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
// Add its size to the total size. Note that the return value is subject
|
|
// to alignment rounding, but it's close enough for our purposes
|
|
nTotalBytes += SizeofResource(NULL, hResInfo);
|
|
|
|
// Release the resource
|
|
FreeResource(hResInfo);
|
|
return TRUE; // keep enumerating
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
ExtractFilesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
|
|
{
|
|
char szTmpFile[MAX_PATH];
|
|
char szArcLstFile[MAX_PATH];
|
|
HRSRC hResInfo;
|
|
HGLOBAL hGlobal;
|
|
LPBYTE lpBytes;
|
|
LPBYTE lptr;
|
|
LPBYTE lpBytesUnCmp;
|
|
HANDLE hFile;
|
|
char szStatus[128];
|
|
char szText[4096];
|
|
|
|
// Update the UI
|
|
LoadString(hInst, IDS_STATUS_EXTRACTING, szText, sizeof(szText));
|
|
wsprintf(szStatus, szText, lpszName);
|
|
SetStatusLine(szStatus);
|
|
|
|
if(gbUncompressOnly == TRUE)
|
|
lstrcpy(szTmpFile, lpszName);
|
|
else
|
|
{
|
|
// Create a file in the temp directory
|
|
GetFullTempPathName(lpszName, sizeof(szTmpFile), szTmpFile);
|
|
CreateDirectoriesAll(szTmpFile);
|
|
}
|
|
|
|
if((*gszFileToUncompress != '\0') && (lstrcmpi(lpszName, gszFileToUncompress) != 0))
|
|
// We have a file to uncompress, but the one found is not the one we want,
|
|
// so return TRUE to continue looking for the right one.
|
|
return TRUE;
|
|
|
|
// Extract the file
|
|
hResInfo = FindResource((HINSTANCE)hModule, lpszName, lpszType);
|
|
hGlobal = LoadResource((HINSTANCE)hModule, hResInfo);
|
|
lpBytes = (LPBYTE)LockResource(hGlobal);
|
|
|
|
// Create the file
|
|
hFile = CreateFile(szTmpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
DWORD dwSize;
|
|
DWORD dwSizeUnCmp;
|
|
DWORD dwTemp;
|
|
|
|
GetFullTempPathName("Archive.lst", sizeof(szArcLstFile), szArcLstFile);
|
|
WritePrivateProfileString("Archives", lpszName, "TRUE", szArcLstFile);
|
|
|
|
lptr = (LPBYTE)malloc((*(LPDWORD)(lpBytes + sizeof(DWORD))) + 1);
|
|
if(!lptr)
|
|
{
|
|
char szBuf[512];
|
|
|
|
LoadString(hInst, IDS_ERROR_OUT_OF_MEMORY, szBuf, sizeof(szBuf));
|
|
MessageBox(NULL, szBuf, NULL, MB_OK | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
|
|
lpBytesUnCmp = lptr;
|
|
dwSizeUnCmp = *(LPDWORD)(lpBytes + sizeof(DWORD));
|
|
|
|
// Copy the file. The first DWORD specifies the size of the file
|
|
dwSize = *(LPDWORD)lpBytes;
|
|
lpBytes += (sizeof(DWORD) * 2);
|
|
|
|
dwTemp = uncompress(lpBytesUnCmp, &dwSizeUnCmp, lpBytes, dwSize);
|
|
|
|
while (dwSizeUnCmp > 0)
|
|
{
|
|
DWORD dwBytesToWrite, dwBytesWritten;
|
|
|
|
ProcessWindowsMessages();
|
|
|
|
dwBytesToWrite = dwSizeUnCmp > 4096 ? 4096 : dwSizeUnCmp;
|
|
if (!WriteFile(hFile, lpBytesUnCmp, dwBytesToWrite, &dwBytesWritten, NULL))
|
|
{
|
|
char szBuf[512];
|
|
|
|
LoadString(hInst, IDS_STATUS_EXTRACTING, szText, sizeof(szText));
|
|
wsprintf(szBuf, szText, szTmpFile);
|
|
MessageBox(NULL, szBuf, szTitle, MB_OK | MB_ICONEXCLAMATION);
|
|
FreeResource(hResInfo);
|
|
if(lptr)
|
|
free(lptr);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
dwSizeUnCmp -= dwBytesWritten;
|
|
lpBytesUnCmp += dwBytesWritten;
|
|
|
|
// Update the UI to reflect the total number of bytes written
|
|
static DWORD nBytesWritten = 0;
|
|
|
|
nBytesWritten += dwBytesWritten;
|
|
UpdateProgressBar(nBytesWritten * 100 / nTotalBytes);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
// Release the resource
|
|
FreeResource(hResInfo);
|
|
if(lptr)
|
|
free(lptr);
|
|
|
|
if((*gszFileToUncompress != '\0') && (lstrcmpi(lpszName, gszFileToUncompress) == 0))
|
|
// We have a file to uncompress, and we have uncompressed it,
|
|
// so return FALSE to stop uncompressing any other file.
|
|
return FALSE;
|
|
|
|
return TRUE; // keep enumerating
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Progress bar
|
|
|
|
// Draws a recessed border around the gauge
|
|
static void
|
|
DrawGaugeBorder(HWND hWnd)
|
|
{
|
|
HDC hDC = GetWindowDC(hWnd);
|
|
RECT rect;
|
|
int cx, cy;
|
|
HPEN hShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
|
HGDIOBJ hOldPen;
|
|
|
|
GetWindowRect(hWnd, &rect);
|
|
cx = rect.right - rect.left;
|
|
cy = rect.bottom - rect.top;
|
|
|
|
// Draw a dark gray line segment
|
|
hOldPen = SelectObject(hDC, (HGDIOBJ)hShadowPen);
|
|
MoveToEx(hDC, 0, cy - 1, NULL);
|
|
LineTo(hDC, 0, 0);
|
|
LineTo(hDC, cx - 1, 0);
|
|
|
|
// Draw a white line segment
|
|
SelectObject(hDC, GetStockObject(WHITE_PEN));
|
|
MoveToEx(hDC, 0, cy - 1, NULL);
|
|
LineTo(hDC, cx - 1, cy - 1);
|
|
LineTo(hDC, cx - 1, 0);
|
|
|
|
SelectObject(hDC, hOldPen);
|
|
DeleteObject(hShadowPen);
|
|
ReleaseDC(hWnd, hDC);
|
|
}
|
|
|
|
// Draws the progress bar
|
|
static void
|
|
DrawProgressBar(HWND hWnd)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC = BeginPaint(hWnd, &ps);
|
|
RECT rect;
|
|
HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
|
|
|
|
// Draw the bars
|
|
GetClientRect(hWnd, &rect);
|
|
rect.left = rect.top = BAR_MARGIN;
|
|
rect.bottom -= BAR_MARGIN;
|
|
rect.right = rect.left + BAR_WIDTH;
|
|
|
|
for (int i = 0; i < dlgInfo.nBars; i++) {
|
|
RECT dest;
|
|
|
|
if (IntersectRect(&dest, &ps.rcPaint, &rect))
|
|
FillRect(hDC, &rect, hBrush);
|
|
OffsetRect(&rect, BAR_WIDTH + BAR_SPACING, 0);
|
|
}
|
|
|
|
DeleteObject(hBrush);
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
|
|
// Adjusts the width of the gauge based on the maximum number of bars
|
|
static void
|
|
SizeToFitGauge(HWND hWnd)
|
|
{
|
|
RECT rect;
|
|
int cx;
|
|
|
|
// Get the window size in pixels
|
|
GetWindowRect(hWnd, &rect);
|
|
|
|
// Size the width to fit
|
|
cx = 2 * GetSystemMetrics(SM_CXBORDER) + 2 * BAR_MARGIN +
|
|
dlgInfo.nMaxBars * BAR_WIDTH + (dlgInfo.nMaxBars - 1) * BAR_SPACING;
|
|
|
|
SetWindowPos(hWnd, NULL, -1, -1, cx, rect.bottom - rect.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
// Window proc for gauge
|
|
LRESULT APIENTRY
|
|
GaugeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DWORD dwStyle;
|
|
RECT rect;
|
|
|
|
switch (msg) {
|
|
case WM_NCCREATE:
|
|
dwStyle = GetWindowLong(hWnd, GWL_STYLE);
|
|
SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_BORDER);
|
|
return TRUE;
|
|
|
|
case WM_CREATE:
|
|
// Figure out the maximum number of bars that can be displayed
|
|
GetClientRect(hWnd, &rect);
|
|
dlgInfo.nBars = 0;
|
|
dlgInfo.nMaxBars = (rect.right - rect.left - 2 * BAR_MARGIN + BAR_SPACING) /
|
|
(BAR_WIDTH + BAR_SPACING);
|
|
|
|
// Size the gauge to exactly fit the maximum number of bars
|
|
SizeToFitGauge(hWnd);
|
|
return TRUE;
|
|
|
|
case WM_NCPAINT:
|
|
DrawGaugeBorder(hWnd);
|
|
return TRUE;
|
|
|
|
case WM_PAINT:
|
|
DrawProgressBar(hWnd);
|
|
return TRUE;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
HRESULT FileExists(LPSTR szFile)
|
|
{
|
|
DWORD rv;
|
|
|
|
if((rv = GetFileAttributes(szFile)) == -1)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
return(rv);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// WinMain
|
|
|
|
static BOOL
|
|
RunInstaller()
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO sti;
|
|
char szCmdLine[MAX_BUF];
|
|
char szSetupFile[MAX_BUF];
|
|
char szUninstallFile[MAX_BUF];
|
|
char szArcLstFile[MAX_BUF];
|
|
BOOL bRet;
|
|
char szText[256];
|
|
char szTempPath[MAX_BUF];
|
|
char szTmp[MAX_PATH];
|
|
char xpiDir[MAX_PATH];
|
|
char szFilename[MAX_BUF];
|
|
char szBuf[MAX_BUF];
|
|
|
|
if(gbUncompressOnly == TRUE)
|
|
return(TRUE);
|
|
|
|
// Update UI
|
|
UpdateProgressBar(100);
|
|
LoadString(hInst, IDS_STATUS_LAUNCHING_SETUP, szText, sizeof(szText));
|
|
SetStatusLine(szText);
|
|
|
|
memset(&sti,0,sizeof(sti));
|
|
sti.cb = sizeof(STARTUPINFO);
|
|
|
|
// Setup program is in the directory specified for temporary files
|
|
GetFullTempPathName("", MAX_BUF, szTempPath);
|
|
GetFullTempPathName("Archive.lst", sizeof(szArcLstFile), szArcLstFile);
|
|
GetFullTempPathName("SETUP.EXE", sizeof(szSetupFile), szSetupFile);
|
|
GetFullTempPathName("uninstall.exe", sizeof(szUninstallFile), szUninstallFile);
|
|
|
|
GetPrivateProfileString("Archives", "uninstall.exe", "", szBuf, sizeof(szBuf), szArcLstFile);
|
|
if((FileExists(szUninstallFile) != FALSE) && (*szBuf != '\0'))
|
|
{
|
|
lstrcpy(szCmdLine, szUninstallFile);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(szCmdLine, szSetupFile);
|
|
GetModuleFileName(NULL, szFilename, sizeof(szFilename));
|
|
ParsePath(szFilename, xpiDir, sizeof(xpiDir), PP_PATH_ONLY);
|
|
AppendBackSlash(xpiDir, sizeof(xpiDir));
|
|
lstrcat(xpiDir, "xpi");
|
|
if(FileExists(xpiDir))
|
|
{
|
|
GetShortPathName(xpiDir, szBuf, sizeof(szBuf));
|
|
lstrcat(szCmdLine, " -a ");
|
|
lstrcat(szCmdLine, szBuf);
|
|
}
|
|
lstrcat(szCmdLine, " -n ");
|
|
lstrcat(szCmdLine, szFilename);
|
|
}
|
|
|
|
if(szCmdLine != NULL)
|
|
lstrcat(szCmdLine, szCmdLineToSetup);
|
|
|
|
// Launch the installer
|
|
bRet = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, szTempPath, &sti, &pi);
|
|
|
|
if (!bRet)
|
|
return FALSE;
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
// Wait for the InstallShield UI to appear before taking down the dialog box
|
|
WaitForInputIdle(pi.hProcess, 3000); // wait up to 3 seconds
|
|
if(dwMode != SILENT)
|
|
{
|
|
DestroyWindow(dlgInfo.hWndDlg);
|
|
}
|
|
|
|
// Wait for the installer to complete
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
|
|
// Delete the files from the temp directory
|
|
EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)DeleteTempFilesProc, 0);
|
|
|
|
// delete archive.lst file in the temp directory
|
|
GetFullTempPathName("Archive.lst", sizeof(szTmp), szTmp);
|
|
DeleteFile(szTmp);
|
|
GetFullTempPathName("xpcom.ns", sizeof(szTmp), szTmp);
|
|
DirectoryRemove(szTmp, TRUE);
|
|
DirectoryRemove(szTempPath, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
int APIENTRY
|
|
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
WNDCLASS wc;
|
|
HWND hwndFW;
|
|
|
|
hInst = hInstance;
|
|
LoadString(hInst, IDS_TITLE, szTitle, MAX_BUF);
|
|
|
|
// Parse the command line
|
|
ParseCommandLine(lpCmdLine);
|
|
|
|
/* Allow multiple installer instances with the
|
|
provision that each instance is guaranteed
|
|
to have its own unique setup directory
|
|
*/
|
|
if(FindWindow("NSExtracting", "Extracting...") != NULL ||
|
|
(hwndFW = FindWindow(CLASS_NAME_SETUP_DLG, NULL)) != NULL ||
|
|
(hwndFW = FindWindow(CLASS_NAME_SETUP, NULL)) != NULL)
|
|
{
|
|
if (gbAllowMultipleInstalls)
|
|
{
|
|
char szTempPath[MAX_BUF];
|
|
GetFullTempPathName("", MAX_BUF, szTempPath);
|
|
DWORD dwLen = lstrlen(gszWizTempDir);
|
|
|
|
for(int i = 1; i <= 100 && (FileExists(szTempPath) != FALSE); i++)
|
|
{
|
|
itoa(i, (gszWizTempDir + dwLen), 10);
|
|
GetFullTempPathName("", MAX_BUF, szTempPath);
|
|
}
|
|
|
|
if (FileExists(szTempPath) != FALSE)
|
|
{
|
|
MessageBox(NULL, "Cannot create temp directory", NULL, MB_OK | MB_ICONEXCLAMATION);
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hwndFW!=NULL)
|
|
{
|
|
ShowWindow(hwndFW, SW_RESTORE);
|
|
SetForegroundWindow(hwndFW);
|
|
}
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
// Figure out the total size of the resources
|
|
EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)SizeOfResourcesProc, 0);
|
|
|
|
// Register a class for the gauge
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.lpfnWndProc = (WNDPROC)GaugeWndProc;
|
|
wc.hInstance = hInstance;
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
|
wc.lpszClassName = "NSGauge";
|
|
RegisterClass(&wc);
|
|
|
|
// Register a class for the main dialog
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
|
|
wc.lpfnWndProc = DefDlgProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = DLGWINDOWEXTRA;
|
|
wc.hInstance = hInstance;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.lpszClassName = "NSExtracting";
|
|
RegisterClass(&wc);
|
|
|
|
if(dwMode != SILENT)
|
|
{
|
|
// Display the dialog box
|
|
dlgInfo.hWndDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_EXTRACTING), NULL, (DLGPROC)DialogProc);
|
|
UpdateWindow(dlgInfo.hWndDlg);
|
|
}
|
|
|
|
// Extract the files
|
|
EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)ExtractFilesProc, 0);
|
|
|
|
// Launch the install program and wait for it to finish
|
|
RunInstaller();
|
|
return 0;
|
|
}
|