|
|
#include <windows.h>
#include <regstr.h>
#include <shellapi.h>
#include "cdinst.h"
#include "resource.h"
// global variables
HINSTANCE g_hInst; CHAR g_szTitle[128]; CHAR g_szSrcDir[MAX_PATH], g_szDstDir[MAX_PATH];
int _stdcall ModuleEntry(void) { int i; STARTUPINFO si; LPSTR pszCmdLine = GetCommandLine();
if ( *pszCmdLine == '\"' ) { /*
* Scan, and skip over, subsequent characters until * another double-quote or a null is encountered. */ while ( *++pszCmdLine && (*pszCmdLine != '\"') ) ; /*
* If we stopped on a double-quote (usual case), skip * over it. */ if ( *pszCmdLine == '\"' ) pszCmdLine++; } else { while (*pszCmdLine > ' ') pszCmdLine++; }
/*
* Skip past any white space preceeding the second token. */ while (*pszCmdLine && (*pszCmdLine <= ' ')) { pszCmdLine++; }
si.dwFlags = 0; GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine, si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT); ExitProcess(i); return i; // We never comes here.
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, INT iCmdShow) { BOOL bIniCopiedToTemp = FALSE; CHAR szIniFile[MAX_PATH], szSrcDir[MAX_PATH], szDstDir[MAX_PATH]; LPSTR pszSection, pszPtr, pszLine, pszFile, pszSrcSubDir, pszDstSubDir; DWORD dwLen, dwSpaceReq, dwSpaceFree;
g_hInst = hInstance;
LoadString(g_hInst, IDS_TITLE, g_szTitle, sizeof(g_szTitle));
ParseCmdLine(pszCmdLine);
if (*g_szSrcDir == '\0') { if (GetModuleFileName(g_hInst, g_szSrcDir, sizeof(g_szSrcDir))) if ((pszPtr = ANSIStrRChr(g_szSrcDir, '\\')) != NULL) *pszPtr = '\0';
if (*g_szSrcDir == '\0') { ErrorMsg(IDS_SRCDIR_NOT_FOUND); return -1; } }
if (*g_szDstDir == '\0') { HKEY hk;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_APPPATHS "\\ieak6wiz.exe", 0, KEY_READ, &hk) == ERROR_SUCCESS) { dwLen = sizeof(g_szDstDir);
RegQueryValueEx(hk, "Path", NULL, NULL, (LPBYTE) g_szDstDir, &dwLen); RegCloseKey(hk); }
if (*g_szDstDir == '\0') { ErrorMsg(IDS_DESTDIR_NOT_FOUND); return -1; } }
// look for cdinst.ini in the dir where the parent module (ieak6cd.exe) is running from
*szIniFile = '\0'; lstrcpy(szIniFile, g_szSrcDir); AddPath(szIniFile, "cdinst.ini"); if (!FileExists(szIniFile)) { // not found where ieak6cd.exe is running from; so look for it in the dir where the current
// module (cdinst.exe) is running from
*szIniFile = '\0'; if (GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile))) { if ((pszPtr = ANSIStrRChr(szIniFile, '\\')) != NULL) *pszPtr = '\0'; AddPath(szIniFile, "cdinst.ini"); }
if (!FileExists(szIniFile)) { *szIniFile = '\0'; GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile)); ErrorMsg(IDS_INI_NOT_FOUND, g_szSrcDir, szIniFile); return -1; } }
// copy cdinst.ini to the temp dir -- need to do this because on Win95, if cdinst.ini
// is at the same location as ieak6cd.exe on a read-only media (like CD), then
// GetPrivateProfileSection() calls would fail.
// NOTE: szSrcDir and szDstDir are used as temp variables below
if (GetTempPath(sizeof(szSrcDir), szSrcDir)) if (GetTempFileName(szSrcDir, "cdinst", 0, szDstDir)) if (CopyFile(szIniFile, szDstDir, FALSE)) { bIniCopiedToTemp = TRUE; lstrcpy(szIniFile, szDstDir); SetFileAttributes(szIniFile, FILE_ATTRIBUTE_NORMAL); }
// NOTE: If the destination dir is a UNC path, GetFreeDiskSpace() won't return the right value on Win95 Gold.
// So we turn off disk space checking if installing to a UNC path.
while (!EnoughDiskSpace(g_szSrcDir, g_szDstDir, szIniFile, &dwSpaceReq, &dwSpaceFree)) { if (ErrorMsg(IDS_NOT_ENOUGH_DISK_SPACE, dwSpaceReq, dwSpaceFree) == IDNO) return -1; }
// copy files that are specified in the [copy] section
// format of a line in the [copy] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <src sub dir (can be a relative path) - optional>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Copy", &pszSection, &dwLen, szIniFile)) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir); GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile); GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile); CopyFiles(szSrcDir, pszFile, szDstDir, FALSE); } } if (pszSection != NULL) LocalFree(pszSection);
// delete files that are specified in the [exclude] section from the destination dir
// format of a line in the [exclude] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Exclude", &pszSection, &dwLen, szIniFile)) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, NULL, &pszDstSubDir); GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile); DelFiles(pszFile, szDstDir); } } if (pszSection != NULL) LocalFree(pszSection);
// extract all the files from cabs that are specified in the [extract] section
// format of a line in the [extract] section is (all the fields should be on one line):
// <cab file (can contain wildcards)>,
// <src sub dir (can be a relative path) - optional>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Extract", &pszSection, &dwLen, szIniFile)) { HINSTANCE hAdvpack;
if ((hAdvpack = LoadLibrary("advpack.dll")) != NULL) { EXTRACTFILES pfnExtractFiles;
if ((pfnExtractFiles = (EXTRACTFILES) GetProcAddress(hAdvpack, "ExtractFiles")) != NULL) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir); GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile); GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile); ExtractFiles(szSrcDir, pszFile, szDstDir, pfnExtractFiles); } }
FreeLibrary(hAdvpack); } } if (pszSection != NULL) LocalFree(pszSection);
// move files that are specified in the [move] section from a subdir to another subdir under the destination dir
// format of a line in the [move] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <from sub dir under the dest dir (can be a relative path) - optional>,
// <to sub dir under the dest dir (can be a relative path) - optional>
if (ReadSectionFromInf("Move", &pszSection, &dwLen, szIniFile)) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir); GetDirPath(g_szDstDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile); GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile); MoveFiles(szSrcDir, pszFile, szDstDir); } } if (pszSection != NULL) LocalFree(pszSection);
if (bIniCopiedToTemp) DeleteFile(szIniFile);
return 0; }
BOOL EnoughDiskSpace(LPCSTR pcszSrcRootDir, LPCSTR pcszDstRootDir, LPCSTR pcszIniFile, LPDWORD pdwSpaceReq, LPDWORD pdwSpaceFree) // check if there is enough free disk space to copy all the files
{ DWORD dwSpaceReq = 0, dwSpaceFree; CHAR szSrcDir[MAX_PATH], szDstDir[MAX_PATH]; LPSTR pszSection, pszLine, pszFile, pszSrcSubDir, pszDstSubDir; DWORD dwLen, dwFlags;
if (!GetFreeDiskSpace(pcszDstRootDir, &dwSpaceFree, &dwFlags)) { // if we can't get FreeDiskSpace info, then turn off disk space checking
return TRUE; }
// total space required =
// size of all the files to be copied +
// 2 * size of all the files to be extracted
if (ReadSectionFromInf("Copy", &pszSection, &dwLen, pcszIniFile)) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir); GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile); GetDirPath(pcszDstRootDir, pszDstSubDir, szDstDir, sizeof(szDstDir), pcszIniFile);
dwSpaceReq += FindSpaceRequired(szSrcDir, pszFile, szDstDir); } } if (pszSection != NULL) LocalFree(pszSection);
if (ReadSectionFromInf("Extract", &pszSection, &dwLen, pcszIniFile)) { for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1) { ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, NULL); GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile);
dwSpaceReq += 2 * FindSpaceRequired(szSrcDir, pszFile, NULL); } } if (pszSection != NULL) LocalFree(pszSection);
dwSpaceReq += 1024; // 1MB buffer to account for random stuff
if (dwFlags & FS_VOL_IS_COMPRESSED) { // if the destination volume is compressed, the free space returned is only
// a guesstimate; for example, if it's a DoubleSpace volume, the system thinks
// that it can compress by 50% and so it reports the free space as (actual free space * 2)
// it's better to be safe when dealing with compressed volumes; so bump up the space
// requirement by a factor 2
dwSpaceReq <<= 1; // multiply by 2
}
if (pdwSpaceReq != NULL) *pdwSpaceReq = dwSpaceReq;
if (pdwSpaceFree != NULL) *pdwSpaceFree = dwSpaceFree;
return dwSpaceFree > dwSpaceReq; }
BOOL GetFreeDiskSpace(LPCSTR pcszDir, LPDWORD pdwFreeSpace, LPDWORD pdwFlags) // Return the free disk space (in KBytes) in *pdwFreeSpace
{ BOOL bRet = FALSE; DWORD dwFreeSpace = 0; DWORD nSectorsPerCluster, nBytesPerSector, nFreeClusters, nTotalClusters; CHAR szDrive[8];
if (pcszDir == NULL || *pcszDir == '\0' || *(pcszDir + 1) != ':') return FALSE;
if (pdwFreeSpace == NULL) return FALSE;
lstrcpyn(szDrive, pcszDir, 3); AddPath(szDrive, NULL); if (GetDiskFreeSpace(szDrive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)) { // convert size to KBytes; assumption here is that the free space doesn't exceed 4096 gigs
if ((*pdwFreeSpace = MulDiv(nFreeClusters, nSectorsPerCluster * nBytesPerSector, 1024)) != (DWORD) -1) { bRet = TRUE;
if (pdwFlags != NULL) { *pdwFlags = 0; GetVolumeInformation(szDrive, NULL, 0, NULL, NULL, pdwFlags, NULL, 0); } } }
return bRet; }
DWORD FindSpaceRequired(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir) // Return the difference in size (in KBytes) of pcszFile (can contain wildcards)
// under pcszSrcDir and pcszDstDir (if specified)
{ DWORD dwSizeReq = 0; CHAR szSrcFile[MAX_PATH], szDstFile[MAX_PATH]; LPSTR pszSrcPtr, pszDstPtr; WIN32_FIND_DATA fileData; HANDLE hFindFile;
lstrcpy(szSrcFile, pcszSrcDir); AddPath(szSrcFile, NULL); pszSrcPtr = szSrcFile + lstrlen(szSrcFile);
if (pcszDstDir != NULL) { lstrcpy(szDstFile, pcszDstDir); AddPath(szDstFile, NULL); pszDstPtr = szDstFile + lstrlen(szDstFile); }
lstrcpy(pszSrcPtr, pcszFile); if ((hFindFile = FindFirstFile(szSrcFile, &fileData)) != INVALID_HANDLE_VALUE) { do { if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { DWORD dwSrcSize, dwDstSize;
// assumption here is that the size of the file doesn't exceed 4 gigs
dwSrcSize = fileData.nFileSizeLow; dwDstSize = 0;
if (pcszDstDir != NULL) { lstrcpy(pszDstPtr, fileData.cFileName); dwDstSize = FileSize(szDstFile); }
if (dwSrcSize >= dwDstSize) { // divide the difference by 1024 (we are interested in KBytes)
dwSizeReq += ((dwSrcSize - dwDstSize) >> 10); if (dwSrcSize > dwDstSize) dwSizeReq++; // increment by 1 to promote any fraction to a whole number
} } } while (FindNextFile(hFindFile, &fileData));
FindClose(hFindFile); }
return dwSizeReq; }
VOID ParseIniLine(LPSTR pszLine, LPSTR *ppszFile, LPSTR *ppszSrcDir, LPSTR *ppszDstDir) { if (ppszFile != NULL) *ppszFile = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES)); if (ppszSrcDir != NULL) *ppszSrcDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES)); if (ppszDstDir != NULL) *ppszDstDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES)); }
LPSTR GetDirPath(LPCSTR pcszRootDir, LPCSTR pcszSubDir, CHAR szDirPath[], DWORD cchBuffer, LPCSTR pcszIniFile) { *szDirPath = '\0';
if (pcszRootDir == NULL) return NULL;
lstrcpyn(szDirPath, pcszRootDir, cchBuffer); if (pcszSubDir != NULL && *pcszSubDir) { CHAR szTemp[MAX_PATH];
// if there are any placeholders in pcszSubDir (%en%, etc), ReplacePlaceholders will replace
// them with the actual strings
if (ReplacePlaceholders(pcszSubDir, pcszIniFile, szTemp, sizeof(szTemp))) { if ((DWORD) lstrlen(szDirPath) + 1 < cchBuffer) // there is room for '\\' which AddPath
// might append to szDirPath (see below)
{ INT iLen;
AddPath(szDirPath, NULL); // we have enough room in szDirPath for '\\'
if (cchBuffer > (DWORD) (iLen = lstrlen(szDirPath))) lstrcpyn(szDirPath + iLen, szTemp, cchBuffer - iLen); } } }
return szDirPath; }
DWORD ReplacePlaceholders(LPCSTR pszSrc, LPCSTR pszIns, LPSTR pszBuffer, DWORD cchBuffer) { LPCSTR pszAux; CHAR szResult[MAX_PATH]; UINT nDestPos, nLeftPos;
nDestPos = 0; nLeftPos = (UINT) -1;
for (pszAux = pszSrc; *pszAux; pszAux = CharNext(pszAux)) { if (*pszAux != '%') { szResult[nDestPos++] = *pszAux;
if (IsDBCSLeadByte(*pszAux)) szResult[nDestPos++] = *(pszAux + 1); // copy the trail byte as well
} else if (*(pszAux + 1) == '%') // "%%" is just '%' in the string
{ if (nLeftPos != (UINT) -1) // REVIEW: (andrewgu) "%%" are not allowed inside tokens. this also means that
// tokens can't be like %foo%%bar%, where the intention is for foo and bar to
// be tokens.
return 0;
szResult[nDestPos++] = *pszAux++; } else { UINT nRightPos;
nRightPos = (UINT) (pszAux - pszSrc); // initialized, but not necessarily used as such
if (nLeftPos == (UINT) -1) nLeftPos = nRightPos; else { CHAR szAux1[MAX_PATH], szAux2[MAX_PATH]; DWORD dwLen; UINT nTokenLen;
// "%%" is invalid here
nTokenLen = nRightPos - nLeftPos - 1;
lstrcpyn(szAux1, pszSrc + nLeftPos + 1, nTokenLen + 1);
if ((dwLen = GetPrivateProfileString("Strings", szAux1, "", szAux2, sizeof(szAux2), pszIns))) { lstrcpy(&szResult[nDestPos - nTokenLen], szAux2); nDestPos += dwLen - nTokenLen; }
nLeftPos = (UINT) -1; } } }
if (nLeftPos != (UINT) -1) // mismatched '%'
return 0;
if (cchBuffer <= nDestPos) // insufficient buffer size
return 0;
szResult[nDestPos] = '\0'; // make sure zero terminated
lstrcpy(pszBuffer, szResult);
return nDestPos; }
VOID SetAttribsToNormal(LPCSTR pcszFile, LPCSTR pcszDir) // Set the attribs of pcszFile (can contain wildcards) under pcszDir to NORMAL
{ CHAR szFile[MAX_PATH]; LPSTR pszPtr; WIN32_FIND_DATA fileData; HANDLE hFindFile;
lstrcpy(szFile, pcszDir); AddPath(szFile, NULL); pszPtr = szFile + lstrlen(szFile);
lstrcpy(pszPtr, pcszFile); if ((hFindFile = FindFirstFile(szFile, &fileData)) != INVALID_HANDLE_VALUE) { do { if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { lstrcpy(pszPtr, fileData.cFileName); SetFileAttributes(szFile, FILE_ATTRIBUTE_NORMAL); } } while (FindNextFile(hFindFile, &fileData));
FindClose(hFindFile); } }
VOID CopyFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, BOOL fQuiet) { SHFILEOPSTRUCT shfStruc; CHAR szSrcFiles[MAX_PATH + 1];
if (!PathExists(pcszDstDir)) PathCreatePath(pcszDstDir); else { // set the attribs of files under pcszDstDir to NORMAL so that on a reinstall,
// SHFileOperation doesn't choke on read-only files
SetAttribsToNormal(pcszFile, pcszDstDir); }
ZeroMemory(szSrcFiles, sizeof(szSrcFiles)); lstrcpy(szSrcFiles, pcszSrcDir); AddPath(szSrcFiles, pcszFile);
ZeroMemory(&shfStruc, sizeof(shfStruc));
shfStruc.hwnd = NULL; shfStruc.wFunc = FO_COPY; shfStruc.pFrom = szSrcFiles; shfStruc.pTo = pcszDstDir; shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR; if (fQuiet) shfStruc.fFlags |= FOF_SILENT;
SHFileOperation(&shfStruc); }
VOID DelFiles(LPCSTR pcszFile, LPCSTR pcszDstDir) { SHFILEOPSTRUCT shfStruc; CHAR szDstFiles[MAX_PATH + 1];
// set the attribs of files under pcszDstDir to NORMAL so that
// SHFileOperation doesn't choke on read-only files
SetAttribsToNormal(pcszFile, pcszDstDir);
ZeroMemory(szDstFiles, sizeof(szDstFiles)); lstrcpy(szDstFiles, pcszDstDir); AddPath(szDstFiles, pcszFile);
ZeroMemory(&shfStruc, sizeof(shfStruc));
shfStruc.hwnd = NULL; shfStruc.wFunc = FO_DELETE; shfStruc.pFrom = szDstFiles; shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
SHFileOperation(&shfStruc); }
VOID ExtractFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, EXTRACTFILES pfnExtractFiles) { CHAR szSrcCab[MAX_PATH];
lstrcpy(szSrcCab, pcszSrcDir); AddPath(szSrcCab, pcszFile);
// NOTE: ExtractFiles fails if the dest dir doesn't exist
if (!PathExists(pcszDstDir)) PathCreatePath(pcszDstDir); else { // set the attribs of all the files under pcszDstDir to NORMAL so that on a reinstall,
// ExtractFiles doesn't choke on read-only files
SetAttribsToNormal("*.*", pcszDstDir); }
pfnExtractFiles(szSrcCab, pcszDstDir, 0, NULL, NULL, 0); }
VOID MoveFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir) { // Can't use SHFileOperation to move files because on a reinstall,
// we get an error saying that the target files already exist.
// Workaround is to call CopyFiles and then DelFiles.
CopyFiles(pcszSrcDir, pcszFile, pcszDstDir, TRUE); DelFiles(pcszFile, pcszSrcDir); }
|