|
|
/*++
* * 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); }
|