windows-nt/Source/XPSP1/NT/base/mvdm/wow32/walias.c
2020-09-26 16:20:57 +08:00

739 lines
20 KiB
C

/*++
*
* WOW v1.0
*
* Copyright (c) 1991, Microsoft Corporation
*
* WALIAS.C
* WOW32 16-bit handle alias support
*
* History:
* Created 27-Jan-1991 by Jeff Parsons (jeffpar)
* Modified 12-May-1992 by Mike Tricker (miketri) to add MultiMedia support
--*/
#include "precomp.h"
#pragma hdrstop
MODNAME(walias.c);
extern CRITICAL_SECTION gcsWOW;
extern PTD gptdTaskHead;
//BUGBUG - this must be removed once MM_MCISYSTEM_STRING is defined in MMSYSTEM.H.
#ifndef MM_MCISYSTEM_STRING
#define MM_MCISYSTEM_STRING 0x3CA
#endif
#ifdef DEBUG
extern BOOL fSkipLog; // TRUE to temporarily skip certain logging
#endif
typedef struct _stdclass {
LPSTR lpszClassName;
ATOM aClassAtom;
WNDPROC lpfnWndProc;
INT iOrdinal;
DWORD vpfnWndProc;
} STDCLASS;
// Some cool defines stolen from USERSRV.H
#define MENUCLASS MAKEINTATOM(0x8000)
#define DESKTOPCLASS MAKEINTATOM(0x8001)
#define DIALOGCLASS MAKEINTATOM(0x8002)
#define SWITCHWNDCLASS MAKEINTATOM(0x8003)
#define ICONTITLECLASS MAKEINTATOM(0x8004)
// See WARNING below!
STDCLASS stdClasses[] = {
NULL, 0, NULL, 0, 0, // WOWCLASS_UNKNOWN
NULL, 0, NULL, 0, 0, // WOWCLASS_WIN16
"BUTTON", 0, NULL, FUN_BUTTONWNDPROC, 0, // WOWCLASS_BUTTON,
"COMBOBOX", 0, NULL, FUN_COMBOBOXCTLWNDPROC, 0, // WOWCLASS_COMBOBOX,
"EDIT", 0, NULL, FUN_EDITWNDPROC, 0, // WOWCLASS_EDIT,
"LISTBOX", 0, NULL, FUN_LBOXCTLWNDPROC, 0, // WOWCLASS_LISTBOX,
"MDICLIENT", 0, NULL, FUN_MDICLIENTWNDPROC, 0, // WOWCLASS_MDICLIENT,
"SCROLLBAR", 0, NULL, FUN_SBWNDPROC, 0, // WOWCLASS_SCROLLBAR,
"STATIC", 0, NULL, FUN_STATICWNDPROC, 0, // WOWCLASS_STATIC,
"#32769", (WORD)DESKTOPCLASS, NULL, FUN_DESKTOPWNDPROC, 0, // WOWCLASS_DESKTOP,
"#32770", (WORD)DIALOGCLASS, NULL, FUN_DEFDLGPROCTHUNK, 0, // WOWCLASS_DIALOG,
"#32772", (WORD)ICONTITLECLASS, NULL, FUN_TITLEWNDPROC, 0, // WOWCLASS_ICONTITLE,
"#32768", (WORD)MENUCLASS, NULL, FUN_MENUWNDPROC, 0, // WOWCLASS_MENU,
"#32771", (WORD)SWITCHWNDCLASS, NULL, 0, 0, // WOWCLASS_SWITCHWND,
"COMBOLBOX", 0, NULL, FUN_LBOXCTLWNDPROC, 0, // WOWCLASS_COMBOLBOX
};
//
// WARNING! The above sequence and values must be maintained otherwise the
// table in WMSG16.C for message thunking must be changed. Same goes for
// the #define's in WALIAS.H
//
// The above COMBOLBOX case is special because it is class that is
// almost identical to a listbox. Therefore we lie about it.
INT GetStdClassNumber(
PSZ pszClass
) {
INT i;
if ( HIWORD(pszClass) ) {
// They passed us a string
for ( i = WOWCLASS_BUTTON; i < NUMEL(stdClasses); i++ ) {
if ( WOW32_stricmp(pszClass, stdClasses[i].lpszClassName) == 0 ) {
return( i );
}
}
} else {
// They passed us an atom
for ( i = WOWCLASS_BUTTON; i < NUMEL(stdClasses); i++ ) {
if ( stdClasses[i].aClassAtom == 0 ) {
// RegisterWindowMessage is an undocumented way of determining
// an atom value in the context of the server-side heap.
stdClasses[i].aClassAtom = (ATOM)RegisterWindowMessage(stdClasses[i].lpszClassName);
}
if ( (ATOM)LOWORD(pszClass) == stdClasses[i].aClassAtom ) {
return( i );
}
}
}
return( WOWCLASS_WIN16 ); // private 16-bit class created by the app
}
// Returns a 32 window proc given a class index
WNDPROC GetStdClassWndProc(
DWORD iClass
) {
WNDPROC lpfn32;
if ( iClass < WOWCLASS_WIN16 || iClass > WOWCLASS_MAX ) {
WOW32ASSERT(FALSE);
return( NULL );
}
lpfn32 = stdClasses[iClass].lpfnWndProc;
if ( lpfn32 == NULL ) {
WNDCLASS wc;
BOOL f;
f = GetClassInfo( NULL, stdClasses[iClass].lpszClassName, &wc );
if ( f ) {
VPVOID vp;
DWORD UNALIGNED * lpdw;
lpfn32 = wc.lpfnWndProc;
stdClasses[iClass].lpfnWndProc = lpfn32;
vp = GetStdClassThunkProc(iClass);
vp = (VPVOID)((DWORD)vp - sizeof(DWORD)*3);
GETVDMPTR( vp, sizeof(DWORD)*3, lpdw );
WOW32ASSERT(*lpdw == SUBCLASS_MAGIC); // Are we editing the right stuff?
if (!lpdw)
*(lpdw+2) = (DWORD)lpfn32;
FLUSHVDMCODEPTR( vp, sizeof(DWORD)*3, lpdw );
FREEVDMPTR( lpdw );
}
}
return( lpfn32 );
}
// Returns a 16 window proc thunk given a class index
DWORD GetStdClassThunkProc(
INT iClass
) {
DWORD dwResult;
SHORT iOrdinal;
PARM16 Parm16;
if ( iClass < WOWCLASS_WIN16 || iClass > WOWCLASS_MAX ) {
WOW32ASSERT(FALSE);
return( 0 );
}
iOrdinal = (SHORT)stdClasses[iClass].iOrdinal;
if ( iOrdinal == 0 ) {
return( (DWORD)NULL );
}
// If we've already gotten this proc, then don't bother calling into 16-bit
dwResult = stdClasses[iClass].vpfnWndProc;
if ( dwResult == (DWORD)NULL ) {
// Callback into the 16-bit world asking for the 16:16 address
Parm16.SubClassProc.iOrdinal = iOrdinal;
if (!CallBack16(RET_SUBCLASSPROC, &Parm16, (VPPROC)NULL,
(PVPVOID)&dwResult)) {
WOW32ASSERT(FALSE);
return( 0 );
}
// Save it since it is a constant.
stdClasses[iClass].vpfnWndProc = dwResult;
}
return( dwResult );
}
/*
* PWC GetClassWOWWords(hInst, pszClass)
* is a ***private*** API for WOW only. It returns a pointer to the
* WOW Class structure in the server's window class structure.
* This is similar to GetClassLong(hwnd32, GCL_WOWWORDS) (see FindPWC),
* but in this case we don't have a hwnd32, we have the class name
* and instance handle.
*/
PWC FindClass16(LPCSTR pszClass, HAND16 hInst)
{
register PWC pwc;
pwc = (PWC)(pfnOut.pfnGetClassWOWWords)(HMODINST32(hInst), pszClass);
WOW32WARNMSGF(
pwc,
("WOW32 warning: GetClassWOWWords('%s', %04x) returned NULL\n", pszClass, hInst)
);
return (pwc);
}
#ifdef DEBUG
INT nAliases;
INT iLargestListSlot;
PSZ apszHandleClasses[] = {
"Unknown", // WOWCLASS_UNKNOWN
"Window", // WOWCLASS_WIN16
"Button", // WOWCLASS_BUTTON
"ComboBox", // WOWCLASS_COMBOBOX
"Edit", // WOWCLASS_EDIT
"ListBox", // WOWCLASS_LISTBOX
"MDIClient", // WOWCLASS_MDICLIENT
"Scrollbar", // WOWCLASS_SCROLLBAR
"Static", // WOWCLASS_STATIC
"Desktop", // WOWCLASS_DESKTOP
"Dialog", // WOWCLASS_DIALOG
"Menu", // WOWCLASS_MENU
"IconTitle", // WOWCLASS_ICONTITLE
"Accel", // WOWCLASS_ACCEL
"Cursor", // WOWCLASS_CURSOR
"Icon", // WOWCLASS_ICON
"DC", // WOWCLASS_DC
"Font", // WOWCLASS_FONT
"MetaFile", // WOWCLASS_METAFILE
"Region", // WOWCLASS_RGN
"Bitmap", // WOWCLASS_BITMAP
"Brush", // WOWCLASS_BRUSH
"Palette", // WOWCLASS_PALETTE
"Pen", // WOWCLASS_PEN
"Object" // WOWCLASS_OBJECT
};
BOOL MessageNeedsThunking(UINT uMsg)
{
switch (uMsg) {
case WM_CREATE:
case WM_ACTIVATE:
case WM_SETFOCUS:
case WM_KILLFOCUS:
case WM_SETTEXT:
case WM_GETTEXT:
case WM_ERASEBKGND:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case WM_ACTIVATEAPP:
case WM_SETCURSOR:
case WM_MOUSEACTIVATE:
case WM_GETMINMAXINFO:
case WM_ICONERASEBKGND:
case WM_NEXTDLGCTL:
case WM_DRAWITEM:
case WM_MEASUREITEM:
case WM_DELETEITEM:
case WM_VKEYTOITEM:
case WM_CHARTOITEM:
case WM_SETFONT:
case WM_GETFONT:
case WM_QUERYDRAGICON:
case WM_COMPAREITEM:
case WM_OTHERWINDOWCREATED:
case WM_OTHERWINDOWDESTROYED:
case WM_COMMNOTIFY:
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
case WM_NCCREATE:
case WM_NCCALCSIZE:
case WM_COMMAND:
case WM_HSCROLL:
case WM_VSCROLL:
case WM_INITMENU:
case WM_INITMENUPOPUP:
case WM_MENUSELECT:
case WM_MENUCHAR:
case WM_ENTERIDLE:
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORBTN:
case WM_CTLCOLORDLG:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLORSTATIC:
case WM_PARENTNOTIFY:
case WM_MDICREATE:
case WM_MDIDESTROY:
case WM_MDIACTIVATE:
case WM_MDIGETACTIVE:
case WM_MDISETMENU:
case WM_RENDERFORMAT:
case WM_PAINTCLIPBOARD:
case WM_VSCROLLCLIPBOARD:
case WM_SIZECLIPBOARD:
case WM_ASKCBFORMATNAME:
case WM_CHANGECBCHAIN:
case WM_HSCROLLCLIPBOARD:
case WM_PALETTEISCHANGING:
case WM_PALETTECHANGED:
case MM_JOY1MOVE:
case MM_JOY2MOVE:
case MM_JOY1ZMOVE:
case MM_JOY2ZMOVE:
case MM_JOY1BUTTONDOWN:
case MM_JOY2BUTTONDOWN:
case MM_JOY1BUTTONUP:
case MM_JOY2BUTTONUP:
case MM_MCINOTIFY:
case MM_MCISYSTEM_STRING:
case MM_WOM_OPEN:
case MM_WOM_CLOSE:
case MM_WOM_DONE:
case MM_WIM_OPEN:
case MM_WIM_CLOSE:
case MM_WIM_DATA:
case MM_MIM_OPEN:
case MM_MIM_CLOSE:
case MM_MIM_DATA:
case MM_MIM_LONGDATA:
case MM_MIM_ERROR:
case MM_MIM_LONGERROR:
case MM_MOM_OPEN:
case MM_MOM_CLOSE:
case MM_MOM_DONE:
LOGDEBUG(LOG_IMPORTANT,
("MessageNeedsThunking: WM_msg %04x is not thunked\n", uMsg));
return TRUE;
default:
return FALSE;
}
}
#endif
PTD ThreadProcID32toPTD(DWORD dwThreadID, DWORD dwProcessID)
{
PTD ptd, ptdThis;
PWOAINST pWOA;
//
// If we have active child instances of WinOldAp,
// try to map the process ID of a child Win32 app
// to the corresponding WinOldAp PTD.
//
ptdThis = CURRENTPTD();
EnterCriticalSection(&ptdThis->csTD);
pWOA = ptdThis->pWOAList;
while (pWOA && pWOA->dwChildProcessID != dwProcessID) {
pWOA = pWOA->pNext;
}
if (pWOA) {
ptd = pWOA->ptdWOA;
LeaveCriticalSection(&ptdThis->csTD);
} else {
LeaveCriticalSection(&ptdThis->csTD);
//
// We didn't find a WinOldAp PTD to return, see
// if the thread ID matches one of our app threads.
//
EnterCriticalSection(&gcsWOW);
ptd = gptdTaskHead;
while (ptd && ptd->dwThreadID != dwThreadID) {
ptd = ptd->ptdNext;
}
LeaveCriticalSection(&gcsWOW);
}
return ptd;
}
PTD Htask16toPTD(
HTASK16 htask16
) {
PTD ptd;
EnterCriticalSection(&gcsWOW);
ptd = gptdTaskHead;
while(ptd) {
if ( ptd->htask16 == htask16 ) {
break;
}
ptd = ptd->ptdNext;
}
LeaveCriticalSection(&gcsWOW);
return ptd;
}
HTASK16 ThreadID32toHtask16(
DWORD ThreadID32
) {
PTD ptd;
HTASK16 htask16;
if ( ThreadID32 == 0 ) {
WOW32ASSERTMSG(ThreadID32, "WOW::ThreadID32tohTask16: Thread ID is 0\n");
htask16 = 0;
} else {
ptd = ThreadProcID32toPTD( ThreadID32, (DWORD)-1 );
if ( ptd ) {
// Good, its one of our wow threads.
htask16 = ptd->htask16;
} else {
// Nope, its is some other 32-bit thread
htask16 = FindHtaskAlias( ThreadID32 );
if ( htask16 == 0 ) {
//
// See the comment in WOLE2.C for a nice description
//
htask16 = AddHtaskAlias( ThreadID32 );
}
}
}
return htask16;
}
DWORD Htask16toThreadID32(
HTASK16 htask16
) {
if ( htask16 == 0 ) {
return( 0 );
}
if ( ISTASKALIAS(htask16) ) {
return( GetHtaskAlias(htask16,NULL) );
} else {
return( THREADID32(htask16) );
}
}
//***************************************************************************
// GetGCL_HMODULE - returns the valid hmodule if the window corresponds to
// a 16bit class else returns the hmodule of 16bit user.exe
// if the window is of a standard class.
//
// These cases are required for compatibility sake.
// apps like VirtualMonitor, hDC etc depend on such behaviour.
// - Nanduri
//***************************************************************************
WORD gUser16hInstance = 0;
ULONG GetGCL_HMODULE(HWND hwnd)
{
ULONG ul;
PTD ptd;
PWOAINST pWOA;
DWORD dwProcessID;
ul = (ULONG)GetClassLong(hwnd, GCL_HMODULE);
//
// hMod32 = 0xZZZZ0000
//
if (ul != 0 && LOWORD(ul) == 0) {
//
// If we have active WinOldAp children, see if this window
// belongs to a Win32 process spawned by one of the
// active winoldap's. If it is, return the hmodule
// of the corresponding winoldap. Otherwise we
// return user.exe's hinstance (why not hmodule?)
//
dwProcessID = (DWORD)-1;
GetWindowThreadProcessId(hwnd, &dwProcessID);
ptd = CURRENTPTD();
EnterCriticalSection(&ptd->csTD);
pWOA = ptd->pWOAList;
while (pWOA && pWOA->dwChildProcessID != dwProcessID) {
pWOA = pWOA->pNext;
}
if (pWOA) {
ul = pWOA->ptdWOA->hMod16;
LOGDEBUG(LOG_ALWAYS, ("WOW32 GetClassLong(0x%x, GWW_HMODULE) returning 0x%04x\n",
hwnd, ul));
} else {
ul = (ULONG) gUser16hInstance;
WOW32ASSERT(ul);
}
LeaveCriticalSection(&ptd->csTD);
}
else {
ul = (ULONG)GETHMOD16(ul); // 32-bit hmod is HMODINST32
}
return ul;
}
//
// EXPORTED handle mapping functions. WOW32 code should use the
// macros defined in walias.h -- these functions are for use by
// third-party 32-bit code running in WOW, for example called
// using generic thunks from WOW-specific 16-bit code.
//
HANDLE WOWHandle32 (WORD h16, WOW_HANDLE_TYPE htype)
{
switch (htype) {
case WOW_TYPE_HWND:
return HWND32(h16);
case WOW_TYPE_HMENU:
return HMENU32(h16);
case WOW_TYPE_HDWP:
return HDWP32(h16);
case WOW_TYPE_HDROP:
return HDROP32(h16);
case WOW_TYPE_HDC:
return HDC32(h16);
case WOW_TYPE_HFONT:
return HFONT32(h16);
case WOW_TYPE_HMETAFILE:
return HMETA32(h16);
case WOW_TYPE_HRGN:
return HRGN32(h16);
case WOW_TYPE_HBITMAP:
return HBITMAP32(h16);
case WOW_TYPE_HBRUSH:
return HBRUSH32(h16);
case WOW_TYPE_HPALETTE:
return HPALETTE32(h16);
case WOW_TYPE_HPEN:
return HPEN32(h16);
case WOW_TYPE_HACCEL:
return HACCEL32(h16);
case WOW_TYPE_HTASK:
return (HANDLE)HTASK32(h16);
case WOW_TYPE_FULLHWND:
return (HANDLE)FULLHWND32(h16);
default:
return(INVALID_HANDLE_VALUE);
}
}
WORD WOWHandle16 (HANDLE h32, WOW_HANDLE_TYPE htype)
{
switch (htype) {
case WOW_TYPE_HWND:
return GETHWND16(h32);
case WOW_TYPE_HMENU:
return GETHMENU16(h32);
case WOW_TYPE_HDWP:
return GETHDWP16(h32);
case WOW_TYPE_HDROP:
return GETHDROP16(h32);
case WOW_TYPE_HDC:
return GETHDC16(h32);
case WOW_TYPE_HFONT:
return GETHFONT16(h32);
case WOW_TYPE_HMETAFILE:
return GETHMETA16(h32);
case WOW_TYPE_HRGN:
return GETHRGN16(h32);
case WOW_TYPE_HBITMAP:
return GETHBITMAP16(h32);
case WOW_TYPE_HBRUSH:
return GETHBRUSH16(h32);
case WOW_TYPE_HPALETTE:
return GETHPALETTE16(h32);
case WOW_TYPE_HPEN:
return GETHPEN16(h32);
case WOW_TYPE_HACCEL:
return GETHACCEL16(h32);
case WOW_TYPE_HTASK:
return GETHTASK16(h32);
default:
return(0xffff);
}
}
PVOID gpGdiHandleInfo = (PVOID)-1;
//WARNING: This structure must match ENTRY in ntgdi\inc\hmgshare.h
typedef struct _ENTRYWOW
{
LONG l1;
LONG l2;
USHORT FullUnique;
USHORT us1;
LONG l3;
} ENTRYWOW, *PENTRYWOW;
//
// this routine converts a 16bit GDI handle to a 32bit handle. There
// is no need to do any validation on the handle since the 14bit space
// for handles ignoring the low two bits is completely contained in the
// valid 32bit handle space.
//
HANDLE hConvert16to32(int h16)
{
ULONG h32;
int i = h16 >> 2;
h32 = i | (ULONG)(((PENTRYWOW)gpGdiHandleInfo)[i].FullUnique) << 16;
return((HANDLE)h32);
}
// Implemented as temporary fix for Whistler Bug #435401
// Should be fixed for Blackcomb or sooner
extern HANDLE hmodWOW32;
HAND16 hConvert32to16(DWORD h32)
{
PARM16 Parm16;
VPVOID vp = 0;
// see if handle is over 14-bits
if(LOWORD(h32) > 0x00003FFF) {
char szErrorMessage[512];
char szTitle[512];
char szModName[9];
PTDB pTDB;
pTDB = (PVOID)SEGPTR(CURRENTPTD()->htask16,0);
RtlCopyMemory(szModName, pTDB->TDB_ModName, sizeof(szModName)-1);
szModName[sizeof(szModName)-1] = 0;
if (!LoadString(hmodWOW32, iszApplication,
szTitle, sizeof(szTitle)/sizeof(CHAR)))
{
szTitle[0] = 0;
}
strcat(szTitle, szModName);
LoadString(hmodWOW32,
iszExceedGDIHandleLimit,
szErrorMessage,
sizeof szErrorMessage);
// The GDI32 handle allocation has gone over the 16K threshhold
// This thread is toast.
WOWSysErrorBox(szTitle, szErrorMessage, SEB_OK | SEB_DEFBUTTON, 0, 0);
LOGDEBUG(LOG_ALWAYS,
("GDI32 handle limit exceeded for Task %04X \n",
CURRENTPTD()->htask16));
CallBack16(RET_FORCETASKEXIT, &Parm16, 0, &vp);
// this should never return
return(0);
}
// everything is hunky dory
return((HAND16)(((DWORD) (h32)) << 2));
}
// We probably don't need to worry about this buffer being too small since we're
// really only interested in the predefined standard classes which tend to
// be rather short-named.
#define MAX_CLASSNAME_LEN 64
// There is a time frame (from when an app calls CreateWindow until USER32 gets
// a message at one of its WndProc's for the window - see FritzS) during which
// the fnid (class type) can't be set officially for the window. If the
// GETICLASS macro is invoked during this period, it will be unable to find the
// iClass for windows created on any of the standard control classes using the
// fast fnid index method (see walias.h). Once the time frame is passed, the
// fast fnid method will work fine for these windows.
//
// This is manifested in apps that set CBT hooks and try to subclass the
// standard classes while in their hook proc. See bug #143811.
INT GetIClass(PWW pww, HWND hwnd)
{
INT iClass;
DWORD dwClassAtom;
// if it is a standard class
if(((pww->fnid & 0xfff) >= FNID_START) &&
((pww->fnid & 0xfff) <= FNID_END)) {
// return the class id for this initialized window
iClass = pfnOut.aiWowClass[( pww->fnid & 0xfff) - FNID_START];
}
else {
iClass = WOWCLASS_WIN16; // default return: app private class
dwClassAtom = GetClassLong(hwnd, GCW_ATOM);
if(dwClassAtom) {
iClass = GetStdClassNumber((PSZ)dwClassAtom);
}
}
return(iClass);
}