// launcher.cpp
//
// Wednesday, March 18, 2009 (Melekor)
// initial version.
//

#include <windows.h>
#include <shlwapi.h>

#pragma comment(linker,"/ENTRY:WinMain")

// Create a remote thread in the target process that loads our dll and immediately exits.
// Return value is the dll handle.
HMODULE Inject(HANDLE hProcess, LPCSTR pszDllPath, UINT uiDllPathLength)
{
	HMODULE hLibModule;
	LPVOID pszDllPathRemote;
	HANDLE hThread;
	pszDllPathRemote = VirtualAllocEx(hProcess, NULL, uiDllPathLength, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
	WriteProcessMemory(hProcess, pszDllPathRemote, (LPVOID)pszDllPath, uiDllPathLength, NULL);
	hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)
		GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA"), pszDllPathRemote, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);
	GetExitCodeThread(hThread, (DWORD*)&hLibModule);
	CloseHandle(hThread);
	VirtualFreeEx(hProcess, pszDllPathRemote, uiDllPathLength, MEM_RELEASE);
	return hLibModule;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	// set the current directory to the executable's location.
	// when we spawn the myth process, the current directory will be inherited.
	WCHAR fileName[MAX_PATH];
	DWORD length = GetModuleFileNameW(NULL, fileName, MAX_PATH);
	for(DWORD i = length; i != 0 && fileName[i] != '\\'; --i)
		fileName[i] = 0;
	SetCurrentDirectoryW(fileName);

	// spawn the myth process (initially suspended)

	PROCESS_INFORMATION processInfo;
	STARTUPINFOW startupInfo = { sizeof(STARTUPINFOW) };

	// if there is a command line argument, use that as the path to the executable -
	// this enables drag & drop onto the launcher.
	LPWSTR* args;
	int numArgs;
	args = CommandLineToArgvW(GetCommandLineW(), &numArgs);
	LPWSTR path = numArgs == 1 ? L"Myth_TFL.exe" : args[1];
	PathStripPathW(path);

	BOOL success = CreateProcessW(
		path,
		NULL, NULL, NULL, FALSE,
		CREATE_SUSPENDED,
		NULL, NULL,
		&startupInfo,
		&processInfo);

	if(success)
	{
		// myth successfully launched, attempt to inject the launcherdll
		const char launcherModule[] = "launcherdll\0";
		HANDLE hProcess = processInfo.hProcess;
		HMODULE hLibModule = Inject(hProcess, launcherModule, sizeof(launcherModule));
		if(hLibModule)
		{
			// injection successful, let myth run and we're done.
			ResumeThread(processInfo.hThread);
			success = TRUE;
		}
		else
		{
			// injection failed, so kill the myth process.
			TerminateProcess(hProcess,-1);
			success = FALSE;
		}
	}

	if(!success)
	{
		MessageBox(NULL, "DLL injection failed!", "Error", MB_ICONERROR);
	}

	return 0;
}

