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