windows-nt/Source/XPSP1/NT/windows/published/shimhookmacro.w
2020-09-26 16:20:57 +08:00

502 lines
30 KiB
OpenEdge ABL

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
ShimHookMacro.h
Abstract:
Shim hooking macros for version 2
Notes:
None
History:
10/29/2000 markder Created
12/06/2000 robkenny Converted to use namespaces
09/11/2001 mnikkel Modified DPFN and LOGN to retain LastError
--*/
#pragma once
#ifndef _ShimHookMacro_h_
#define _ShimHookMacro_h_
//
// These are dwReason values that the shim notification functions
// can be called with.
//
//
// This means that all the static linked DLLs have run their init routines.
//
#define SHIM_STATIC_DLLS_INITIALIZED 100
//
// This means that the current process is about to die.
// This gives the shims a chance to do cleanup work while all the modules
// are still loaded.
//
#define SHIM_PROCESS_DYING 101
//
// This notification is sent to notify the shims that a DLL is unloading
//
#define SHIM_DLL_LOADING 102
extern PLDR_DATA_TABLE_ENTRY g_DllLoadingEntry;
#define GETDLLLOADINGHANDLE() (g_DllLoadingEntry)
//
// This debug macro needs to be in this file because it needs access
// to g_szModuleName which is only defined inside the namespace.
//
inline void DPFN(ShimLib::DEBUGLEVEL dwDetail, LPCSTR pszFmt, ...)
{
#if DBG
// This must be the first line of this routine to preserve LastError.
DWORD dwLastError = GetLastError();
extern const CHAR * g_szModuleName; // created by the DECLARE_SHIM macro, inside of the shim's namespace
va_list vaArgList;
va_start(vaArgList, pszFmt);
ShimLib::DebugPrintfList(g_szModuleName, dwDetail, pszFmt, vaArgList);
va_end(vaArgList);
// This must be the last line of this routine to preserve LastError.
SetLastError(dwLastError);
#else
dwDetail;
pszFmt;
#endif
}
inline void LOGN(ShimLib::DEBUGLEVEL dwDetail, LPCSTR pszFmt, ...)
{
// This must be the first line of this routine to preserve LastError.
DWORD dwLastError = GetLastError();
extern const CHAR * g_szModuleName;
if (ShimLib::g_bFileLogEnabled)
{
va_list vaArgList;
va_start(vaArgList, pszFmt);
ShimLib::ShimLogList(g_szModuleName, dwDetail, pszFmt, vaArgList);
va_end(vaArgList);
}
#if DBG
// If logging isn't enabled, dump to the debugger
else
{
va_list vaArgList;
va_start(vaArgList, pszFmt);
ShimLib::DebugPrintfList(g_szModuleName, dwDetail, pszFmt, vaArgList);
va_end(vaArgList);
}
#endif
// This must be the last line of this routine to preserve LastError.
SetLastError(dwLastError);
}
#define APIHOOK(hook) APIHook_##hook
#define COMHOOK(iface, hook) COMHook_##iface##_##hook
#define APIHOOK_ENUM_BEGIN enum {
#define APIHOOK_ENUM_ENTRY(hook) APIHOOK_##hook##,
#define APIHOOK_ENUM_ENTRY_COMSERVER(module) APIHOOK_##module##_DllGetClassObject,
#define APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER() \
APIHOOK_ENUM_ENTRY_COMSERVER(DDRAW) \
APIHOOK_ENUM_ENTRY_COMSERVER(DSOUND) \
APIHOOK_ENUM_ENTRY_COMSERVER(DPLAYX) \
APIHOOK_ENUM_ENTRY_COMSERVER(DINPUT) \
APIHOOK_ENUM_ENTRY(DirectDrawCreate) \
APIHOOK_ENUM_ENTRY(DirectDrawCreateEx) \
APIHOOK_ENUM_ENTRY(DirectSoundCreate) \
APIHOOK_ENUM_ENTRY(DirectPlayCreate) \
APIHOOK_ENUM_ENTRY(DirectInputCreateA) \
APIHOOK_ENUM_ENTRY(DirectInputCreateW) \
APIHOOK_ENUM_ENTRY(DirectInputCreateEx)
#define APIHOOK_ENUM_END APIHOOK_Count };
#define HOOK_BEGIN \
PHOOKAPI \
InitializeHooksMulti( \
DWORD fdwReason, \
LPSTR pszCmdLine, \
DWORD* pdwHookCount \
) \
{ \
DPFN(eDbgLevelSpew, \
"[InitializeHooksMulti] fdwReason(%d) pszCmdLine(%s)\n", \
fdwReason, pszCmdLine); \
\
if (fdwReason == DLL_PROCESS_ATTACH) { \
lstrcpynA( g_szCommandLine, pszCmdLine, SHIM_COMMAND_LINE_MAX_BUFFER); \
\
g_pAPIHooks = \
(PHOOKAPI) ShimMalloc(sizeof(HOOKAPI)*APIHOOK_Count); \
if (g_pAPIHooks == NULL) { \
return NULL; \
} \
*pdwHookCount = APIHOOK_Count; \
}
#define HOOK_END \
if (fdwReason == DLL_PROCESS_ATTACH) { \
DPFN(eDbgLevelSpew, \
"[InitializeHooksMulti] pdwHookCount(%d)\n", \
pdwHookCount ? *pdwHookCount : 0); \
} \
return g_pAPIHooks; \
}
#define APIHOOK_ENTRY(module, hook) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
g_pAPIHooks[APIHOOK_##hook##].pszModule = #module; \
g_pAPIHooks[APIHOOK_##hook##].pszFunctionName = #hook; \
g_pAPIHooks[APIHOOK_##hook##].pfnNew = APIHOOK(hook); \
}
#define APIHOOK_ENTRY_NAME(module, hook, hookname) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
g_pAPIHooks[APIHOOK_##hook##].pszModule = #module; \
g_pAPIHooks[APIHOOK_##hook##].pszFunctionName = #hookname; \
g_pAPIHooks[APIHOOK_##hook##].pfnNew = APIHOOK(hook); \
}
#define APIHOOK_ENTRY_ORD(module, hook, hookord) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
g_pAPIHooks[APIHOOK_##hook##].pszModule = #module; \
g_pAPIHooks[APIHOOK_##hook##].pszFunctionName = (char *)IntToPtr(hookord); \
g_pAPIHooks[APIHOOK_##hook##].pfnNew = APIHOOK(hook); \
}
#define APIHOOK_ENTRY_COMSERVER(module) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pszModule = #module ".DLL"; \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pszFunctionName = "DllGetClassObject"; \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pfnNew = APIHOOK(module##_DllGetClassObject); \
}
#define APIHOOK_ENTRY_DIRECTX_COMSERVER() \
if (fdwReason == DLL_PROCESS_ATTACH) { \
APIHOOK_ENTRY_COMSERVER(DDRAW) \
APIHOOK_ENTRY_COMSERVER(DSOUND) \
APIHOOK_ENTRY_COMSERVER(DPLAYX) \
APIHOOK_ENTRY_COMSERVER(DINPUT) \
APIHOOK_ENTRY(DDRAW.DLL, DirectDrawCreate) \
APIHOOK_ENTRY(DDRAW.DLL, DirectDrawCreateEx) \
APIHOOK_ENTRY(DSOUND.DLL, DirectSoundCreate) \
APIHOOK_ENTRY(DPLAYX.DLL, DirectPlayCreate) \
APIHOOK_ENTRY(DINPUT.DLL, DirectInputCreateA) \
APIHOOK_ENTRY(DINPUT.DLL, DirectInputCreateW) \
APIHOOK_ENTRY(DINPUT.DLL, DirectInputCreateEx) \
}
#define COMHOOK_ENTRY(obj, iface, hook, vtblndx) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
AddComHook(CLSID_##obj, IID_##iface, COMHOOK(iface, hook), vtblndx); \
}
#define DECLARE_SHIM(shim) \
namespace NS_##shim \
{ \
const CHAR * g_szModuleName = #shim; \
CHAR g_szCommandLine[SHIM_COMMAND_LINE_MAX_BUFFER]; \
PHOOKAPI g_pAPIHooks = NULL; \
BOOL g_bSubshimUsed = FALSE; \
extern PHOOKAPI InitializeHooksMulti(DWORD, LPSTR, DWORD*); \
};
#define MULTISHIM_BEGIN() \
VOID ShimLib::InitializeHooks(DWORD) \
{ \
g_dwShimVersion = 2; \
} \
PHOOKAPI ShimLib::InitializeHooksEx(DWORD fdwReason, LPWSTR pwszShim, LPSTR pszCmdLine, DWORD* pdwHookCount) \
{ \
PHOOKAPI pAPIHooks = NULL; \
g_bMultiShim = TRUE;
#define MULTISHIM_ENTRY(shim) \
if ((fdwReason == DLL_PROCESS_ATTACH && pwszShim != NULL && 0 == _wcsicmp( pwszShim, L#shim )) || \
(fdwReason == DLL_PROCESS_DETACH && NS_##shim::g_bSubshimUsed) || \
(fdwReason == SHIM_PROCESS_DYING && NS_##shim::g_bSubshimUsed) || \
(fdwReason == SHIM_DLL_LOADING && NS_##shim::g_bSubshimUsed) || \
(fdwReason == SHIM_STATIC_DLLS_INITIALIZED && NS_##shim::g_bSubshimUsed)) { \
NS_##shim::g_bSubshimUsed = TRUE; \
pAPIHooks = NS_##shim::InitializeHooksMulti( fdwReason, pszCmdLine, pdwHookCount ); \
}
#define MULTISHIM_END() \
return pAPIHooks; \
}
#define MULTISHIM_NOTIFY_FUNCTION() NotifyFn
#define NOTIFY_FUNCTION NotifyFn
#define CALL_MULTISHIM_NOTIFY_FUNCTION() NotifyFn(fdwReason);
#define CALL_NOTIFY_FUNCTION \
if (FALSE == NotifyFn(fdwReason) && \
fdwReason == DLL_PROCESS_ATTACH) { \
*pdwHookCount = 0; \
DPFN(eDbgLevelSpew, \
"[InitializeHooksMulti] NotifyFn returned FALSE, fail load shim\n", \
g_pAPIHooks); \
return NULL; \
}
#define ORIGINAL_API(hook) \
(*(_pfn_##hook##)(g_pAPIHooks[APIHOOK_##hook##].pfnOld))
#define _ORIGINAL_API(hook, proto) \
(*(_pfn_##proto##)(g_pAPIHooks[APIHOOK_##hook##].pfnOld))
#define ORIGINAL_COM(iface, hook, pThis) \
(*(_pfn_##iface##_##hook##)(LookupOriginalCOMFunction(*((PVOID *) pThis), COMHOOK(iface, hook), TRUE )))
#define COMMAND_LINE \
(g_szCommandLine)
#define IMPLEMENT_COMSERVER_HOOK(module) \
HRESULT \
APIHOOK(##module##_DllGetClassObject)( \
REFCLSID rclsid, \
REFIID riid, \
LPVOID * ppv \
) \
{ \
HRESULT hrReturn = E_FAIL; \
\
hrReturn = _ORIGINAL_API(module##_DllGetClassObject, DllGetClassObject)( \
rclsid, riid, ppv); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(rclsid, riid, ppv, TRUE); \
} \
\
return hrReturn; \
}
#define IMPLEMENT_DIRECTX_COMSERVER_HOOKS() \
IMPLEMENT_COMSERVER_HOOK(DDRAW) \
IMPLEMENT_COMSERVER_HOOK(DSOUND) \
IMPLEMENT_COMSERVER_HOOK(DPLAYX) \
IMPLEMENT_COMSERVER_HOOK(DINPUT) \
\
HRESULT \
APIHOOK(DirectDrawCreate)( \
IN GUID FAR *lpGUID, \
OUT LPVOID *lplpDD, \
OUT IUnknown* pUnkOuter \
) \
{ \
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectDrawCreate)(lpGUID, lplpDD, pUnkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectDraw, IID_IDirectDraw, lplpDD, FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectDrawCreateEx)( \
GUID FAR *lpGUID, \
LPVOID *lplpDD, \
REFIID iid, \
IUnknown* pUnkOuter \
) \
{ \
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectDrawCreateEx)( \
lpGUID, \
lplpDD, \
iid, \
pUnkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectDraw, iid, lplpDD, FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectSoundCreate)( \
LPCGUID lpcGuid, \
LPDIRECTSOUND *ppDS, \
LPUNKNOWN pUnkOuter) \
{ \
\
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectSoundCreate)( \
lpcGuid, \
ppDS, \
pUnkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectSound, \
IID_IDirectSound, \
(LPVOID*) ppDS, \
FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectPlayCreate)( \
LPGUID lpGUIDSP, \
LPDIRECTPLAY FAR *lplpDP, \
IUnknown *lpUnk) \
{ \
\
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectPlayCreate)( \
lpGUIDSP, \
lplpDP, \
lpUnk); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectPlay, \
IID_IDirectPlay, \
(LPVOID*) lplpDP, \
FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectInputCreateA)( \
HINSTANCE hinst, \
DWORD dwVersion, \
LPDIRECTINPUTA * lplpDirectInput, \
LPUNKNOWN punkOuter) \
{ \
\
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectInputCreateA)( \
hinst, \
dwVersion, \
lplpDirectInput, \
punkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectInput, \
IID_IDirectInputA, \
(LPVOID*) lplpDirectInput, \
FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectInputCreateW)( \
HINSTANCE hinst, \
DWORD dwVersion, \
LPDIRECTINPUTW * lplpDirectInput, \
LPUNKNOWN punkOuter) \
{ \
\
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectInputCreateW)( \
hinst, \
dwVersion, \
lplpDirectInput, \
punkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectInput, \
IID_IDirectInputW, \
(LPVOID*) lplpDirectInput, \
FALSE); \
} \
\
return hrReturn; \
} \
\
HRESULT \
APIHOOK(DirectInputCreateEx)( \
HINSTANCE hinst, \
DWORD dwVersion, \
REFIID riidltf, \
LPVOID * ppvOut, \
LPUNKNOWN punkOuter) \
{ \
\
HRESULT hrReturn = E_FAIL; \
\
hrReturn = ORIGINAL_API(DirectInputCreateEx)( \
hinst, \
dwVersion, \
riidltf, \
ppvOut, \
punkOuter); \
\
if (S_OK == hrReturn) { \
HookCOMInterface(CLSID_DirectInput, \
riidltf, \
(LPVOID*) ppvOut, \
FALSE); \
} \
\
return hrReturn; \
}
// Only add this hook to the list if bDeclare is TRUE
// otherwise a blank entry is added.
#define APIHOOK_ENTRY_OR_NOT(bDeclare, module, hook) \
if (bDeclare) { \
APIHOOK_ENTRY(module, hook) \
}
// Only add this hook to the list if bDeclare is TRUE
// otherwise a blank entry is added.
#define APIHOOK_ENTRY_COMSERVER_OR_NOT(bDeclare, module) \
if (bDeclare) { \
APIHOOK_ENTRY_COMSERVER(module) \
} else { \
APIHOOK_ENTRY_COMSERVER_BLANK(module) \
}
#define APIHOOK_ENTRY_COMSERVER_BLANK(module) \
if (fdwReason == DLL_PROCESS_ATTACH) { \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pszModule = ""; \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pszFunctionName = ""; \
g_pAPIHooks[APIHOOK_##module##_DllGetClassObject].pfnNew = NULL; \
}
#endif // _SHIMHOOKMACRO_H_