/** The "IELess Release" configuration excludes the requirement of IE6.0 in the install.
* IELess Release is signified by the presence of #define EXCLUDE_IE6 (defined in the project settings).
* If you're not using MFC, and have made a standalone install as detailed in Nikola Dudar's blog, then you can
* build an IELess Release.
*
* This won't help with running on Win95/NT. And if you use any MFC, then the IELess Release will not work.
* PS. To clarify any IE4/5/6 confusion: We check for IE5.0, and if it is not present, we install IE6.0.2600.1106
**/
/**
* To compile the resources: you'll have to download the following installs
* Vcredist_x86.exe (Visual C++ Runtime redistributable)
* Not available from Microsoft yet (obtain from %ProgramFiles%\Microsoft Visual Studio 8\SDK\v2.0\Bootstrapper\Packages\vcredist_x86)
* InstMSIA.exe (Windows Installer 2.0)
* Download from http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=CEBBACD8-C094-4255-B702-DE3BB768148F
* Sp4Express_En.exe (Windows 2000 Service Pack 4 express install)
* Download from http://download.microsoft.com/download/B/1/A/B1A2A4DF-CC8E-454B-AD9F-378143D77AEB/SP4Express_EN.exe
* WindowsInstaller-kb893803-v2-x86.exe (Windows Installer 3.1 rerelease)
* Download from http://www.microsoft.com/downloads/details.aspx?familyid=889482FC-5F56-4A38-B838-DE776FD4138C&displaylang=en
* Place these files in the same folder as the source files.
**/
#ifndef VCBOOTSTRAP_H
#define VCBOOTSTRAP_H
#pragma once
/* Change this line to */
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
#include <io.h> /* _findfirst/_findnext */
#include <errno.h> /* errno */
#include <direct.h> /* _mkdir */
#include <string> /* basic_string */
#include <stdexcept> /* runtime_error */
#include <vector> /* vector */
#include <map> /* map */
#include <windows.h> /* LoadLibrary, DialogBoxParam, MsgWaitformultipleobjects, CreateProcess, ... */
#include <commctrl.h> /* InitCommonControls */
#include <shlwapi.h> /* DllGetVersionInfo */
#include <tchar.h> /* LPCTSTR */
#if defined(_MSC_VER) && defined(_DEBUG)
#include <crtdbg.h> /* DEBUG Builds only: _CrtSetDbgFlag */
#endif /* _DEBUG */
#include "resource.h"
#pragma comment (lib, "comctl32")
enum InstallPreRequisites {
#ifndef EXCLUDE_IE6
INTERNET_EXPLORER_INSTALL = 1<<0,
#endif /* EXCLUDE_IE6 */
WINDOWS_INSTALLER_2_0_INSTALL = 1<<1,
WINDOWS_INSTALLER_3_1_INSTALL = 1<<2,
WINDOWS_SERVICE_PACK4_INSTALL = 1<<3,
VISUAL_C80_INSTALL = 1<<4
};
template<class T>
class IAutoHandle
{/* abstract base class */
public:
explicit IAutoHandle(const T &WrapHandle)
: h(WrapHandle)
{/* Caller is responsible for checking NULL values */
}
inline operator T()
{
return this->h;
}
protected:
virtual ~IAutoHandle(){};
inline T get() {return this->h;}
inline const T get() const {return this->h;}
T h;
};
class AutoLibrary : public IAutoHandle<HMODULE>
{
public:
explicit AutoLibrary(HMODULE hModule) : IAutoHandle<HMODULE>(hModule) {}
virtual ~AutoLibrary()
{
::FreeLibrary(this->get());
}
};
#ifndef EXCLUDE_IE6
class read_registry_key
{
public:
read_registry_key(const std::basic_string<char> &subkey)
: hKey(NULL)
{/* Reads a key from HKEY_LOCAL_MACHINE only. */
LONG lResult = 0;
lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey.c_str(), 0, KEY_READ, &this->hKey);
if(lResult != ERROR_SUCCESS)
{
throw std::runtime_error("Error occurred opening registry key");
}
/* We're only responsible for managing hKey, and this constructor must fully complete for hKey to be valid. */
}
const std::vector<BYTE> get_value(const std::basic_string<char> &value)
{
LONG lResult = 0;
std::vector<BYTE> result;
DWORD lpcbData = 0;
lResult = RegQueryValueExA(this->hKey, value.c_str(), NULL, NULL, NULL, &lpcbData);
if(lpcbData < 1 || lpcbData > INT_MAX)
{
throw std::runtime_error("Registry key is too large");
}
result.resize(lpcbData);
lResult = RegQueryValueExA(this->hKey, value.c_str(), NULL, NULL, &result.at(0), &lpcbData);
if(lResult != ERROR_SUCCESS)
{
throw std::runtime_error("Registry key exists but doesn't contain a required value");
}
return result;
}
~read_registry_key()
{
/* If this doesn't exist, then the user will get leaked handles (who cares, especially if we cannot close it?). */
RegCloseKey(this->hKey);
/* hAdvApi32 is freed automatically. */
}
private:
HKEY hKey;
};
#endif /* EXCLUDE_IE6 */
class file_object
{
public:
explicit file_object(const std::basic_string<char> &fileName, DWORD desiredAccess = GENERIC_READ, DWORD dwDisposition = OPEN_EXISTING) : hFile(NULL)
{
HANDLE FileTmpHandle = CreateFile(fileName.c_str(), desiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, dwDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
if(FileTmpHandle == NULL || FileTmpHandle == INVALID_HANDLE_VALUE)
{/* We won't be opening weird driver handles on Win9x */
throw std::runtime_error("error occurred opening file");
}
else this->hFile = FileTmpHandle;
}
DWORD write(const void *exeData, unsigned int dataSize)
{
DWORD result = 0;
if(!::WriteFile(this->hFile, exeData, dataSize, &result, NULL))
{
return 0;
}
return result;
}
~file_object()
{
/* Let it leak on systems without CloseHandle */
CloseHandle(this->hFile);
}
private:
HANDLE hFile;
};
class directory_object
{/* C4512 is suppressed in the project settings */
private:
const std::basic_string<char> dirName;
public:
explicit directory_object(std::basic_string<char> dirNameIn) : dirName(dirNameIn)
{
SetLastError(ERROR_SUCCESS);
errno = 0;
if(_mkdir(dirName.c_str()) < 0)
{
if(errno != EEXIST)
throw std::runtime_error("Error occurred creating directory");
}
}
const std::basic_string<char> &GetName() const
{
return this->dirName;
}
virtual ~directory_object()
{/* Due to the way that processes are spawned in the temp directory, the directory cannot always completely deleted. */
}
};
class directory_object_temp : public directory_object
{
private:
BOOL EmptyDirectory(const std::basic_string<char> &dirName)
{/* Does not delete subdirectories and will panic on the first sign of error. */
BOOL Result = TRUE;
std::basic_string<char> dirSearch = dirName;
::_finddata_t dirEnt = {0};
dirSearch.append("\\*.*");
intptr_t FindHandle = ::_findfirst(dirSearch.c_str(), &dirEnt);
do {
if(dirEnt.name[0] == '.' && (dirEnt.name[1] == '\0' || dirEnt.name[1] == '.'))
{
continue;
}
dirSearch = dirName;
dirSearch += "\\";
dirSearch += dirEnt.name;
if(remove(dirSearch.c_str()) == -1)
{
Result = FALSE;
break;
}
} while(::_findnext(FindHandle, &dirEnt) != -1);
::_findclose(FindHandle);
return Result;
}
public:
/* call tmpnam_s yourself and put the name in here. */
explicit directory_object_temp(const std::basic_string<char> &tmpDirName) : directory_object(tmpDirName)
{
}
virtual ~directory_object_temp()
{/* BUGBUG: this class obliterates all files in the directory, including any files we may not own */
this->EmptyDirectory(this->GetName());
_rmdir(this->GetName().c_str());
}
};
int ScratchCode(const HINSTANCE hInst, const std::basic_string<TCHAR> &sCmdLine, const int nCmdShow);
INT_PTR CALLBACK MsgDlgProc(HWND TheirhWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
DWORD ExtractAndLoadExecutable(HWND TheirhWnd, const std::basic_string<char> &exeName, \
const std::basic_string<char> &sCmdLine, int nCmdShow);
const std::basic_string<char> GetTemporaryName();
BOOL WaitWithMessageLoop(HANDLE hHandleToWaitOn, DWORD dwIterateTimeOutMilliseconds = INFINITE);
BOOL CheckIfCanLoadDLL(int &reqdSoftware);
int InstallRequiredApps(HWND TheirhWnd, const int reqdSoftware);
#endif /* VCBOOTSTRAP_H */