template <> cut_part_factory<Cut_Part_base>* cut_part_factory<Cut_Part_base>::s_default_cut_part_factory(const process& pro){

	process::const_iterator it = find_if(pro.begin(),pro.end(),is_of_type(higgs));

	bool has_a_higgs = ( it != pro.end() ) ;
//	bool has_a_higgs = true;
#ifndef BH_PUBLIC
	if ( has_a_higgs ) {
			switch ( settings::general::s_cut_type ){
			case  settings::general::Darren:
				return &global_CPFH;
			case  settings::general::FHZ:
				_WARNING("cut_part_factory<Cut_Part_base>::s_default_higgs_cut_part_factory() : No FHZ factory exists using Darren extended factory");
				return &global_CPFH;
			case  settings::general::worker:
				_WARNING("cut_part_factory<Cut_Part_base>::s_default_higgs_cut_part_factory() : No worker factory exists using Darren extended factory");
				return &global_CPFH;
			}
	} else {
		switch ( settings::general::s_cut_type ){
		case  settings::general::Darren:
			return &global_CPFD;
		case  settings::general::FHZ:
			return &global_CPFF;
		case  settings::general::worker:
			return &global_CPFW;
		}
	}
#else
	return &global_CPFW;
#endif
};
void * PluginManager::QueryInterface(UInt32 id)
{
	void	* result = NULL;

#ifdef RUNTIME
	switch(id)
	{
	case kInterface_Scaleform:
		result = (void *)&g_SKSEScaleformInterface;
		break;
//#ifdef _PPAPI
	case kInterface_Papyrus:
		result = (void *)&g_SKSEPapyrusInterface;
		break;
//#endif
	case kInterface_Serialization:
		result = (void *)&g_SKSESerializationInterface;
		break;
	case kInterface_Task:
		result = (void *)&g_SKSETaskInterface;
		break;
	case kInterface_Messaging:
		result = (void *)&g_SKSEMessagingInterface;
		break;

	default:
		_WARNING("unknown QueryInterface %08X", id);
		break;
	}
#else
	_WARNING("unknown QueryInterface %08X", id);
#endif

	return result;
}
示例#3
0
void ImportConsoleCommand(const char * name)
{
	CommandInfo	* info = g_consoleCommands.GetByName(name);
	if(info)
	{
		CommandInfo	infoCopy = *info;

		std::string	newName;

		newName = std::string("con_") + name;

		infoCopy.shortName = "";
		infoCopy.longName = _strdup(newName.c_str());

		g_scriptCommands.Add(&infoCopy);

//		_MESSAGE("imported console command %s", name);
	}
	else
	{
		_WARNING("couldn't find console command (%s)", name);

		// pad it
		g_scriptCommands.Add(&kPaddingCommand);
	}
}
示例#4
0
inline float kinematics::betaiSystem( TLorentzVector* pa, TLorentzVector* pb, int i)
{
	TLorentzVector pTmp = (*pa)+(*pb);
	float E = pTmp.E();
	if(E<=0.) return -99999999.;

	if     (i==1) return pTmp.Px()/E;
	else if(i==2) return pTmp.Py()/E;
	else if(i==3) return pTmp.Pz()/E;
	else _WARNING("i needs to be 1,2,3 (x,y,z), returning -99999999.");
	return -99999999.;
}
示例#5
0
UInt8 InputManager::AllowTextInput(bool allow)
{
	if(allow)
	{
		if(allowTextInput == 0xFF)
			_WARNING("InputManager::AllowTextInput: counter overflow");
		else
			allowTextInput++;
	}
	else
	{
		if(allowTextInput == 0)
			_WARNING("InputManager::AllowTextInput: counter underflow");
		else
			allowTextInput--;
	}

	if(IsConsoleMode())
		Console_Print("%s text input, count = %d", allow ? "allowed" : "disallowed", allowTextInput);

	return allowTextInput;
}
示例#6
0
int
mlvpn_tuntap_read(struct tuntap_s *tuntap)
{
    circular_buffer_t *sbuf;
    mlvpn_tunnel_t *rtun;
    mlvpn_pkt_t *pkt;
    int ret;
    uint32_t type;
    struct iovec iov[2];

    /* choosing a tunnel to send to (direct buffer copy) */
    rtun = mlvpn_rtun_choose();

    /* Not connected to anyone. read and discard packet. */
    if (! rtun)
    {
        char blackhole[DEFAULT_MTU+sizeof(type)];
        return read(tuntap->fd, blackhole, DEFAULT_MTU+sizeof(type));
    }

    /* Buffer checking / reset in case of overflow */
    sbuf = rtun->sbuf;
    if (mlvpn_cb_is_full(sbuf))
        _WARNING("[rtun %s] buffer overflow.\n", rtun->name);

    /* Ask for a free buffer */
    pkt = mlvpn_pktbuffer_write(sbuf);

    iov[0].iov_base = &type;
    iov[0].iov_len = sizeof(type);
    iov[1].iov_base = pkt->pktdata.data;
    iov[1].iov_len = DEFAULT_MTU;

    ret = readv(tuntap->fd, iov, 2);
    if (ret < 0)
    {
        /* read error on tuntap is not recoverable. We must die. */
        _FATAL("[tuntap %s] unrecoverable read error: %s\n",
                tuntap->devname, strerror(errno));
        exit(1);
    } else if (ret == 0) {
        /* End of file */
        _FATAL("[tuntap %s] unrecoverable error (reached EOF on tuntap!)\n",
                tuntap->devname);
        exit(1);
    }
    pkt->pktdata.len = ret - sizeof(type);

    return pkt->pktdata.len;
}
	void saveDisplayStatus(StaticFunctionTag*, TESObjectREFR* pObject, bool addContributor = true)
	{
		Json::Value jsonDisplayList = ReadDisplayData();

		const char * playerName = nullptr;

		TESFullName* pPlayerName = DYNAMIC_CAST((*g_thePlayer)->baseForm, TESForm, TESFullName);
		if (pPlayerName)
			playerName = pPlayerName->name.data;
		
		if (!saveDisplayStatus(jsonDisplayList, pObject, addContributor ? playerName : nullptr))
			_WARNING("Problem saving Display with FormID %08x", pObject->formID);

		WriteDisplayData(jsonDisplayList);
	}
BOOL OPCEngine::stop(void)
{
	if (m_hOPCThread != INVALID_HANDLE_VALUE) 
	{
		::SetEvent(m_events[END_EVENT]);
		if (WAIT_FAILED == ::WaitForSingleObject(m_hOPCThread, 10000)) 
		{
			_WARNING(TG_GRP, OPCENGINE_WRN_THREAD,(_T("Can't terminate engine thread")));
		}
		::CloseHandle(m_hOPCThread);
		m_hOPCThread = INVALID_HANDLE_VALUE;
	}

	_TRACE(TL_INF, TG_ENG, (_T("stop engine")));
	return (m_hOPCThread == INVALID_HANDLE_VALUE); 
}
void Hooks_Debug_Init(void)
{
	GetSystemTime(&s_launchTime);

	UInt32	enableMiniDump = 0;
	GetConfigOption_UInt32("Debug", "WriteMinidumps", &enableMiniDump);

	if(enableMiniDump)
	{
		_MESSAGE("minidumps enabled");

		// try to get dbghelp
		s_dbgHelpDLL = LoadLibrary("dbghelp.dll");
		if(s_dbgHelpDLL)
		{
			s_dbgHelpWriteDump = (_MiniDumpWriteDump)GetProcAddress(s_dbgHelpDLL, "MiniDumpWriteDump");
			if(!s_dbgHelpWriteDump)
				_WARNING("dbghelp missing MiniDumpWriteDump, upgrade to dbghelp 5.1 or later");
		}
		else
		{
			_MESSAGE("no dbghelp");
		}

		// we want to catch crashes from hook commit, apply exception filter in Init function
		if(s_dbgHelpDLL && s_dbgHelpWriteDump)
		{
			// precalculate as much as possible
			char	myDocumentsPath[MAX_PATH];
			ASSERT(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath)));

			sprintf_s(s_crashDumpPath, sizeof(s_crashDumpPath), "%s\\My Games\\Skyrim\\SKSE\\Crashdumps\\%04d-%02d-%02d_%02d.%02d.%02d.dmp", myDocumentsPath,
				s_launchTime.wYear, s_launchTime.wMonth, s_launchTime.wDay,
				s_launchTime.wHour, s_launchTime.wMinute, s_launchTime.wSecond);

			IFileStream::MakeAllDirs(s_crashDumpPath);

			// replace previous exception filter
			s_oldExceptionFilter = SetUnhandledExceptionFilter(ExceptionFilter);
			_MESSAGE("old exception filter = %08X", s_oldExceptionFilter);

			// disable game overwriting exception filter
			UInt32	thunkAddress = (UInt32)GetIATAddr((UInt8 *)GetModuleHandle(NULL), "kernel32.dll", "SetUnhandledExceptionFilter");
			SafeWrite32(thunkAddress, (UInt32)SetUnhandledExceptionFilter_Hook);
		}
	}
}
示例#10
0
bool AssignToStringVarLong(COMMAND_ARGS, const char* newValue)
{
	double strID = 0;
	UInt8 modIndex = 0;
	bool bTemp = ExpressionEvaluator::Active();
	StringVar* strVar = NULL;

	UInt32 len = (newValue) ? strlen(newValue) : 0;
	if (!newValue || len >= kMaxMessageLength)		//if null pointer or too long, assign an empty string
		newValue = "";

	if (ExtractSetStatementVar(scriptObj, eventList, scriptData, &strID, &modIndex)) {
		strVar = g_StringMap.Get(strID);
		bTemp = false;
	}
	else if (!bTemp) {
		_WARNING("Function must be used within a Set statement or NVSE expression");
		return false;
	}

	if (!modIndex)
		modIndex = scriptObj->GetModIndex();

	if (strVar)
	{
		strVar->Set(newValue);
		g_StringMap.MarkTemporary(strID, false);
	}
	else
		strID = g_StringMap.Add(modIndex, newValue, bTemp);

	*result = strID;

#if _DEBUG	// console feedback disabled in release by request (annoying when called from batch scripts)
	if (IsConsoleMode() && !bTemp)
	{
		if (len < 480)
			Console_Print("Assigned string >> \"%s\"", newValue);
		else
			Console_Print("Assigned string (too long to print)");
	}
#endif

	return true;
}
示例#11
0
static void DoModScriptWindow(HWND wnd)
{
	SendMessage(wnd, EM_EXLIMITTEXT, 0, 0x00FFFFFF);

	bool	setFont = false;

	if(GetAsyncKeyState(VK_F11))
	{
		LOGFONT		newFontInfo = fontInfo;
		CHOOSEFONT	chooseInfo = { sizeof(chooseInfo) };
		
		chooseInfo.lpLogFont = &newFontInfo;
		chooseInfo.Flags = CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS | CF_SCREENFONTS;

		if(ChooseFont(&chooseInfo))
		{
			HANDLE	newFont = CreateFontIndirect(&newFontInfo);
			if(newFont)
			{
				DeleteObject(fontHandle);

				fontInfo = newFontInfo;
				fontHandle = newFont;
			}
			else
				_WARNING("couldn't create font");
		}

		setFont = true;
	}

	if(GetAsyncKeyState(VK_F12) || setFont || userSetFont)
	{
		userSetFont = true;
		SendMessage(wnd, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
		SendMessage(wnd, WM_SETFONT, (WPARAM)fontHandle, 1);

		UInt32	tabStopSize = 16;
		SendMessage(wnd, EM_SETTABSTOPS, 1, (LPARAM)&tabStopSize);	// one tab stop every 16 dialog units
	}
}
void VisitFormListRecursive(BGSListForm * formList, std::function<void(TESForm*)> functor, UInt8 recurseMax = 3)
{
	if (recurseMax <= 0) {
		_WARNING("%s: Too many recursions, aborting!", __FUNCTION__);
		return;
	}
	_MESSAGE("%s: Checking formlist %08x, recursion %d of 3...", __FUNCTION__, formList->formID, 3 - recurseMax);
	for (int i = 0; i < formList->forms.count; i++)
	{
		TESForm* childForm = NULL;
		if (formList->forms.GetNthItem(i, childForm))
		{
			BGSListForm* childList = NULL;
			childList = DYNAMIC_CAST(childForm, TESForm, BGSListForm);
			if (childList) {
				_MESSAGE("%s: Recursing into formlist %08x...", __FUNCTION__, formList->formID);
				VisitFormListRecursive(childList, functor, recurseMax - 1);
			} else
				functor(childForm);
		}
	}

	// Script Added Forms
	if (formList->addedForms) {
		for (int i = 0; i < formList->addedForms->count; i++) {
			UInt32 formid = 0;
			formList->addedForms->GetNthItem(i, formid);
			TESForm* childForm = LookupFormByID(formid);
			if (childForm) {
				BGSListForm* childList = NULL;
				childList = DYNAMIC_CAST(childForm, TESForm, BGSListForm);
				if (childList) {
					VisitFormListRecursive(formList, functor, recurseMax - 1);
				}
				else
					functor(childForm);
			}
		}
	}
}
示例#13
0
const std::string & GetRuntimeDirectory()
{
	static std::string s_runtimeDirectory;

	if(s_runtimeDirectory.empty())
	{
		std::string	runtimePath = GetRuntimePath();

		// truncate at last slash
		std::string::size_type	lastSlash = runtimePath.rfind('\\');
		if(lastSlash != std::string::npos)	// if we don't find a slash something is VERY WRONG
		{
			s_runtimeDirectory = runtimePath.substr(0, lastSlash + 1);
		}
		else
		{
			_WARNING("no slash in runtime path? (%s)", runtimePath.c_str());
		}
	}

	return s_runtimeDirectory;
}
示例#14
0
// nogore EXE has debug info pointing to TESVng.pdb (probably something else)
// however sometimes the debug info is pointing to the wrong place?
void BranchScan(const UInt8 * base, ProcHookInfo * hookInfo)
{
	bool	result = false;
	bool	probable = false;

	// first check the header where it says it should be
	BranchScan_Basic(base, hookInfo, &probable);

	if(!probable)
	{
		_MESSAGE("using slow branch check");

		// keep scanning, now do the slow and manual way
		// look for RSDS header in .rdata

		const IMAGE_SECTION_HEADER	* rdataSection = GetImageSection(base, ".rdata");
		if(rdataSection)
		{
			const UInt8	* sectionBase = base + rdataSection->PointerToRawData;
			UInt32		sectionLen = rdataSection->SizeOfRawData;

			__try
			{
				for(UInt32 i = 0; (i + sizeof(DebugHeader)) <= sectionLen; i += 4)
				{
					const DebugHeader	* header = (const DebugHeader *)(sectionBase + i);

					header->ReadInfo(hookInfo, &probable);

					if(probable)
						break;
				}
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				_WARNING("exception while scanning for branch");
			}
		}
	}
示例#15
0
void ReadPartReplacements(std::string fixedPath, std::string modPath, std::string fileName)
{
	std::string fullPath = fixedPath + modPath + fileName;
	BSResourceNiBinaryStream file(fullPath.c_str());
	if (!file.IsValid()) {
		return;
	}

	UInt32 lineCount = 0;
	UInt8 gender = 0;
	std::string str = "";
	while (BSReadLine(&file, &str))
	{
		lineCount++;
		str = std::trim(str);
		if (str.length() == 0)
			continue;
		if (str.at(0) == '#')
			continue;

		if (str.at(0) == '[')
		{
			str.erase(0, 1);
			if (_strnicmp(str.c_str(), "Male", 4) == 0)
				gender = 0;
			if (_strnicmp(str.c_str(), "Female", 6) == 0)
				gender = 1;
			continue;
		}

		std::vector<std::string> side = explode(str, '=');
		if (side.size() < 2) {
			_ERROR("%s Error - Line (%d) race from %s has no left-hand side.", __FUNCTION__, lineCount, fullPath.c_str());
			continue;
		}

		std::string lSide = std::trim(side[0]);
		std::string rSide = std::trim(side[1]);

		BGSHeadPart * facePart = GetHeadPartByName(rSide);
		TESRace * race = GetRaceByName(lSide);
		if (!race) {
			_WARNING("%s Warning - Line (%d) race %s from %s is not a valid race.", __FUNCTION__, lineCount, lSide.c_str(), fullPath.c_str());
			continue;
		}

		if (!facePart) {
			_WARNING("%s Warning - Line (%d) head part %s from %s is not a valid head part.", __FUNCTION__, lineCount, rSide.c_str(), fullPath.c_str());
			continue;
		}

		auto charGenData = race->chargenData[gender];
		if (!charGenData) {
			_ERROR("%s Error - Line (%d) race %s from %s has no CharGen data.", __FUNCTION__, lineCount, lSide.c_str(), fullPath.c_str());
			continue;
		}

		if (charGenData->headParts) {
			for (UInt32 i = 0; i < charGenData->headParts->count; i++) {
				BGSHeadPart * headPart = NULL;
				if (charGenData->headParts->GetNthItem(i, headPart)) {
					if (headPart->type == facePart->type) {
						charGenData->headParts->arr.entries[i] = facePart;
					}
				}
			}
		}
	}
}
示例#16
0
static void do_handle_error(liGnuTLSFilter *f, const char *gnutlsfunc, int r, gboolean writing) {
	switch (r) {
	case GNUTLS_E_AGAIN:
		if (writing) f->write_wants_read = TRUE;
		return;
	case GNUTLS_E_REHANDSHAKE:
#ifdef HAVE_SAVE_RENEGOTIATION
		if (f->initial_handshaked_finished && !gnutls_safe_renegotiation_status(f->session)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated unsafe renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		} else {
			_DEBUG(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation", gnutlsfunc);
		}
#else
		if (f->initial_handshaked_finished) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		}
#endif
		return;
	case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
		f_close_with_alert(f, r);
		return;
	case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
	case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
		_DEBUG(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
			gnutls_strerror_name(r), gnutls_strerror(r));
		f_close_with_alert(f, r);
		return;
	case GNUTLS_E_FATAL_ALERT_RECEIVED:
	case GNUTLS_E_WARNING_ALERT_RECEIVED:
		{
			gnutls_alert_description_t alert_desc = gnutls_alert_get(f->session);
			const char* alert_desc_name = gnutls_alert_get_name(alert_desc);
			_INFO(f->srv, f->wrk, f->log_context, "%s (%s): %s %s (%u)", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r),
				(NULL != alert_desc_name) ? alert_desc_name : "unknown alert",
				(unsigned int) alert_desc);
		}
		/* error not handled yet: break instead of return */
		break;
	default:
		if (gnutls_error_is_fatal(r)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
		} else {
			_WARNING(f->srv, f->wrk, f->log_context, "%s non fatal (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
		}
		/* error not handled yet: break instead of return */
		break;
	}

	/* generic error handling */
	if (gnutls_error_is_fatal(r)) {
		if (f->initial_handshaked_finished) {
			f_close_with_alert(f, r);
		} else {
			f_abort_gnutls(f);
		}
	}
}
示例#17
0
int main(int argc, char ** argv)
{
	gLog.SetPrintLevel(IDebugLog::kLevel_Error);
	gLog.SetLogLevel(IDebugLog::kLevel_DebugMessage);

	if(!g_options.Read(argc, argv))
	{
		PrintError("Couldn't read arguments.");
		g_options.PrintUsage();

		return -1;
	}

	if(g_options.m_optionsOnly)
	{
		g_options.PrintUsage();
		return 0;
	}

	if(g_options.m_launchCS)
		_MESSAGE("launching editor");

	if(g_options.m_loadOldblivion)
		_MESSAGE("loading oldblivion");

	// create the process
	STARTUPINFO			startupInfo = { 0 };
	PROCESS_INFORMATION	procInfo = { 0 };
	bool				dllHasFullPath = false;

	startupInfo.cb = sizeof(startupInfo);

	const char	* procName = g_options.m_launchCS ? "TESConstructionSet.exe" : "Oblivion.exe";
	const char	* baseDllName = g_options.m_launchCS ? "obse_editor" : "obse";

	if(g_options.m_altEXE.size())
	{
		procName = g_options.m_altEXE.c_str();
		_MESSAGE("launching alternate exe (%s)", procName);
	}

	if(g_options.m_altDLL.size())
	{
		baseDllName = g_options.m_altDLL.c_str();
		_MESSAGE("launching alternate dll (%s)", baseDllName);

		dllHasFullPath = true;
	}

	std::string		dllSuffix;
	ProcHookInfo	procHookInfo;

	if(!TestChecksum(procName, &dllSuffix, &procHookInfo))
	{
		_ERROR("checksum not found");
		return -1;
	}

	if(procHookInfo.steamVersion)
	{
		// ### maybe check for the loader DLL and just CreateProcess("oblivion.exe") if we can?
		PrintError("You are trying to use a Steam version of Oblivion. Steam users should launch the game through Steam, not by running obse_loader.exe. If OBSE fails to load, go to Steam > Settings > In Game and check the box marked \"Enable Steam community in game\". Please see the instructions in obse_readme.txt for more information.");
		return 0;
	}

	if(g_options.m_crcOnly)
		return 0;

	// build dll path
	std::string	dllPath;
	if(dllHasFullPath)
	{
		dllPath = baseDllName;
	}
	else
	{
		dllPath = GetCWD() + "\\" + baseDllName + "_" + dllSuffix + ".dll";
	}

	_MESSAGE("dll = %s", dllPath.c_str());

	// check to make sure the dll exists
	{
		IFileStream	tempFile;

		if(!tempFile.Open(dllPath.c_str()))
		{
			PrintError("Couldn't find OBSE DLL (%s). Please make sure you have installed OBSE correctly and are running it from your Oblivion folder.", dllPath.c_str());
			return -1;
		}
	}

	bool result = CreateProcess(
		procName,
		NULL,	// no args
		NULL,	// default process security
		NULL,	// default thread security
		TRUE,	// don't inherit handles
		CREATE_SUSPENDED,
		NULL,	// no new environment
		NULL,	// no new cwd
		&startupInfo, &procInfo) != 0;

	// check for Vista failing to create the process due to elevation requirements
	if(!result && (GetLastError() == ERROR_ELEVATION_REQUIRED))
	{
		// in theory we could figure out how to UAC-prompt for this process and then run CreateProcess again, but I have no way to test code for that
		PrintError("Vista has decided that launching Oblivion requires UAC privilege elevation. There is no good reason for this to happen, but to fix it, right-click on obse_loader.exe, go to Properties, pick the Compatibility tab, then turn on \"Run this program as an administrator\".");
		return -1;
	}
	
	ASSERT_STR_CODE(result, "Launching Oblivion failed", GetLastError());

	if(g_options.m_setPriority)
	{
		if(!SetPriorityClass(procInfo.hProcess, g_options.m_priority))
			_WARNING("couldn't set process priority");
	}

	result = false;

	if(g_options.m_launchCS)
	{
		if(g_options.m_oldInject)
		{
			_MESSAGE("using old editor injection method");

			// start the process
			ResumeThread(procInfo.hThread);

			// CS needs to run its crt0 code before the DLL is attached, this delays until the message pump is running
			// note that this method makes it impossible to patch the startup code

			// this is better than Sleep(1000) but still ugly
			WaitForInputIdle(procInfo.hProcess, 1000 * 10);

			// too late if this fails
			result = InjectDLL(&procInfo, dllPath.c_str(), !g_options.m_noSync);
			if(!result)
				PrintError("Couldn't inject dll.");
		}
		else
		{
			_MESSAGE("using new editor injection method");

			result = DoInjectDLL_New(&procInfo, dllPath.c_str(), &procHookInfo);
			if(!result)
				PrintError("Couldn't inject dll.");

			// start the process either way
			ResumeThread(procInfo.hThread);
		}
	}
	else
	{
		result = InjectDLL(&procInfo, dllPath.c_str(), !g_options.m_noSync);
		if(result)
		{
			// try to load oldblivion if requested
			if(g_options.m_loadOldblivion)
			{
				result = LoadOldblivion(&procInfo);
				if(!result)
					PrintError("Couldn't load oldblivion.");
			}
		}
		else
			PrintError("Couldn't inject dll.");
		
		if(result)
		{
			_MESSAGE("launching oblivion");

			// start the process
			ResumeThread(procInfo.hThread);
		}
		else
		{
			_ERROR("terminating oblivion process");

			// kill the partially-created process
			TerminateProcess(procInfo.hProcess, 0);

			g_options.m_waitForClose = false;
		}
	}

	// wait for the process to close if requested
	if(g_options.m_waitForClose)
	{
		WaitForSingleObject(procInfo.hProcess, INFINITE);
	}

	// clean up
	CloseHandle(procInfo.hProcess);
	CloseHandle(procInfo.hThread);

	return 0;
}