PROWAREtech

articles » current » windows » application-programming-interface » console-setup-program

Windows API: Basic Console Setup Program (setup.exe)

A Windows console setup program; written in C/C++.

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

The code 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 console application is written using the Win32 API. Feel free to modify the code to meet your needs.

See this article for an example of this same code but with a graphical user environment (not a console app).

Excuse the spaghetti code.

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

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

void Strcpy(char* dest, const char* src)
{
	while (*src)
		*dest++ = *src++;
	*dest = '\0';
}

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(const char* pszFirst, const 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;
}

int FailMessage()
{
	MessageBoxA(GetConsoleWindow(), "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, "SeShutdownPrivilege", &tkp.Privileges[0].Luid); // "SeShutdownPrivilege" == SE_SHUTDOWN_NAME

	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;
}

BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType)
{
	switch (dwCtrlType)
	{
	case CTRL_C_EVENT:
	case CTRL_BREAK_EVENT:
	case CTRL_CLOSE_EVENT:
		return MessageBoxA(GetConsoleWindow(), "EXIT?", "Do you wish to exit", MB_YESNO) == IDNO;
	}
	return FALSE;
}

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

	if (argc == 1)
	{
		ShellExecuteA(NULL, "runas", argv[0], "/admin", NULL, SW_SHOWNORMAL);
		return 0;
	}

	HWND hwnd = GetConsoleWindow();

	SetConsoleCtrlHandler(HandlerRoutine, TRUE);
	EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); // DISABLE CONSOLE WINDOW CLOSE BUTTON


	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(hwnd, "The program installed successfully. Restart your computer now to finish the installation.", "Success", MB_OK | MB_ICONINFORMATION | MB_OKCANCEL) == IDOK)
	{
		if (!Reboot())
			MessageBoxA(hwnd, "Please reboot your computer now.", "Reboot Required", MB_OK);
	}
	return 0;
}

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE