Windows Setup Program (Setup.exe)

This setup utility allows one to install an executable and then run executables that will setup the computer, like .NET setup files.

Setup.exe reads the install.txt file to know the executable that needs to be installed in the Program Files folder and for the shortcut link installed in the Start Menu. Next, the system reads the execute.txt file to know the files that need to be executed (like .NET setup files) to finish setting up the computer.

This program is written using the Win32 API. Feel free to modify the code to meet your needs.

To download the example executables, click here: WINAPISETUP.zip.

#include <windows.h>
#include <shlobj.h>

#define ALLOC(siz) LocalAlloc(LMEM_FIXED, siz)
#define FREE(mem) LocalFree(mem)

HRESULT CreateShortcut(char *szPathToObject, char *szPathToShortcut, char *szDescription)
{
	HRESULT hr;
	IShellLinkA *psl;

	CoInitialize(NULL);
	hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&psl);
	if(SUCCEEDED(hr))
	{
		IPersistFile *ppf;

		psl->SetPath(szPathToObject);
		psl->SetDescription(szDescription);

		hr = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
		if(SUCCEEDED(hr))
		{
			WCHAR *wsz = (WCHAR *)ALLOC(MAX_PATH * sizeof(WCHAR));
			int i;

			if(i = MultiByteToWideChar(CP_ACP, 0, szPathToShortcut, -1, wsz, MAX_PATH))
				hr = ppf->Save(wsz, TRUE);
			else
				hr = -1;
			FREE(wsz);
			ppf->Release();
		}
		psl->Release();
	}
	CoUninitialize();
	return hr;
}

void WriteToConsole(char *pszFirst, char *pszSecond)
{
	unsigned long ul;
	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
	if(h != INVALID_HANDLE_VALUE)
	{
		WriteConsoleA(h, pszFirst, strlen(pszFirst), &ul, NULL);
		if(pszSecond)
			WriteConsoleA(h, pszSecond, strlen(pszSecond), &ul, NULL);
	}
}

void PrintLastError()
{
	LPVOID lpMsgBuf;
	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(char *)&lpMsgBuf,0,NULL);
	WriteToConsole((char *)lpMsgBuf, "\r\n");
	FREE(lpMsgBuf);
}

DWORD WINAPI PrintDots(void *pv)
{
	while(TRUE)
	{
		WriteToConsole(".", NULL);
		Sleep(1000);
	}
	return 0xffffffff;
}

BOOL ExecuteProcess(char *szCmdLine)
{
	STARTUPINFOA *si = (STARTUPINFOA *)ALLOC(sizeof(STARTUPINFOA));
	PROCESS_INFORMATION *pi = (PROCESS_INFORMATION *)ALLOC(sizeof(PROCESS_INFORMATION));

	ZeroMemory(si, sizeof(STARTUPINFOA));
	si->cb = sizeof(STARTUPINFOA);
	ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
	WriteToConsole("Executing \"", szCmdLine);
	WriteToConsole("\"\r\nIf your system has to reboot then you will have to start setup again\r\n", NULL);
	if(!CreateProcessA(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, si, pi))
	{
		PrintLastError();
		FREE(si);
		FREE(pi);
		return FALSE;
	}
	HANDLE hThread = CreateThread(NULL, 0, PrintDots, NULL, 0, NULL);
	WaitForSingleObject(pi->hProcess, INFINITE);
	TerminateThread(hThread, 0);
	WriteToConsole("\r\n", NULL);
	CloseHandle(pi->hProcess);
	CloseHandle(pi->hThread);
	FREE(pi);
	FREE(si);
	return TRUE;
}

HWND GetConsoleHandle()
{
	#define BUFFSIZE 768
	HWND hwnd;
	char pszWindowTitle[BUFFSIZE]; 

	GetConsoleTitleA(pszWindowTitle, BUFFSIZE);
	int i = strlen(pszWindowTitle);
	ltoa(GetTickCount(), &pszWindowTitle[i], 16);
	ltoa(GetCurrentProcessId(), &pszWindowTitle[strlen(pszWindowTitle)], 16);
	SetConsoleTitleA(pszWindowTitle);
	Sleep(50);
	hwnd = FindWindowA(NULL, pszWindowTitle);
	pszWindowTitle[i] = 0;
	SetConsoleTitleA(pszWindowTitle);
	return(hwnd);
}

int FailMessage()
{
	MessageBoxA(GetConsoleHandle(), "The program failed to installed successfully.", "Failed", MB_OK|MB_ICONSTOP);
	return 0;
}

BOOL Reboot()
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;

	if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		PrintLastError();
		FailMessage();
		return FALSE;
	}

	LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);

	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0))
	{
		PrintLastError();
		FailMessage();
		return FALSE;
	}

	if(!InitiateSystemShutdownA(NULL, NULL, 0, TRUE, TRUE))
	{
		PrintLastError();
		FailMessage();
		return FALSE;
	}

	tkp.Privileges[0].Attributes = 0;

	if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0))
	{
		PrintLastError();
		FailMessage();
	}
	return TRUE;
}

int main(int argc, char **argv)
{
	HANDLE hFile;
	char *szInstallTxt;

	char *szProgramFilesFolder = (char *)ALLOC(MAX_PATH);
	SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szProgramFilesFolder);

	char *szProgramsMenuFolder = (char *)ALLOC(MAX_PATH);
	SHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, szProgramsMenuFolder);

	DWORD i;
	for(i = strlen(argv[0]); i > 0 && argv[0][i] != '\\'; i--);
	if(0 == i)
	{
		WriteToConsole("Error in path\r\n", NULL);
		return FailMessage();
	}
	char ch = argv[0][++i];
	argv[0][i] = 0;
	WriteToConsole("Changing folder: ", argv[0]);
	if(!SetCurrentDirectoryA(argv[0]))
	{
		PrintLastError();
		return FailMessage();
	}
	argv[0][i] = ch;
	WriteToConsole("\r\n", NULL);

	WriteToConsole("Opening \"install.txt\"\r\n", NULL);
	hFile = CreateFileA("install.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if(hFile == INVALID_HANDLE_VALUE)
	{
		PrintLastError();
		return FailMessage();
	}
	else
	{
		szInstallTxt = (char *)ALLOC(i = GetFileSize(hFile, NULL) + 1);
		WriteToConsole("Reading \"install.txt\"\r\n", NULL);
		if(!ReadFile(hFile, szInstallTxt, i, &i, NULL))
		{
			PrintLastError();
			return FailMessage();
		}
		CloseHandle(hFile);
		szInstallTxt[i] = 0;
		WriteToConsole("Checking \"", szInstallTxt);
		WriteToConsole("\"\r\n", NULL);
		hFile = CreateFileA(szInstallTxt, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
		if(hFile == INVALID_HANDLE_VALUE)
		{
			PrintLastError();
			return FailMessage();
		}
		CloseHandle(hFile);
	}

	char *sz;
	for(sz = szProgramFilesFolder; *sz; sz++);
	*sz++ = '\\';
	for(i = strlen(szInstallTxt); i && szInstallTxt[i] != '.'; i--);
	if(i == 0)
	{
		WriteToConsole("Invalid file name \"", szInstallTxt);
		WriteToConsole("\"\r\n", NULL);
		return FailMessage();
	}
	szInstallTxt[i] = 0;
	strcpy(sz, szInstallTxt);
	char *szName = (char *)ALLOC(strlen(szInstallTxt));
	strcpy(szName, szInstallTxt);
	szInstallTxt[i] = '.';
	WIN32_FIND_DATAA fd;
	HANDLE hFind = FindFirstFileA(szProgramFilesFolder, &fd);
	if(hFind != INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
		{
			if(!CreateDirectoryA(szProgramFilesFolder, NULL))
			{
				PrintLastError();
				return FailMessage();
			}
		}
	}
	else
	{
		if(!CreateDirectoryA(szProgramFilesFolder, NULL))
		{
			PrintLastError();
			return FailMessage();
		}
	}
	for(sz = szProgramFilesFolder; *sz; sz++);
	*sz++ = '\\';
	strcpy(sz, szInstallTxt);
	if(!CopyFileA(szInstallTxt, szProgramFilesFolder, FALSE))
	{
		PrintLastError();
		return FailMessage();
	}
	sz = &szProgramsMenuFolder[strlen(szProgramsMenuFolder)];
	*sz++ = '\\';
	strcpy(sz, szName);
	sz = &sz[strlen(sz)];
	strcpy(sz, ".lnk");
	WriteToConsole("Creating \"", szProgramsMenuFolder);
	WriteToConsole("\"\r\n", NULL);
	if(!SUCCEEDED(CreateShortcut(szProgramFilesFolder, szProgramsMenuFolder, szName)))
		WriteToConsole("Error creating shortcut\r\n", NULL);

	WriteToConsole("Opening \"execute.txt\"\r\n", NULL);
	hFile = CreateFileA("execute.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if(hFile != INVALID_HANDLE_VALUE)
	{
		char *szExecTxt = (char *)ALLOC(i = GetFileSize(hFile, NULL) + 2);
		WriteToConsole("Reading \"execute.txt\"\r\n", NULL);
		if(!ReadFile(hFile, szExecTxt, i, &i, NULL))
		{
			PrintLastError();
			return FailMessage();
		}
		CloseHandle(hFile);
		if(i > 0)
		{
			*((short *)&szExecTxt[i]) = 0;
			for(i = 0; szExecTxt[i]; i++)
			{
				if(szExecTxt[i] == '\r' && szExecTxt[i + 1] == '\n')
				{
					szExecTxt[i] = 0;
					strcpy(&szExecTxt[i + 1], &szExecTxt[i + 2]);
				}
			}
			while(*szExecTxt == 0) szExecTxt++;
			while(*szExecTxt)
			{
				if(!ExecuteProcess(szExecTxt))
					return FailMessage();
				while(*szExecTxt) szExecTxt++;
				szExecTxt++;
			}
		}
	}
	if(MessageBoxA(GetConsoleHandle(), "The program installed successfully. Restart your computer now to finish the installation.", "Success", MB_OK|MB_ICONINFORMATION|MB_OKCANCEL) == IDOK)
	{
		if(!Reboot())
			MessageBox(GetConsoleHandle(), "Please reboot your computer now.", "Reboot Required", MB_OK);
	}
	return 0;
}