Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C++/CLI

Bootstrapper for the VC++ 2005 Redists (with MSI 3.1)

Rate me:
Please Sign up or sign in to vote.
4.97/5 (67 votes)
24 Feb 200624 min read 548.2K   2K   159  
A discussion on deployment in Visual C++ 2005, and an amended version of the vcredist_x86.exe that includes MSI 3.1.
/** 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 */

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Mr. Shah is a reclusive C++/C# developer lurking somewhere in the depths of the city of London. He learnt physics at Kings' College London and obtained a Master in Science there. Having earned an MCAD, he teeters on the brink of transitioning from C++ to C#, unsure of which language to jump to. Fortunately, he also knows how to use .NET interop to merge code between the two languages (which means he won't have to make the choice anytime soon).

His interests (apart from programming) are walking, football (the real one!), philosophy, history, retro-gaming, strategy gaming, and any good game in general.

He maintains a website / blog / FAQ / junk at shexec32.serveftp.net, where he places the best answers he's written to the questions you've asked. If you can find him, maybe you can hire Mr. Shah to help you with anything C++[/CLI]/C#/.NET related Smile | :) .

Comments and Discussions