windows-nt/Source/XPSP1/NT/windows/appcompat/shims/specific/cluefinders3rdgrade.cpp
2020-09-26 16:20:57 +08:00

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