331 lines
6.7 KiB
C++
331 lines
6.7 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ClueFinders3rdGrade.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This shim simulates the behaviour of Win9x wrt static controls and
|
||
|
Get/SetWindowText. Basically, Win9x stored the resource id for a static
|
||
|
control in it's name. On NT, this isn't stored.
|
||
|
|
||
|
We used to set a low-level window hook that catches the CreateWindow calls,
|
||
|
but gave up because it kept regressing and it would be too expensive for
|
||
|
the layer.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
This is an app specific shim.
|
||
|
|
||
|
History:
|
||
|
|
||
|
06/19/2000 linstev Created
|
||
|
11/17/2000 linstev Made app specific
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
IMPLEMENT_SHIM_BEGIN(ClueFinders3rdGrade)
|
||
|
#include "ShimHookMacro.h"
|
||
|
|
||
|
APIHOOK_ENUM_BEGIN
|
||
|
APIHOOK_ENUM_ENTRY(GetWindowTextA)
|
||
|
APIHOOK_ENUM_ENTRY(SetWindowTextA)
|
||
|
APIHOOK_ENUM_ENTRY(CreateDialogIndirectParamA)
|
||
|
APIHOOK_ENUM_END
|
||
|
|
||
|
typedef HMODULE (*_pfn_GetModuleHandleA)(LPCSTR lpModuleName);
|
||
|
|
||
|
//
|
||
|
// List of static handles
|
||
|
//
|
||
|
|
||
|
struct HWNDITEM
|
||
|
{
|
||
|
HWND hWnd;
|
||
|
DWORD dwRsrcId;
|
||
|
HWNDITEM *next;
|
||
|
};
|
||
|
HWNDITEM *g_hWndList = NULL;
|
||
|
|
||
|
//
|
||
|
// Handle to use for CallNextHook
|
||
|
//
|
||
|
|
||
|
HHOOK g_hHookCbt = 0;
|
||
|
|
||
|
//
|
||
|
// Critical section for list access
|
||
|
//
|
||
|
|
||
|
CRITICAL_SECTION g_csList;
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Search the window list for a resource id if GetWindowTextA fails.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
int
|
||
|
APIHOOK(GetWindowTextA)(
|
||
|
HWND hWnd,
|
||
|
LPSTR lpString,
|
||
|
int nMaxCount
|
||
|
)
|
||
|
{
|
||
|
int iRet = ORIGINAL_API(GetWindowTextA)(
|
||
|
hWnd,
|
||
|
lpString,
|
||
|
nMaxCount);
|
||
|
|
||
|
if (iRet == 0) {
|
||
|
//
|
||
|
// Check for Resource Id
|
||
|
//
|
||
|
|
||
|
EnterCriticalSection(&g_csList);
|
||
|
|
||
|
HWNDITEM *hitem = g_hWndList;
|
||
|
while (hitem) {
|
||
|
if (hitem->hWnd == hWnd) {
|
||
|
//
|
||
|
// Copy the resource id into the buffer
|
||
|
//
|
||
|
|
||
|
if ((hitem->dwRsrcId != (DWORD)-1) && (nMaxCount >= 3)) {
|
||
|
MoveMemory(lpString, (LPBYTE) &hitem->dwRsrcId + 1, 3);
|
||
|
iRet = 2;
|
||
|
|
||
|
DPFN( eDbgLevelError, "Returning ResourceId: %08lx for HWND=%08lx", *(LPDWORD)lpString, hWnd);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
hitem = hitem->next;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&g_csList);
|
||
|
}
|
||
|
|
||
|
return iRet;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hook SetWindowText so the list is kept in sync.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
APIHOOK(SetWindowTextA)(
|
||
|
HWND hWnd,
|
||
|
LPCSTR lpString
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Set the text for this window if it's in our list
|
||
|
//
|
||
|
|
||
|
EnterCriticalSection(&g_csList);
|
||
|
|
||
|
HWNDITEM *hitem = g_hWndList;
|
||
|
while (hitem) {
|
||
|
if (hitem->hWnd == hWnd) {
|
||
|
if (lpString && (*(LPBYTE) lpString == 0xFF)) {
|
||
|
hitem->dwRsrcId = *(LPDWORD) lpString;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hitem = hitem->next;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&g_csList);
|
||
|
|
||
|
return ORIGINAL_API(SetWindowTextA)(hWnd, lpString);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hook to find CreateWindow calls and get the attached resource id.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
LRESULT
|
||
|
CALLBACK
|
||
|
CBTProcW(
|
||
|
int nCode,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
HWND hWnd = (HWND) wParam;
|
||
|
LPCBT_CREATEWNDW pCbtWnd;
|
||
|
|
||
|
switch (nCode) {
|
||
|
case HCBT_CREATEWND:
|
||
|
|
||
|
//
|
||
|
// Add to our list of windows if it's a static - or we don't know
|
||
|
//
|
||
|
|
||
|
pCbtWnd = (LPCBT_CREATEWNDW) lParam;
|
||
|
|
||
|
if (pCbtWnd && pCbtWnd->lpcs && pCbtWnd->lpcs->lpszClass &&
|
||
|
(IsBadReadPtr(pCbtWnd->lpcs->lpszClass, 4) ||
|
||
|
(_wcsicmp(pCbtWnd->lpcs->lpszClass, L"static") == 0))) {
|
||
|
HWNDITEM *hitem = (HWNDITEM *) malloc(sizeof(HWNDITEM));
|
||
|
|
||
|
if (hitem) {
|
||
|
hitem->hWnd = hWnd;
|
||
|
|
||
|
//
|
||
|
// Check for a resource id in the name
|
||
|
//
|
||
|
|
||
|
if (pCbtWnd->lpcs->lpszName &&
|
||
|
(*(LPBYTE) pCbtWnd->lpcs->lpszName == 0xFF)) {
|
||
|
hitem->dwRsrcId = *(LPDWORD) pCbtWnd->lpcs->lpszName;
|
||
|
} else {
|
||
|
hitem->dwRsrcId = (DWORD)-1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update our list
|
||
|
//
|
||
|
|
||
|
EnterCriticalSection(&g_csList);
|
||
|
|
||
|
hitem->next = g_hWndList;
|
||
|
g_hWndList = hitem;
|
||
|
|
||
|
LeaveCriticalSection(&g_csList);
|
||
|
|
||
|
DPFN( eDbgLevelError, "CreateWindow HWND=%08lx, ResourceId=%08lx", hitem->hWnd, hitem->dwRsrcId);
|
||
|
} else {
|
||
|
DPFN( eDbgLevelError, "Failed to allocate list item");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case HCBT_DESTROYWND:
|
||
|
|
||
|
//
|
||
|
// Remove the window from our list
|
||
|
//
|
||
|
|
||
|
EnterCriticalSection(&g_csList);
|
||
|
|
||
|
HWNDITEM *hitem = g_hWndList, *hprev = NULL;
|
||
|
|
||
|
while (hitem) {
|
||
|
if (hitem->hWnd == hWnd) {
|
||
|
if (hprev) {
|
||
|
hprev->next = hitem->next;
|
||
|
} else {
|
||
|
g_hWndList = hitem->next;
|
||
|
}
|
||
|
|
||
|
free(hitem);
|
||
|
|
||
|
DPFN( eDbgLevelError, "DestroyWindow %08lx", hWnd);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
hprev = hitem;
|
||
|
hitem = hitem->next;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&g_csList);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return CallNextHookEx(g_hHookCbt, nCode, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hook CreateDialog which is where the problem occurs
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HWND
|
||
|
APIHOOK(CreateDialogIndirectParamA)(
|
||
|
HINSTANCE hInstance,
|
||
|
LPCDLGTEMPLATE lpTemplate,
|
||
|
HWND hWndParent,
|
||
|
DLGPROC lpDialogFunc,
|
||
|
LPARAM lParamInit
|
||
|
)
|
||
|
{
|
||
|
if (!g_hHookCbt) {
|
||
|
g_hHookCbt = SetWindowsHookExW(WH_CBT, CBTProcW, GetModuleHandleW(0), 0);
|
||
|
DPFN( eDbgLevelInfo, "[CreateDialogIndirectParamA] Hook added");
|
||
|
}
|
||
|
|
||
|
HWND hRet = ORIGINAL_API(CreateDialogIndirectParamA)(
|
||
|
hInstance,
|
||
|
lpTemplate,
|
||
|
hWndParent,
|
||
|
lpDialogFunc,
|
||
|
lParamInit);
|
||
|
|
||
|
if (g_hHookCbt) {
|
||
|
UnhookWindowsHookEx(g_hHookCbt);
|
||
|
g_hHookCbt = 0;
|
||
|
}
|
||
|
|
||
|
return hRet;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Register hooked functions
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
NOTIFY_FUNCTION(
|
||
|
DWORD fdwReason)
|
||
|
{
|
||
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
||
|
//
|
||
|
// Initialize our critical section here
|
||
|
//
|
||
|
|
||
|
InitializeCriticalSection(&g_csList);
|
||
|
|
||
|
} else if (fdwReason == DLL_PROCESS_DETACH) {
|
||
|
//
|
||
|
// Clear the hook
|
||
|
//
|
||
|
|
||
|
if (g_hHookCbt) {
|
||
|
UnhookWindowsHookEx(g_hHookCbt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HOOK_BEGIN
|
||
|
|
||
|
CALL_NOTIFY_FUNCTION
|
||
|
|
||
|
APIHOOK_ENTRY(USER32.DLL, GetWindowTextA)
|
||
|
APIHOOK_ENTRY(USER32.DLL, SetWindowTextA)
|
||
|
APIHOOK_ENTRY(USER32.DLL, CreateDialogIndirectParamA)
|
||
|
|
||
|
HOOK_END
|
||
|
|
||
|
IMPLEMENT_SHIM_END
|
||
|
|