diff --git a/reactos/dll/appcompat/shims/layer/main.c b/reactos/dll/appcompat/shims/layer/main.c index ac494f30eb2..cfdad2b2c1c 100644 --- a/reactos/dll/appcompat/shims/layer/main.c +++ b/reactos/dll/appcompat/shims/layer/main.c @@ -16,10 +16,10 @@ PHOOKAPI WINAPI GetHookAPIs(IN LPCSTR szCommandLine, IN LPCWSTR wszShimName, OUT return ShimLib_GetHookAPIs(szCommandLine, wszShimName, pdwHookCount); } -/* PLDR_DATA_TABLE_ENTRY */ -BOOL WINAPI NotifyShims(DWORD fdwReason, PVOID P) +/* Forward to the generic implementation */ +BOOL WINAPI NotifyShims(DWORD fdwReason, PVOID ptr) { - return TRUE; + return ShimLib_NotifyShims(fdwReason, ptr); } BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) diff --git a/reactos/dll/appcompat/shims/layer/versionlie.c b/reactos/dll/appcompat/shims/layer/versionlie.c index f4305e40414..445e424d429 100644 --- a/reactos/dll/appcompat/shims/layer/versionlie.c +++ b/reactos/dll/appcompat/shims/layer/versionlie.c @@ -89,7 +89,6 @@ typedef BOOL(WINAPI* GETVERSIONEXAPROC)(LPOSVERSIONINFOEXA); #define SHIM_NS Win95VersionLie - #include DWORD WINAPI SHIM_OBJ_NAME(APIHook_GetVersion)() @@ -128,7 +127,6 @@ BOOL WINAPI SHIM_OBJ_NAME(APIHook_GetVersionExW)(LPOSVERSIONINFOEXA lpOsVersionI #define SHIM_NS Win98VersionLie - #include DWORD WINAPI SHIM_OBJ_NAME(APIHook_GetVersion)() diff --git a/reactos/dll/appcompat/shims/layer/versionlie.inl b/reactos/dll/appcompat/shims/layer/versionlie.inl index 1da8433a3d6..8e153f7a6f9 100644 --- a/reactos/dll/appcompat/shims/layer/versionlie.inl +++ b/reactos/dll/appcompat/shims/layer/versionlie.inl @@ -43,9 +43,9 @@ BOOL WINAPI SHIM_OBJ_NAME(APIHook_RtlGetVersion)(LPOSVERSIONINFOEXA lpOsVersionI return FALSE; } -BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason) +BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason, PVOID ptr) { - if (fdwReason == SHIM_REASON_ATTACH && VERSION_INFO.wServicePackMajor) + if (fdwReason == SHIM_NOTIFY_ATTACH && VERSION_INFO.wServicePackMajor) { static CONST WCHAR szServicePack[] = {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','%','u',0}; HRESULT hr = StringCbPrintfA(VERSION_INFO.szCSDVersionA, sizeof(VERSION_INFO.szCSDVersionA), diff --git a/reactos/dll/appcompat/shims/shimlib/CMakeLists.txt b/reactos/dll/appcompat/shims/shimlib/CMakeLists.txt index 77632b2978b..1b233162c0c 100644 --- a/reactos/dll/appcompat/shims/shimlib/CMakeLists.txt +++ b/reactos/dll/appcompat/shims/shimlib/CMakeLists.txt @@ -1,7 +1,11 @@ list(APPEND SOURCE + shimdbgsupp.c shimlib.c - shimlib.h) + shimlib.h + # These .inl functions are included so they show up in vs + setup_shim.inl + implement_shim.inl) add_library(shimlib ${SOURCE}) add_dependencies(shimlib xdk) diff --git a/reactos/dll/appcompat/shims/shimlib/implement_shim.inl b/reactos/dll/appcompat/shims/shimlib/implement_shim.inl index b75919f1176..186cdf87711 100644 --- a/reactos/dll/appcompat/shims/shimlib/implement_shim.inl +++ b/reactos/dll/appcompat/shims/shimlib/implement_shim.inl @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Shim library * FILE: dll/appcompat/shims/shimlib/implement_shim.inl - * PURPOSE: Shimlib helper file, used to register shims using the earlier prepared macro's + * PURPOSE: Shimlib helper file, used to register shims setup with macro's from setup_shim.inl * PROGRAMMER: Mark Jansen */ @@ -18,57 +18,56 @@ #error "setup_shim.inl should be included before this file!" #endif +#if SHIM_NUM_HOOKS > 0 #ifndef SHIM_SETUP_HOOKS #error "Please define a hook: #define SHIM_SETUP_HOOKS SHIM_HOOK(num, dll_name, function_name, your_function)" #endif +#else +#ifdef SHIM_SETUP_HOOKS +#error "Hooks are defined, yet SHIM_NUM_HOOKS is <= 0 !" +#endif +#endif -PHOOKAPI WINAPI SHIM_OBJ_NAME(InitializeHooksMulti)(DWORD fdwReason, PCSTR pszCmdLine, PDWORD pdwHookCount) +PHOOKAPI WINAPI SHIM_OBJ_NAME(GetHookAPIs)(DWORD fdwReason, PCSTR pszCmdLine, PDWORD pdwHookCount) { - if (fdwReason == SHIM_REASON_ATTACH) + if (pszCmdLine) { - if (pszCmdLine) - { - SHIM_OBJ_NAME(g_szCommandLine) = ShimLib_StringDuplicateA(pszCmdLine); - } - else - { - SHIM_OBJ_NAME(g_szCommandLine) = ""; - } - SHIM_OBJ_NAME(g_pAPIHooks) = ShimLib_ShimMalloc(sizeof(HOOKAPI) * SHIM_NUM_HOOKS); - ZeroMemory(SHIM_OBJ_NAME(g_pAPIHooks), sizeof(HOOKAPI) * SHIM_NUM_HOOKS); - *pdwHookCount = SHIM_NUM_HOOKS; + SHIM_OBJ_NAME(g_szCommandLine) = ShimLib_StringDuplicateA(pszCmdLine); } + else + { + SHIM_OBJ_NAME(g_szCommandLine) = ""; + } + SHIM_OBJ_NAME(g_pAPIHooks) = ShimLib_ShimMalloc(sizeof(HOOKAPI) * SHIM_NUM_HOOKS); + ZeroMemory(SHIM_OBJ_NAME(g_pAPIHooks), sizeof(HOOKAPI) * SHIM_NUM_HOOKS); + *pdwHookCount = SHIM_NUM_HOOKS; #ifdef SHIM_NOTIFY_FN - if (!SHIM_NOTIFY_FN(fdwReason) && fdwReason == SHIM_REASON_ATTACH) + if (!SHIM_NOTIFY_FN(fdwReason, NULL)) return NULL; #endif - if (fdwReason == SHIM_REASON_ATTACH) - { - SHIM_SETUP_HOOKS - } +#if SHIM_NUM_HOOKS > 0 + SHIM_SETUP_HOOKS +#endif return SHIM_OBJ_NAME(g_pAPIHooks); } -PVOID SHIM_OBJ_NAME(FindShim)(PCWSTR wszString) -{ - PCSTR szString = SHIM_OBJ_NAME(g_szModuleName); - while (*szString == *wszString) - { - if (!*szString) - return SHIM_OBJ_NAME(InitializeHooksMulti); - szString++; wszString++; - } - return NULL; -} - #if defined(_MSC_VER) #pragma section(".shm$BBB",long,read) #endif -_SHMALLOC(".shm$BBB") _PVSHIM SHIM_OBJ_NAME(_shim_fn) = SHIM_OBJ_NAME(FindShim); +_SHMALLOC(".shm$BBB") SHIMREG SHIM_OBJ_NAME(_shim_fn) = +{ + SHIM_OBJ_NAME(GetHookAPIs), +#ifdef SHIM_NOTIFY_FN + SHIM_NOTIFY_FN, +#else + NULL, +#endif + SHIM_STRINGIFY(SHIM_NS) +}; #undef SHIM_SETUP_HOOKS #undef SHIM_NOTIFY_FN diff --git a/reactos/dll/appcompat/shims/shimlib/setup_shim.inl b/reactos/dll/appcompat/shims/shimlib/setup_shim.inl index aa366a287b6..cb87b65a31b 100644 --- a/reactos/dll/appcompat/shims/shimlib/setup_shim.inl +++ b/reactos/dll/appcompat/shims/shimlib/setup_shim.inl @@ -19,13 +19,15 @@ #define SHIM_STRINGIFY2(X_) # X_ #define SHIM_STRINGIFY(X_) SHIM_STRINGIFY2(X_) +/* TODO: static_assert on (num < SHIM_NUM_HOOKS) */ + #define SHIM_HOOK(num, dll, function, target) \ SHIM_OBJ_NAME(g_pAPIHooks)[num].LibraryName = dll; \ SHIM_OBJ_NAME(g_pAPIHooks)[num].FunctionName = function; \ SHIM_OBJ_NAME(g_pAPIHooks)[num].ReplacementFunction = target; \ SHIM_OBJ_NAME(g_pAPIHooks)[num].OriginalFunction = NULL; \ - SHIM_OBJ_NAME(g_pAPIHooks)[num].Unk1 = NULL; \ - SHIM_OBJ_NAME(g_pAPIHooks)[num].Unk2 = NULL; + SHIM_OBJ_NAME(g_pAPIHooks)[num].Reserved[0] = NULL; \ + SHIM_OBJ_NAME(g_pAPIHooks)[num].Reserved[1] = NULL; #define CALL_SHIM(SHIM_NUM, SHIM_CALLCONV) \ ((SHIM_CALLCONV)(SHIM_OBJ_NAME(g_pAPIHooks)[SHIM_NUM].OriginalFunction)) diff --git a/reactos/dll/appcompat/shims/shimlib/shimdbgsupp.c b/reactos/dll/appcompat/shims/shimlib/shimdbgsupp.c new file mode 100644 index 00000000000..7861ec705b9 --- /dev/null +++ b/reactos/dll/appcompat/shims/shimlib/shimdbgsupp.c @@ -0,0 +1,79 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Shim library + * FILE: dll/appcompat/shims/shimlib/shimdbgsupp.c + * PURPOSE: Shim debug helper functions + * PROGRAMMER: Mark Jansen + */ + +#include +#include +#include +#include + +#include "wine/winternl.h" + +#define DPFLTR_APPCOMPAT_ID 123 + +void ApphelppInitDebugSupport(PCWSTR KeyName, PULONG Level); +static void SeiInitDebugSupport() +{ + ApphelppInitDebugSupport(L"SHIMENG_DEBUG_LEVEL", &g_ShimEngDebugLevel); +} + + +/** + * Outputs diagnostic info. + * + * @param [in] Level The level to log this message with, choose any of [SHIM_ERR, + * SHIM_WARN, SHIM_INFO]. + * @param [in] FunctionName The function this log should be attributed to. + * @param [in] Format The format string. + * @param ... Variable arguments providing additional information. + * + * @return Success: TRUE Failure: FALSE. + */ +BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...) +{ + char Buffer[512]; + va_list ArgList; + char* Current = Buffer; + const char* LevelStr; + size_t Length = sizeof(Buffer); + + if (g_ShimEngDebugLevel == 0xffffffff) + SeiInitDebugSupport(); + + if (Level > g_ShimEngDebugLevel) + return FALSE; + + switch (Level) + { + case SEI_ERR: + LevelStr = "Err "; + Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL); + break; + case SEI_WARN: + LevelStr = "Warn"; + Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL); + break; + case SEI_INFO: + LevelStr = "Info"; + Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL); + break; + default: + LevelStr = "User"; + Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL); + break; + } + StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName); + va_start(ArgList, Format); + StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList); + va_end(ArgList); +#if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX + return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer)); +#else + OutputDebugStringA(Buffer); + return TRUE; +#endif +} diff --git a/reactos/dll/appcompat/shims/shimlib/shimlib.c b/reactos/dll/appcompat/shims/shimlib/shimlib.c index 7720305ff27..65aed846a56 100644 --- a/reactos/dll/appcompat/shims/shimlib/shimlib.c +++ b/reactos/dll/appcompat/shims/shimlib/shimlib.c @@ -11,13 +11,25 @@ #include #include -HINSTANCE g_hinstDll; +typedef struct UsedShim +{ + SLIST_ENTRY Entry; + PSHIMREG pShim; +#if (WINVER > _WIN32_WINNT_WS03) + BOOL bInitCalled; +#endif +} UsedShim, *pUsedShim; + + static HANDLE g_ShimLib_Heap; +static PSLIST_HEADER g_UsedShims; void ShimLib_Init(HINSTANCE hInstance) { - g_hinstDll = hInstance; g_ShimLib_Heap = HeapCreate(0, 0x10000, 0); + + g_UsedShims = (PSLIST_HEADER)ShimLib_ShimMalloc(sizeof(SLIST_HEADER)); + RtlInitializeSListHead(g_UsedShims); } void ShimLib_Deinit() @@ -43,6 +55,18 @@ PCSTR ShimLib_StringDuplicateA(PCSTR szString) return lstrcpyA(NewString, szString); } +BOOL ShimLib_StrAEqualsW(PCSTR szString, PCWSTR wszString) +{ + while (*szString == *wszString) + { + if (!*szString) + return TRUE; + + szString++; wszString++; + } + return FALSE; +} + #if defined(_MSC_VER) #if defined(_M_IA64) || defined(_M_AMD64) @@ -62,8 +86,8 @@ PCSTR ShimLib_StringDuplicateA(PCSTR szString) #endif -_SHMALLOC(".shm") _PVSHIM _shim_start = 0; -_SHMALLOC(".shm$ZZZ") _PVSHIM _shim_end = 0; +_SHMALLOC(".shm") SHIMREG _shim_start = { 0 }; +_SHMALLOC(".shm$ZZZ") SHIMREG _shim_end = { 0 }; /* Generic GetHookAPIs function. @@ -72,21 +96,53 @@ _SHMALLOC(".shm$ZZZ") _PVSHIM _shim_end = 0; This helper function will return the correct shim, and call the init function */ PHOOKAPI WINAPI ShimLib_GetHookAPIs(IN LPCSTR szCommandLine, IN LPCWSTR wszShimName, OUT PDWORD pdwHookCount) { - uintptr_t ps = (uintptr_t)&_shim_start; - ps += sizeof(uintptr_t); - for (; ps != (uintptr_t)&_shim_end; ps += sizeof(uintptr_t)) + PSHIMREG ps = &_shim_start; + ps++; + for (; ps != &_shim_end; ps++) { - _PVSHIM* pfunc = (_PVSHIM *)ps; - if (*pfunc != NULL) + if (ps->GetHookAPIs != NULL && ps->ShimName != NULL) { - PVOID res = (*pfunc)(wszShimName); - if (res) + if (ShimLib_StrAEqualsW(ps->ShimName, wszShimName)) { - PHOOKAPI (WINAPI* PFN)(DWORD, PCSTR, PDWORD) = res; - return (*PFN)(SHIM_REASON_ATTACH, szCommandLine, pdwHookCount); + pUsedShim shim = (pUsedShim)ShimLib_ShimMalloc(sizeof(UsedShim)); + shim->pShim = ps; +#if (WINVER > _WIN32_WINNT_WS03) + shim->bInitCalled = FALSE; +#endif + RtlInterlockedPushEntrySList(g_UsedShims, &(shim->Entry)); + + return ps->GetHookAPIs(SHIM_NOTIFY_ATTACH, szCommandLine, pdwHookCount); } } } return NULL; } + +BOOL WINAPI ShimLib_NotifyShims(DWORD fdwReason, PVOID ptr) +{ + PSLIST_ENTRY pEntry = RtlFirstEntrySList(g_UsedShims); + + if (fdwReason < SHIM_REASON_INIT) + fdwReason += (SHIM_REASON_INIT - SHIM_NOTIFY_ATTACH); + + while (pEntry) + { + pUsedShim pUsed = CONTAINING_RECORD(pEntry, UsedShim, Entry); + _PVNotify Notify = pUsed->pShim->Notify; +#if (WINVER > _WIN32_WINNT_WS03) + if (pUsed->bInitCalled && fdwReason == SHIM_REASON_INIT) + Notify = NULL; +#endif + if (Notify) + Notify(fdwReason, ptr); +#if (WINVER > _WIN32_WINNT_WS03) + if (fdwReason == SHIM_REASON_INIT) + pUsed->bInitCalled = TRUE; +#endif + + pEntry = pEntry->Next; + } + + return TRUE; +} diff --git a/reactos/dll/appcompat/shims/shimlib/shimlib.h b/reactos/dll/appcompat/shims/shimlib/shimlib.h index 59e325d7a11..d7926f59e1a 100644 --- a/reactos/dll/appcompat/shims/shimlib/shimlib.h +++ b/reactos/dll/appcompat/shims/shimlib/shimlib.h @@ -8,32 +8,71 @@ #pragma once -typedef struct tagHOOKAPI { +typedef struct tagHOOKAPI +{ PCSTR LibraryName; PCSTR FunctionName; PVOID ReplacementFunction; PVOID OriginalFunction; - PVOID Unk1; - PVOID Unk2; + PVOID Reserved[2]; } HOOKAPI, *PHOOKAPI; -extern HINSTANCE g_hinstDll; -void ShimLib_Init(HINSTANCE); -void ShimLib_Deinit(void); PVOID ShimLib_ShimMalloc(SIZE_T); void ShimLib_ShimFree(PVOID); PCSTR ShimLib_StringDuplicateA(PCSTR); +BOOL ShimLib_StrAEqualsW(PCSTR, PCWSTR); + + +/* Forward events to generic handlers */ +void ShimLib_Init(HINSTANCE); +void ShimLib_Deinit(void); PHOOKAPI WINAPI ShimLib_GetHookAPIs(LPCSTR,LPCWSTR,PDWORD); +BOOL WINAPI ShimLib_NotifyShims(DWORD fdwReason, PVOID ptr); -#define SHIM_REASON_ATTACH 1 -#define SHIM_REASON_DETACH 2 -#define SHIM_REASON_DLL_LOAD 3 /* Arg: PLDR_DATA_TABLE_ENTRY */ -#define SHIM_REASON_DLL_UNLOAD 4 /* Arg: Module Handle */ +/* Shims should respond to SHIM_REASON_XXXX in the Notify routines. + SHIM_NOTIFY_ codes are sent by apphelp, and translated to SHIM_REASON_ by the shimlib routines. + The only exception being SHIM_NOTIFY_ATTACH, that is also set for one-time init. + */ + +#define SHIM_REASON_INIT 100 +#define SHIM_REASON_DEINIT 101 +#define SHIM_REASON_DLL_LOAD 102 /* Arg: PLDR_DATA_TABLE_ENTRY */ +#define SHIM_REASON_DLL_UNLOAD 103 /* Arg: PLDR_DATA_TABLE_ENTRY */ + +#define SHIM_NOTIFY_ATTACH 1 +#define SHIM_NOTIFY_DETACH 2 +#define SHIM_NOTIFY_DLL_LOAD 3 /* Arg: PLDR_DATA_TABLE_ENTRY */ +#define SHIM_NOTIFY_DLL_UNLOAD 4 /* Arg: PLDR_DATA_TABLE_ENTRY */ -typedef PVOID (__cdecl *_PVSHIM)(PCWSTR); + +typedef enum _SEI_LOG_LEVEL { + SEI_ERR = 1, + SEI_WARN = 2, + SEI_INFO = 3, +} SEI_LOG_LEVEL; + +BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...); +extern ULONG g_ShimEngDebugLevel; + +#define SHIMENG_ERR(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_ERR, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0) +#define SHIMENG_WARN(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_WARN, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0) +#define SHIMENG_INFO(fmt, ...) do { if (g_ShimEngDebugLevel) SeiDbgPrint(SEI_INFO, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0) + + + +typedef PHOOKAPI (WINAPI* _PVGetHookAPIs)(DWORD, PCSTR, PDWORD); +typedef BOOL (WINAPI* _PVNotify)(DWORD, PVOID); + +typedef struct tagSHIMREG +{ + _PVGetHookAPIs GetHookAPIs; + _PVNotify Notify; + PCSTR ShimName; +} SHIMREG, *PSHIMREG; + #if defined(_MSC_VER) #define _SHMALLOC(x) __declspec(allocate(x))