[SHIMLIB] Shim helper functions keep a list of used shims, so that events can be...
authorMark Jansen <mark.jansen@reactos.org>
Fri, 16 Dec 2016 19:18:26 +0000 (19:18 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Fri, 16 Dec 2016 19:18:26 +0000 (19:18 +0000)
svn path=/trunk/; revision=73461

reactos/dll/appcompat/shims/layer/main.c
reactos/dll/appcompat/shims/layer/versionlie.c
reactos/dll/appcompat/shims/layer/versionlie.inl
reactos/dll/appcompat/shims/shimlib/CMakeLists.txt
reactos/dll/appcompat/shims/shimlib/implement_shim.inl
reactos/dll/appcompat/shims/shimlib/setup_shim.inl
reactos/dll/appcompat/shims/shimlib/shimdbgsupp.c [new file with mode: 0644]
reactos/dll/appcompat/shims/shimlib/shimlib.c
reactos/dll/appcompat/shims/shimlib/shimlib.h

index ac494f3..cfdad2b 100644 (file)
@@ -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)
index f4305e4..445e424 100644 (file)
@@ -89,7 +89,6 @@ typedef BOOL(WINAPI* GETVERSIONEXAPROC)(LPOSVERSIONINFOEXA);
 
 
 #define SHIM_NS         Win95VersionLie
-
 #include <setup_shim.inl>
 
 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 <setup_shim.inl>
 
 DWORD WINAPI SHIM_OBJ_NAME(APIHook_GetVersion)()
index 1da8433..8e153f7 100644 (file)
@@ -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),
index 77632b2..1b23316 100644 (file)
@@ -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)
index b75919f..186cdf8 100644 (file)
@@ -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
  */
 
 #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)
+    {
+        SHIM_OBJ_NAME(g_szCommandLine) = ShimLib_StringDuplicateA(pszCmdLine);
+    }
+    else
     {
-        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) = "";
     }
+    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
index aa366a2..cb87b65 100644 (file)
 #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 (file)
index 0000000..7861ec7
--- /dev/null
@@ -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 <windef.h>
+#include <winbase.h>
+#include <shimlib.h>
+#include <strsafe.h>
+
+#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
+}
index 7720305..65aed84 100644 (file)
 #include <shimlib.h>
 #include <strsafe.h>
 
-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;
+}
index 59e325d..d7926f5 100644 (file)
@@ -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);
+
+
+/* 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 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)
+
 
 
-#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 */
+typedef PHOOKAPI (WINAPI* _PVGetHookAPIs)(DWORD, PCSTR, PDWORD);
+typedef BOOL (WINAPI* _PVNotify)(DWORD, PVOID);
 
+typedef struct tagSHIMREG
+{
+    _PVGetHookAPIs GetHookAPIs;
+    _PVNotify Notify;
+    PCSTR ShimName;
+} SHIMREG, *PSHIMREG;
 
-typedef PVOID (__cdecl *_PVSHIM)(PCWSTR);
 
 #if defined(_MSC_VER)
 #define _SHMALLOC(x) __declspec(allocate(x))