Skip to content

Commit

Permalink
fixed a race condition in DLL blocking at game startup (also, using k…
Browse files Browse the repository at this point in the history
…eyboard layout as a hint for app locale in certain cases)
  • Loading branch information
[email protected] committed Jul 30, 2011
1 parent 92bc804 commit 047c531
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/shared/ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct TasFlags
int storeVideoMemoryInSavestates;
int appLocale;
unsigned int movieVersion;
int osVersionMajor, osVersionMinor;
LogCategoryFlag includeLogFlags;
LogCategoryFlag excludeLogFlags;
#ifdef _USRDLL
Expand Down
48 changes: 32 additions & 16 deletions src/wintasee/wintasee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,13 +1530,24 @@ void HookCOMInterface(REFIID riid, LPVOID* ppvOut, bool uncheckedFastNew)

//typedef UINT (WINAPI *SetCPGlobalType)(UINT acp);

OSVERSIONINFO osvi = {sizeof(OSVERSIONINFO)};
// warning: we can't trust these too much (version lies from compatibility mode shims are common)
bool IsWindowsXP() { return osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1; }
bool IsWindowsVista() { return osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0; }
bool IsWindows7() { return osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1; }
bool IsWindowsXP() { return tasflags.osVersionMajor == 5 && tasflags.osVersionMinor == 1; }
bool IsWindowsVista() { return tasflags.osVersionMajor == 6 && tasflags.osVersionMinor == 0; }
bool IsWindows7() { return tasflags.osVersionMajor == 6 && tasflags.osVersionMinor == 1; }


// order of execution when the game starts up:
// 1: A very small number of essential DLLs get loaded, such as kernel32.dll.
// 2: DllMain runs, because this DLL (wintasee.dll) has been inserted into the IAT.
// 3: Any statically-linked DLLs used by the game get loaded.
// 4: WinMain runs, but pauses at a breakpoint the debugger process inserted at the entrypoint.
// 5: PostDllMain runs (because we created a thread to run it in DllMain).
// 6: WinMain resumes, and the game's code starts executing.


// DllMain is the entry point of this DLL, but the things we can do there are extremely limited.
// For example, DllMain is not allowed to call any function that might cause any DLL to load.
// PostDllMain is the code we run after DllMain to finish up initialization without restrictions.
DWORD WINAPI PostDllMain(LPVOID lpParam)
{
dllInitializationDone = true;
Expand All @@ -1551,6 +1562,7 @@ DWORD WINAPI PostDllMain(LPVOID lpParam)
extern bool watchForCLLApiNum;
extern int cllApiNum;
watchForCLLApiNum = true; // a few functions like GetSystemMetrics and LoadKeyboardLayout are very likely to call ClientLoadLibrary
cllApiNum = -1;
curtls.treatDLLLoadsAsClient++;
GetSystemMetrics(42);
curtls.treatDLLLoadsAsClient--; // disable here because we'd prefer LoadKeyboardLayout to actually succeed.
Expand Down Expand Up @@ -1580,15 +1592,12 @@ DWORD WINAPI PostDllMain(LPVOID lpParam)
{
// didn't find it, somehow
watchForCLLApiNum = false;
cllApiNum = -1;
GetVersionEx(&osvi);
cllApiNum = (IsWindows7() ? 65 : 66);
debugprintf("using ClientLoadLibrary ApiNumber = %d. OS = %d.%d\n", cllApiNum, osvi.dwMajorVersion, osvi.dwMinorVersion);
debugprintf("using ClientLoadLibrary ApiNumber = %d. OS = %d.%d\n", cllApiNum, tasflags.osVersionMajor, tasflags.osVersionMinor);
}
else
{
GetVersionEx(&osvi);
debugprintf("found ClientLoadLibrary ApiNumber = %d. OS = %d.%d\n", cllApiNum, osvi.dwMajorVersion, osvi.dwMinorVersion);
debugprintf("found ClientLoadLibrary ApiNumber = %d. OS = %d.%d\n", cllApiNum, tasflags.osVersionMajor, tasflags.osVersionMinor);
}
curtls.callingClientLoadLibrary = FALSE;

Expand All @@ -1597,6 +1606,7 @@ DWORD WINAPI PostDllMain(LPVOID lpParam)
curtls.isFirstThread = true;

cmdprintf("POSTDLLMAINDONE: 0");
debugprintf(__FUNCTION__ " returned.\n");

return 0;
}
Expand All @@ -1607,10 +1617,6 @@ BOOL APIENTRY DllMain( HMODULE hModule,
LPVOID lpReserved
)
{
//#pragma message("FIXMEEE")
//return 1;
// debugprintf(__FUNCTION__ ": 0x%X, 0x%X, 0x%X\n", (DWORD)hModule, (DWORD)fdwReason, (DWORD)lpReserved);

ThreadLocalStuff::DllManage(fdwReason);

switch (fdwReason)
Expand All @@ -1620,7 +1626,6 @@ BOOL APIENTRY DllMain( HMODULE hModule,
tasflags.timescale = 1;
tasflags.timescaleDivisor = 1;

// MessageBox(NULL, "HELLOFOO", "BAZBAR", 0);
debugprintf("DllMain started, injection must have worked.\n");
hCurrentProcess = GetCurrentProcess();
DisableThreadLibraryCalls(hModule);
Expand Down Expand Up @@ -1725,16 +1730,27 @@ BOOL APIENTRY DllMain( HMODULE hModule,
// SetCPGlobal(LocaleToCodePage(tasflags.appLocale));
}

debugprintf("version = %d, movie version = %d\n", SRCVERSION, tasflags.movieVersion);
debugprintf("version = %d, movie version = %d, OS = %d.%d.\n", SRCVERSION, tasflags.movieVersion, tasflags.osVersionMajor, tasflags.osVersionMinor);

// in case PostDllMain doesn't get called right away (although we really need it to...)
if(tasflags.osVersionMajor <= 6)
{
extern int cllApiNum;
cllApiNum = (IsWindows7() ? 65 : 66);
}

detTimer.Initialize(tasflags.initialTime);
nonDetTimer.Initialize(tasflags.initialTime);

{
DWORD threadId = 0;
CreateThread(NULL, 0, PostDllMain, NULL, 0, &threadId);
HANDLE hThread = CreateThread(NULL, 0, PostDllMain, NULL, 0, &threadId); // note that Windows won't let this thread start executing until after DllMain returns
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); // in case suspending the main thread doesn't work
SetThreadPriorityBoost(hThread, TRUE);
SetThreadName(threadId, "PostDllMain");
}
if(!s_frameThreadId)
SetThreadName(-1, "Main");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
Expand Down
12 changes: 7 additions & 5 deletions src/wintaser/inputsetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,7 @@ extern bool crcVerifyEnabled;
extern int storeVideoMemoryInSavestates;
extern int storeGuardedPagesInSavestates;
extern int appLocale;
extern int tempAppLocale;
extern int debugPrintMode;
extern LogCategoryFlag includeLogFlags;
extern LogCategoryFlag traceLogFlags;
Expand Down Expand Up @@ -2437,11 +2438,12 @@ void Build_Main_Menu(HMENU& MainMenu, HWND hWnd)

// Locale Submenu
i = 0;
MENU_L(Locale, i++, Flags | ((appLocale==0)?MF_CHECKED:MF_UNCHECKED), ID_EXEC_LOCALE_SYSTEM, "", "Use system locale", 0);
MENU_L(Locale, i++, Flags | ((appLocale==1041)?MF_CHECKED:MF_UNCHECKED) | ((!appLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_JAPANESE, "", "Force &Japanese locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((appLocale==2052)?MF_CHECKED:MF_UNCHECKED) | ((!appLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_CHINESE, "", "Force &Chinese (Simplified) locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((appLocale==1042)?MF_CHECKED:MF_UNCHECKED) | ((!appLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_KOREAN, "", "Force &Korean locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((appLocale==1033)?MF_CHECKED:MF_UNCHECKED) | ((!appLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_ENGLISH, "", "Force &English locale", "can't enable while running");
int curAppLocale = appLocale ? appLocale : tempAppLocale;
MENU_L(Locale, i++, Flags | ((curAppLocale==0)?MF_CHECKED:MF_UNCHECKED) | ((tempAppLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_SYSTEM, "", "Use system locale", "movie has forced non-system locale");
MENU_L(Locale, i++, Flags | ((curAppLocale==1041)?MF_CHECKED:MF_UNCHECKED) | ((!curAppLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_JAPANESE, "", "Force &Japanese locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((curAppLocale==2052)?MF_CHECKED:MF_UNCHECKED) | ((!curAppLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_CHINESE, "", "Force &Chinese (Simplified) locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((curAppLocale==1042)?MF_CHECKED:MF_UNCHECKED) | ((!curAppLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_KOREAN, "", "Force &Korean locale", "can't enable while running");
MENU_L(Locale, i++, Flags | ((curAppLocale==1033)?MF_CHECKED:MF_UNCHECKED) | ((!curAppLocale&&started)?MF_GRAYED:0), ID_EXEC_LOCALE_ENGLISH, "", "Force &English locale", "can't enable while running");

// Performance Submenu
i = 0;
Expand Down
Loading

0 comments on commit 047c531

Please sign in to comment.