|
|
/****************************** Module Header ******************************\
* Module Name: ClMsg.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Includes the mapping table for messages when calling the server. * * 04-11-91 ScottLu Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#define fnINDESTROYCLIPBRD fnDWORD
#define fnOUTDWORDDWORD fnDWORD
#define fnPOWERBROADCAST fnDWORD
#define fnLOGONNOTIFY fnKERNELONLY
#define fnINLPKDRAWSWITCHWND fnKERNELONLY
#define MSGFN(func) fn ## func
#define FNSCSENDMESSAGE CFNSCSENDMESSAGE
#include "messages.h"
#if DBG
BOOL gfTurboDWP = TRUE; #endif
#define BEGIN_CALLWINPROC(fInsideHook, lRet) \
PCLIENTTHREADINFO pcti = GetClientInfo()->pClientThreadInfo; \ BOOL fCallBack = ((pcti!=NULL) && \ TEST_BOOL_FLAG(pcti->CTIF_flags, CTIF_INCALLBACKMESSAGE)); \ RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame \ = { \ sizeof(ActivationFrame), \ RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER \ }; \ fInsideHook = FALSE; \ \ if (!fCallBack) { \ RtlActivateActivationContextUnsafeFast( \ &ActivationFrame, \ pActCtx); \ \ fInsideHook = _BeginIfHookedUserApiHook(); \ } \ \ __try { \
#define END_CALLWINPROC(fInsideHook) \
} __finally { \ if (!fCallBack) { \ if (fInsideHook) { \ _EndUserApiHook(); \ } \ RtlDeactivateActivationContextUnsafeFast( \ &ActivationFrame); \ } \ }
/***************************************************************************\
* UserCallWinProc * * Setups everything to finally call a Win32 WNDPROC * * History: * 27-Apr-2000 jstall Rewrote to support "lightweight hooks" \***************************************************************************/
LRESULT UserCallWinProc( PACTIVATION_CONTEXT pActCtx, WNDPROC pfn, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fInsideHook; LRESULT lRet = 0;
BEGIN_CALLWINPROC(fInsideHook, lRet) BOOL fOverride = fInsideHook && IsMsgOverride(msg, &guah.uoiWnd.mm);
pfn = MapKernelClientFnToClientFn(pfn);
if (fOverride) { /*
* NOTE: It is important that the same lRet is passed to all three * calls, allowing the Before and After OWP's to examine the value. */ PVOID pvCookie = NULL; if (!guah.uoiWnd.pfnBeforeOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie)) { lRet = InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam); guah.uoiWnd.pfnAfterOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie); } } else { lRet = InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam); } END_CALLWINPROC(fInsideHook)
return lRet; }
/***************************************************************************\
* UserCallWinProcCheckWow * * Sets up everything to finally call a Win32 or WOW WNDPROC. * * History: * 27-Apr-2000 jstall Rewrote to support "lightweight hooks" \***************************************************************************/
LRESULT UserCallWinProcCheckWow( PACTIVATION_CONTEXT pActCtx, WNDPROC pfn, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, PVOID pww, BOOL fEnableLiteHooks) { BOOL fInsideHook; LRESULT lRet = 0;
BEGIN_CALLWINPROC(fInsideHook, lRet)
BOOL fOverride = fInsideHook && fEnableLiteHooks && IsMsgOverride(msg, &guah.uoiWnd.mm);
pfn = MapKernelClientFnToClientFn(pfn);
if (fOverride) { /*
* NOTE: It is important that the same lRet is passed to all three * calls, allowing the Before and After OWP's to examine the value. */ void * pvCookie = NULL; if (guah.uoiWnd.pfnBeforeOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie)) { goto DoneCalls; }
lRet = (IsWOWProc(pfn) ? (*pfnWowWndProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) : InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam));
if (guah.uoiWnd.pfnAfterOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie)) { // Fall through and exit normally
} DoneCalls: ; } else { lRet = (IsWOWProc(pfn) ? (*pfnWowWndProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) : InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam)); } END_CALLWINPROC(fInsideHook)
return lRet; #ifdef _WIN64
UNREFERENCED_PARAMETER(pww); #endif // _WIN64
}
/***************************************************************************\
* UserCallDlgProcCheckWow * * Setups everything to finally call a Win32 or WOW DLGPROC * * History: * 27-Apr-2000 jstall Rewrote to support "lightweight hooks" \***************************************************************************/
BOOL UserCallDlgProcCheckWow( PACTIVATION_CONTEXT pActCtx, DLGPROC pfn, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, PVOID pww, INT_PTR * pret) { BOOL fInsideHook; INT_PTR fRet = 0; BOOL fHandled = FALSE;
BEGIN_CALLWINPROC(fInsideHook, fRet)
BOOL fOverride = fInsideHook && IsMsgOverride(msg, &guah.uoiDlg.mm);
pfn = MapKernelClientFnToClientFn(pfn);
if (fOverride) { /*
* NOTE: It is important that the same lRet is passed to all three * calls, allowing the Before and After OWP's to examine the value. */ void * pvCookie = NULL; if (guah.uoiDlg.pfnBeforeOWP(hwnd, msg, wParam, lParam, (LRESULT*) &fRet, &pvCookie)) { fHandled = TRUE; goto DoneCalls; }
fRet = (IsWOWProc(pfn) ? (*pfnWowDlgProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) : InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam));
if (guah.uoiDlg.pfnAfterOWP(hwnd, msg, wParam, lParam, (LRESULT*) &fRet, &pvCookie)) { fHandled = TRUE; // Fall through and exit normally
} DoneCalls: ; } else { fRet = (IsWOWProc(pfn) ? (*pfnWowDlgProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) : InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam)); }
END_CALLWINPROC(fInsideHook)
*pret = fRet;
return fHandled; #ifdef _WIN64
UNREFERENCED_PARAMETER(pww); #endif // _WIN64
}
/***************************************************************************\
* GetMouseKeyState * * Returns the state of mouse and keyboard keys that are sent * in a mouse message. * * History: * 12-Nov-1998 adams Created. \***************************************************************************/
WORD GetMouseKeyState(void) { WORD keystate;
/*
* Note that it is more efficient to call GetKeyState for each * key than to call GetKeyboardState, since the keys we are testing * are cached and don't require a trip to the kernel to fetch. */
#define TESTANDSETKEYSTATE(x) \
if (GetKeyState(VK_##x) & 0x8000) { \ keystate |= MK_##x; \ }
keystate = 0; TESTANDSETKEYSTATE(LBUTTON) TESTANDSETKEYSTATE(RBUTTON) TESTANDSETKEYSTATE(MBUTTON) TESTANDSETKEYSTATE(XBUTTON1) TESTANDSETKEYSTATE(XBUTTON2) TESTANDSETKEYSTATE(SHIFT) TESTANDSETKEYSTATE(CONTROL)
return keystate; }
/***************************************************************************\
* These are client side thunks for server side window procs. This is being * done so that when an app gets a wndproc via GetWindowLong, GetClassLong, * or GetClassInfo, it gets a real callable address - some apps don't call * CallWindowProc, but call the return ed address directly. * * 01-13-92 ScottLu Created. * 03-Dec-1993 mikeke added client side handling of some messages \***************************************************************************/
LRESULT WINAPI DesktopWndProcWorker( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { PWND pwnd;
if (FWINDOWMSG(message, FNID_DESKTOP)) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DESKTOP, fAnsi); }
if ((pwnd = ValidateHwnd(hwnd)) == NULL) return 0;
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
}
LRESULT WINAPI DesktopWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return DesktopWndProcWorker(hwnd, message, wParam, lParam, TRUE); }
LRESULT WINAPI DesktopWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return DesktopWndProcWorker(hwnd, message, wParam, lParam, FALSE); }
/***************************************************************************\
* These are client side thunks for server side window procs. This is being * done so that when an app gets a wndproc via GetWindowLong, GetClassLong, * or GetClassInfo, it gets a real callable address - some apps don't call * CallWindowProc, but call the return ed address directly. * * 01-13-92 ScottLu Created. * 03-Dec-1993 mikeke added client side handling of some messages \***************************************************************************/
LRESULT WINAPI MenuWndProcWorker( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { PWND pwnd;
if (FWINDOWMSG(message, FNID_MENU)) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_MENU, fAnsi); }
if ((pwnd = ValidateHwnd(hwnd)) == NULL) return 0;
switch (message) { case WM_LBUTTONDBLCLK: case WM_NCLBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK:
/*
* Ignore double clicks on these windows. */ break;
case WM_DESTROY: break;
default: return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi); }
return 0; }
LRESULT WINAPI MenuWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return MenuWndProcWorker(hwnd, message, wParam, lParam, TRUE); }
LRESULT WINAPI MenuWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return MenuWndProcWorker(hwnd, message, wParam, lParam, FALSE); }
/***************************************************************************\
\***************************************************************************/
LRESULT WINAPI ScrollBarWndProcWorker( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { PSBWND psbwnd; LPSCROLLINFO lpsi; PSBDATA pw;
if (FWINDOWMSG(message, FNID_SCROLLBAR)) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_SCROLLBAR, fAnsi); }
if ((psbwnd = (PSBWND)ValidateHwnd(hwnd)) == NULL) return 0;
switch (message) { case WM_GETDLGCODE: return DLGC_WANTARROWS;
case SBM_GETPOS: return (LONG)psbwnd->SBCalc.pos;
case SBM_GETRANGE: *((LPINT)wParam) = psbwnd->SBCalc.posMin; *((LPINT)lParam) = psbwnd->SBCalc.posMax; return 0;
case SBM_GETSCROLLINFO: lpsi = (LPSCROLLINFO)lParam; if ((lpsi->cbSize != sizeof(SCROLLINFO)) && (lpsi->cbSize != sizeof(SCROLLINFO) - 4)) { RIPMSG0(RIP_ERROR, "SCROLLINFO: invalid cbSize"); return FALSE; }
if (lpsi->fMask & ~SIF_MASK) { RIPMSG0(RIP_ERROR, "SCROLLINFO: Invalid fMask"); return FALSE; }
pw = (PSBDATA)KPSBDATA_TO_PSBDATA(&(psbwnd->SBCalc)); return(NtUserSBGetParms(hwnd, SB_CTL, pw, lpsi));
case SBM_GETSCROLLBARINFO: return NtUserGetScrollBarInfo(hwnd, OBJID_CLIENT, (PSCROLLBARINFO)lParam);
default: return DefWindowProcWorker((PWND)psbwnd, message, wParam, lParam, fAnsi); } }
LRESULT WINAPI ScrollBarWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return ScrollBarWndProcWorker(hwnd, message, wParam, lParam, TRUE); }
LRESULT WINAPI ScrollBarWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return ScrollBarWndProcWorker(hwnd, message, wParam, lParam, FALSE); }
/***************************************************************************\
* SendMessage * * Translates the message, calls SendMessage on server side. * * 04-11-91 ScottLu Created. * 04-27-92 DarrinM Added code to support client-to-client SendMessages. \***************************************************************************/
LRESULT SendMessageWorker( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { HWND hwnd = HWq(pwnd); PCLIENTINFO pci; PCLS pcls; BOOLEAN fAnsiRecv; BOOLEAN fNeedTranslation = FALSE; BOOLEAN bDoDbcsMessaging = FALSE; LRESULT lRet;
UserAssert(pwnd);
/*
* Pass DDE messages to the server. */ if (message >= WM_DDE_FIRST && message <= WM_DDE_LAST) goto lbServerSendMessage;
/*
* Server must handle inter-thread SendMessages and SendMessages * to server-side procs. */ if ((PtiCurrent() != GETPTI(pwnd)) || TestWF(pwnd, WFSERVERSIDEPROC)) goto lbServerSendMessage;
/*
* Server must handle hooks (at least for now). */ pci = GetClientInfo(); if (IsHooked(pci, (WHF_CALLWNDPROC | WHF_CALLWNDPROCRET))) { lbServerSendMessage: return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_SENDMESSAGE, fAnsi); }
/*
* If the sender and the receiver are both ANSI or both UNICODE * then no message translation is necessary. * * EditWndProc may need to go to the server for translation if we * are calling vanilla EditWndProc from SendMessageA and the edit * control is currently subclassed Ansi but the edit control is * stored Unicode. */ fAnsiRecv = !!(TestWF(pwnd, WFANSIPROC)); if (!fAnsi != !fAnsiRecv) {
/*
* Translation might be necessary between sender and receiver, * check to see if this is one of the messages we translate. */ switch (message) { case WM_CHARTOITEM: case EM_SETPASSWORDCHAR: case WM_CHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case WM_MENUCHAR: case WM_IME_CHAR: case WM_IME_COMPOSITION: if (fAnsi) { /*
* Setup DBCS Messaging for WM_CHAR... */ BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA(message,wParam,TRUE);
/*
* Convert wParam to Unicode... */ RtlMBMessageWParamCharToWCS(message, &wParam);
/*
* The message has been converted to Unicode. */ fAnsi = FALSE; } else { POINT ptZero = {0,0}; /*
* Convert wParam to ANSI... */ RtlWCSMessageWParamCharToMB(message, &wParam);
/*
* Let's DBCS messaging for WM_CHAR.... */ BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_CLIENTW( hwnd,message,wParam,lParam,0,ptZero,bDoDbcsMessaging);
/*
* The message has been converted to ANSI. */ fAnsi = TRUE; } break;
case EM_SETSEL: case EM_GETSEL: case CB_GETEDITSEL: if (IS_DBCS_ENABLED()) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid DBCS message (%x) to SendMessageWorker",message); } //
// Fall down...
default: if ((message < WM_USER) && MessageTable[message].bThunkMessage) { fNeedTranslation = TRUE; } } }
#ifndef LATER
/*
* If the window has a client side worker proc and has * not been subclassed, dispatch the message directly * to the worker proc. Otherwise, dispatch it normally. */ pcls = REBASEALWAYS(pwnd, pcls);
if ((!IsInsideUserApiHook()) && (pcls->fnid >= FNID_CONTROLSTART && pcls->fnid <= FNID_CONTROLEND) && ((KERNEL_ULONG_PTR)pwnd->lpfnWndProc == FNID_TO_CLIENT_PFNW_KERNEL(pcls->fnid) || (KERNEL_ULONG_PTR)pwnd->lpfnWndProc == FNID_TO_CLIENT_PFNA_KERNEL(pcls->fnid))) { PWNDMSG pwm = &gSharedInfo.awmControl[pcls->fnid - FNID_START];
/*
* If this message is not processed by the control, call * xxxDefWindowProc */ if (pwm->abMsgs && ((message > pwm->maxMsgs) || !((pwm->abMsgs)[message / 8] & (1 << (message & 7))))) {
/*
* Special case dialogs so that we can ignore unimportant * messages during dialog creation. */ if (pcls->fnid == FNID_DIALOG && PDLG(pwnd) && PDLG(pwnd)->lpfnDlg != NULL) { /*
* If A/W translation are needed for Dialog, * it should go to kernel side to perform proper message. * DefDlgProcWorker will call aplication's DlgProc directly * without A/W conversion. */ if (fNeedTranslation) { goto lbServerSendMessage; } /*
* Call woker procudure. */ SendMessageToWorker1Again: lRet = ((PROC)(FNID_TO_CLIENT_PFNWORKER(pcls->fnid)))(pwnd, message, wParam, lParam, fAnsi); /*
* if we have DBCS TrailingByte that should be sent, send it here.. */ DISPATCH_DBCS_MESSAGE_IF_EXIST(message,wParam,bDoDbcsMessaging,SendMessageToWorker1);
return lRet; } else { /*
* Call worker procedure. */ SendMessageToDefWindowAgain: lRet = DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi); /*
* if we have DBCS TrailingByte that should be sent, send it here.. */ DISPATCH_DBCS_MESSAGE_IF_EXIST(message,wParam,bDoDbcsMessaging,SendMessageToDefWindow);
return lRet; } } else { /*
* Call woker procudure. */ SendMessageToWorker2Again: lRet = ((PROC)(FNID_TO_CLIENT_PFNWORKER(pcls->fnid)))(pwnd, message, wParam, lParam, fAnsi);
/*
* if we have DBCS TrailingByte that should be sent, send it here.. */ DISPATCH_DBCS_MESSAGE_IF_EXIST(message,wParam,bDoDbcsMessaging,SendMessageToWorker2);
return lRet; } } #endif
/*
* If this message needs to be translated, go through the kernel. */ if (fNeedTranslation) { goto lbServerSendMessage; }
/*
* Call Client Windows procudure. */ SendMessageToWndProcAgain: lRet = UserCallWinProcCheckWow(pwnd->pActCtx, (WNDPROC)pwnd->lpfnWndProc, hwnd, message, wParam, lParam, &(pwnd->state), TRUE);
/*
* if we have DBCS TrailingByte that should be sent, send it here.. */ DISPATCH_DBCS_MESSAGE_IF_EXIST(message,wParam,bDoDbcsMessaging,SendMessageToWndProc);
return lRet; }
// LATER!!! can this somehow be combined or subroutinized with SendMessageWork
// so we don't have to copies of 95% identical code.
/***************************************************************************\
* SendMessageTimeoutWorker * * Translates the message, calls SendMessageTimeout on server side. * * 07-21-92 ChrisBB Created/modified SendMessageWorkder \***************************************************************************/
LRESULT SendMessageTimeoutWorker( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, PULONG_PTR lpdwResult, BOOL fAnsi) { SNDMSGTIMEOUT smto;
/*
* Prevent apps from setting hi 16 bits so we can use them internally. */ if (message & RESERVED_MSG_BITS) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"message\" (%ld) to SendMessageTimeoutWorker", message);
return(0); }
if (fuFlags & ~SMTO_VALID) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid dwFlags (%x) for SendMessageTimeout\n", fuFlags); return(0); }
if (lpdwResult != NULL) *lpdwResult = 0L;
/*
* Always send broadcast requests straight to the server. * Note: the xParam is used to id if it's from timeout or * from an normal sendmessage. */ smto.fuFlags = fuFlags; smto.uTimeout = uTimeout; smto.lSMTOReturn = 0; smto.lSMTOResult = 0;
/*
* Thunk through a special sendmessage for -1 hwnd's so that the general * purpose thunks don't allow -1 hwnd's. */ if (hwnd == (HWND)-1 || hwnd == (HWND)0x0000FFFF) { /*
* Get a real hwnd so the thunks will validation ok. Note that since * -1 hwnd is really rare, calling GetDesktopWindow() here is not a * big deal. */ hwnd = GetDesktopWindow();
CsSendMessage(hwnd, message, wParam, lParam, (ULONG_PTR)&smto, FNID_SENDMESSAGEFF, fAnsi); } else { CsSendMessage(hwnd, message, wParam, lParam, (ULONG_PTR)&smto, FNID_SENDMESSAGEEX, fAnsi); }
if (lpdwResult != NULL) *lpdwResult = smto.lSMTOResult;
return smto.lSMTOReturn; }
#ifdef LAME_BUTTON
PLAMEBTNPROC gpfnCommentReport;
VOID LoadCommentReportIfNeeded( VOID) { if (gpfnCommentReport == NULL) { HMODULE hmod = LoadLibrary(L"LAMEBTN.DLL");
if (hmod != NULL) { gpfnCommentReport = (PLAMEBTNPROC)GetProcAddress(hmod, "CommentReport"); if (gpfnCommentReport == NULL) { FreeLibrary(hmod); } } } }
VOID CallLameButtonHandler( PWND pwnd, HWND hwnd) { UNREFERENCED_PARAMETER(pwnd);
UserAssert(TestWF(pwnd, WEFLAMEBUTTON));
LoadCommentReportIfNeeded();
if (gpfnCommentReport != NULL) { (*gpfnCommentReport)(hwnd, GetProp(hwnd, MAKEINTATOM(gatomLameButton))); } } #endif // LAME_BUTTON
VOID CopyMsgMask( MSGMASK * pDest, MSGMASK * pSrc, BYTE * rgbLocal, DWORD cbMax) { if ((pSrc->rgb != NULL) && (pSrc->cb > 0)) { pDest->rgb = rgbLocal; pDest->cb = min(cbMax, pSrc->cb); CopyMemory(pDest->rgb, pSrc->rgb, pDest->cb); } else { pDest->rgb = NULL; pDest->cb = 0; } }
/***************************************************************************\
* InitUserApiHook * * This function gets called when the module that contains the UserApiHook's * gets loaded. The UserApiHook is installed by calling * RegisterUserApiHook and is loaded on demand by xxxCreateWindowEx and/or * xxxDefWindowProc. The loading/unloading is controlled through the library * management routines. The function calls the initialization function in the * module and then sets up our global variables. * * We keep 2 reference counts. One counts calls to LoadLibrary/FreeLibrary. When * this goes to zero, we can stop calling out to the substitute UserApiHook's. * The other gets incremented when we do an actual callout to the substitute * UserApiHook and decremented on return. We can't actually unload the module * until this count goes to zero too (i.e. we aren't in a callout). * * History: * 10-Mar-2000 JerrySh Created. * 16-May-2000 JStall Changed to support uninitialize callback * 12-Feb-2001 Mohamed Added the check for read-only on reset ptr. \***************************************************************************/ BOOL InitUserApiHook( HMODULE hmod, ULONG_PTR offPfnInitUserApiHook) { INITUSERAPIHOOK pfnInitUserApi = NULL; USERAPIHOOK uahTemp;
BOOL bUpdate= FALSE; BOOL retval = FALSE;
/*
* If we're loading for the first time, call the initialization routine. */ ResetUserApiHook(&uahTemp); pfnInitUserApi = (INITUSERAPIHOOK)((ULONG_PTR)hmod + offPfnInitUserApiHook); bUpdate = pfnInitUserApi(UIAH_INITIALIZE, &uahTemp);
/*
* Check that the value of pfnForceResetUserApiHook hasn't been changed * by client since this should be treated as read-only. */ if ((!bUpdate) || (uahTemp.cbSize <= 0) || (uahTemp.pfnForceResetUserApiHook != ForceResetUserApiHook)) { return FALSE; }
RtlEnterCriticalSection(&gcsUserApiHook);
/*
* Need to check this again inside critical section. */ if (ghmodUserApiHook == NULL) { UserAssertMsg0(gpfnInitUserApi == NULL, "Ensure gpfnInitUserApi not set");
/*
* Save the global state if the init routine succeeded. * Copy the hooked functions */ UserAssert(gcLoadUserApiHook == 0); gcLoadUserApiHook = 1; gfUserApiHook = TRUE; // Turn calling the hooks on
ghmodUserApiHook = hmod; gpfnInitUserApi = pfnInitUserApi;
CopyMemory(&guah, &uahTemp, uahTemp.cbSize);
/*
* Copy the message-filter bit-mask */ CopyMsgMask(&guah.mmDWP, &uahTemp.mmDWP, grgbDwpLiteHookMsg, sizeof(grgbDwpLiteHookMsg)); CopyMsgMask(&guah.uoiWnd.mm, &uahTemp.uoiWnd.mm, grgbWndLiteHookMsg, sizeof(grgbWndLiteHookMsg)); CopyMsgMask(&guah.uoiDlg.mm, &uahTemp.uoiDlg.mm, grgbDlgLiteHookMsg, sizeof(grgbDlgLiteHookMsg));
retval = TRUE; } else if (ghmodUserApiHook == hmod) { /*
* This is the UserApiHook module, so bump up the reference count. */ UserAssert(gcLoadUserApiHook < MAXLONG); UserAssertMsg0(gpfnInitUserApi == pfnInitUserApi, "Need to match from before"); ++gcLoadUserApiHook; retval = TRUE; }
RtlLeaveCriticalSection(&gcsUserApiHook);
if (!retval) { /*
* Initialization failed, so ClientLoadLibrary() is going to * FreeLibrary(). Notify before we do this. */ RIPMSG2(RIP_WARNING, "Uninit from Init Load %lx Call %lx", gcLoadUserApiHook, gcCallUserApiHook); pfnInitUserApi(UIAH_UNINITIALIZE, NULL); }
return retval; }
/***************************************************************************\
* ClearUserApiHook * * This function gets called when the module that contains the UserApiHook * is about to get unloaded. The unload happens when UnregisterUserApiHook * is called or the process that registered it exits. If this is the last unload, * we'll clear the globals containing the UserApiHook function addresses so we * don't do any more callouts. If we're not currently doing a callout, we'll * indicate that it's OK to unload the module. Otherwise, it'll get unloaded * when the last callout completes. * * History: * 10-Mar-2000 JerrySh Created. * 16-May-2000 JStall Changed to support uninitialize callback * 03-Apr-2001 Mohamed Added support for UIAH_UNHOOK logic. \***************************************************************************/ BOOL ClearUserApiHook( HMODULE hmod) { INITUSERAPIHOOK pfnInitUserApi = NULL; INITUSERAPIHOOK pfnSignalInitUserApi = NULL;
/*
* If this is the last reference to the UserApiHook module, clear the * global state. */ RtlEnterCriticalSection(&gcsUserApiHook); if (ghmodUserApiHook == hmod) { UserAssert(gcLoadUserApiHook > 0); UserAssertMsg0(gpfnInitUserApi != NULL, "Ensure gpfnInitUserApi properly set"); UserAssertMsg0(ghmodUserApiHook != NULL, "Should still have valid ghmodUserApiHook"); pfnInitUserApi = gpfnInitUserApi;
if (--gcLoadUserApiHook == 0) { /*
* Use the internal functions, so turn calling the hooks off. It is * very important to set gfUserApiHook FALSE here so that new calls * do not increment gcCallUserApiHook and keep the DLL from being * unloaded. */ gfUserApiHook = FALSE; ResetUserApiHook(&guah);
if (gcCallUserApiHook == 0) { /*
* We're not calling into it, we can free the module. * * FreeLibrary() will be called on this DLL in * ClientFreeLibrary() when this function returns. */ hmod = ghmodUserApiHook; ghmodUserApiHook = NULL; gpfnInitUserApi = NULL; } else { /*
* We're still calling into the module, so we can't free it yet. * This means we have to delay the last callback with UIAH_UNINITIALIZE * until we actually free the library. This will occur in * _EndUserApiHook(). However, we set pfnSignalInitUserApi to initiate * a callback with UIAH_UNHOOK to alert the module to this fact. */ hmod = NULL; pfnInitUserApi = NULL; pfnSignalInitUserApi = gpfnInitUserApi; ++gcLoadUserApiHook; } } else { /*
* This part of code should never be executed since we guard against * multiple loads of same DLL in xxxLoadUserApiHook. However, since * this is a load count and could conceivably be greater than 1, * this warning message is inserted to signal such an event. */ RIPMSG1(RIP_WARNING, " gcLoadUserApiHook: %lx > 1 in Clear Load", gcLoadUserApiHook); } }
RtlLeaveCriticalSection(&gcsUserApiHook);
/*
* Signal that hooks have been uninitialized but DLL can't be unloaded due to outstanding calls. */ if (pfnSignalInitUserApi != NULL) { RIPMSG2(RIP_WARNING, "Unhook from Clear Load %lx Call %lx", gcLoadUserApiHook, gcCallUserApiHook); pfnSignalInitUserApi(UIAH_UNHOOK, NULL);
/*
* After having returned from the DLL, we revalidate the state of the hooking world again. * The outstanding call that we were deferring in favor of, could have completed by now * and finding the load count greater than zero, it ignored completing the deferred cleanup * which we must now do at this point. */ RtlEnterCriticalSection(&gcsUserApiHook); UserAssert(gcLoadUserApiHook > 0); UserAssertMsg0(gpfnInitUserApi != NULL, "Ensure gpfnInitUserApi properly set"); UserAssertMsg0(ghmodUserApiHook != NULL, "Should still have valid ghmodUserApiHook"); pfnInitUserApi = gpfnInitUserApi;
if (--gcLoadUserApiHook == 0) { if (gcCallUserApiHook == 0) { /*
* The outstanding call has completed while we were * calling back and we can now safely clean up. * FreeLibrary() will be called on this DLL in * ClientFreeLibrary() when this function returns. */ hmod = ghmodUserApiHook; ghmodUserApiHook = NULL; gpfnInitUserApi = NULL; } else { /*
* The outstanding call into the DLL hasn't returned. However, we are done * from this point. The DLL has been notified of UNHOOK situation and the * rest of the cleanup will be done in _EndUserApiHook when the last call * into the DLL returns. */ hmod = NULL; pfnInitUserApi = NULL; } } else { /*
* This part of code should never be executed since we guard against * multiple loads of same DLL in xxxLoadUserApiHook. However, since * this is a load count and could conceivably be greater than 1, * this warning message is inserted to signal such an event. */ RIPMSG1(RIP_WARNING, " gcLoadUserApiHook: %lx > 1 in Clear Load", gcLoadUserApiHook); } RtlLeaveCriticalSection(&gcsUserApiHook); }
/*
* This is called in the case where the outstanding call into the DLL was completed in between * the two critical sections and we have completed the full cleanup at this end. */ if (pfnInitUserApi != NULL) { RIPMSG2(RIP_WARNING, "Uninit from Clear Load %lx Call %lx", gcLoadUserApiHook, gcCallUserApiHook); pfnInitUserApi(UIAH_UNINITIALIZE, NULL); }
return (hmod != NULL); }
/***************************************************************************\
* DefaultOWP * * This function provides an empty OWP implementation that can be safely * called while the UserApiHook DLL is being unloaded and we are resetting * the states. * * History: * 27-Apr-2000 JStall Created. \***************************************************************************/ BOOL CALLBACK DefaultOWP(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * pr, void ** pvCookie) { UNREFERENCED_PARAMETER(hwnd); UNREFERENCED_PARAMETER(message); UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(pr); UNREFERENCED_PARAMETER(pvCookie);
return FALSE; }
/***************************************************************************\
* MDIRedrawFrame * * * History: * 20-Apr-2001 Mohamed Created. \***************************************************************************/ void MDIRedrawFrame( HWND hwndChild, BOOL fAdd) { BEGIN_USERAPIHOOK() guah.pfnMDIRedrawFrame(hwndChild, fAdd); END_USERAPIHOOK() }
void RealMDIRedrawFrame( HWND hwndChild, BOOL fAdd) { UNREFERENCED_PARAMETER(fAdd); NtUserRedrawFrame(hwndChild); }
/***************************************************************************\
* ResetUserApiHook * * This function gets called to reset the UserApiHook function pointers to * the internal (default) implementations of the functions. This is done * when any installed UserApiHook is being removed by calling * UnregisterUserApiHook(). * * History: * 28-Mar-2000 JStall Created. * 28-Oct-2000 mohamed Added GetSystemMetrics and SystemParametersInfo hooks. \***************************************************************************/ void ResetUserApiHook(USERAPIHOOK * puah) { puah->cbSize = sizeof(USERAPIHOOK); puah->pfnDefWindowProcA = RealDefWindowProcA; puah->pfnDefWindowProcW = RealDefWindowProcW; puah->mmDWP.rgb = NULL; puah->mmDWP.cb = 0; puah->pfnGetScrollInfo = RealGetScrollInfo; puah->pfnSetScrollInfo = RealSetScrollInfo; puah->pfnEnableScrollBar = RealEnableScrollBar; puah->pfnAdjustWindowRectEx = RealAdjustWindowRectEx; puah->pfnSetWindowRgn = RealSetWindowRgn; puah->uoiWnd.pfnBeforeOWP = DefaultOWP; puah->uoiWnd.pfnAfterOWP = DefaultOWP; puah->uoiWnd.mm.rgb = NULL; puah->uoiWnd.mm.cb = 0; puah->uoiDlg.pfnBeforeOWP = DefaultOWP; puah->uoiDlg.pfnAfterOWP = DefaultOWP; puah->uoiDlg.mm.rgb = NULL; puah->uoiDlg.mm.cb = 0; puah->pfnGetSystemMetrics = RealGetSystemMetrics; puah->pfnSystemParametersInfoA = RealSystemParametersInfoA; puah->pfnSystemParametersInfoW = RealSystemParametersInfoW; puah->pfnForceResetUserApiHook = ForceResetUserApiHook; puah->pfnDrawFrameControl = RealDrawFrameControl; puah->pfnDrawCaption = RealDrawCaption; puah->pfnMDIRedrawFrame = RealMDIRedrawFrame; }
/***************************************************************************\
* ForceResetUserApiHook * * NOTE : This is an API function that is called by external clients. * * This function gets called to force a reset of the UserApiHook function * pointers. This is done usually by the hooked DLL in the case when it is * about to be unloaded by anyone other than WindowManager and is done to * prevent future calls into that DLL. It is to be noted however, that * WindowManger still believes that it is hooked * * Note: * 1- This function is meant to be called only by hooking dll inside * DllMain when recieving a DLL_PROCESS_DETACH message. A check is * made on the LoaderLock to verify. * 2- No serialization is done based on the assumption that the call * is made during DLL_PROCESS_DETACH and hence there is only the * main thread. * * History: * 02-Feb-2001 mohamed Created. \***************************************************************************/ BOOL ForceResetUserApiHook( HMODULE hmod) { /*
* Verify that the calling module is indeed the same hooking module and that * we are indeed being called from DllMain by verifying that we are inside * the loader lock. */
if (ghmodUserApiHook != hmod || !RtlIsThreadWithinLoaderCallout()){ return FALSE; }
/*
* Reset the function pointers back to Window Manager native functions and * reset the global dll initialization function pointer to prevent calls * into hooked dll with un\initialization messages. */
ResetUserApiHook(&guah); gpfnInitUserApi = NULL; return TRUE; }
/***************************************************************************\
* _EndUserApiHook * * This function gets called after each hooked API function call from * END_USERAPIHOOK(). This provides a common place to clean up resources * that were delayed because they were in use during the hooked function * call. * * History: * 28-Mar-2000 JStall Created. * 16-May-2000 JStall Changed to support uninitialize callback \***************************************************************************/ void _EndUserApiHook() { UserAssert(gcCallUserApiHook > 0); if (InterlockedDecrement(&gcCallUserApiHook) == 0) { /*
* If the load count went to zero, free the library. */ if (gcLoadUserApiHook == 0) { HMODULE hmod = NULL; INITUSERAPIHOOK pfnInitUserApi = NULL;
RtlEnterCriticalSection(&gcsUserApiHook); if (gcLoadUserApiHook == 0) { UserAssertMsg0(ghmodUserApiHook != NULL, "Should still have valid ghmodUserApiHook"); UserAssertMsg0(gpfnInitUserApi != NULL, "Should still have valid gpfnInitUserApi");
hmod = ghmodUserApiHook; pfnInitUserApi = gpfnInitUserApi; ghmodUserApiHook = NULL; gpfnInitUserApi = NULL; }
RtlLeaveCriticalSection(&gcsUserApiHook);
/*
* Make the callback that we delayed from ClearUserApiHook() * because there was still an outstanding API call. */ if (pfnInitUserApi != NULL) { RIPMSG2(RIP_WARNING, "Uninit from End Load %lx Call %lx", gcLoadUserApiHook, gcCallUserApiHook); pfnInitUserApi(UIAH_UNINITIALIZE, NULL); }
if (hmod != NULL) { FreeLibrary(hmod); } } } }
/***************************************************************************\
* DefWindowProcWorker * * Handles any messages that can be dealt with wholly on the client and * passes the rest to the server. * * 03-31-92 DarrinM Created. \***************************************************************************/
LRESULT DefWindowProcWorker( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD fAnsi) { if (ghmodUserApiHook) { if (fAnsi) { return DefWindowProcA(HWq(pwnd), message, wParam, lParam); } else { return DefWindowProcW(HWq(pwnd), message, wParam, lParam); } } return RealDefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi); }
LRESULT RealDefWindowProcWorker( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD fAnsi) { HWND hwnd = HWq(pwnd); int icolBack; int icolFore; PWND pwndParent; HWND hwndDefIme; PWND pwndDefIme; PIMEUI pimeui;
#if DBG
if (!gfTurboDWP) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); } else { #endif
if (FDEFWINDOWMSG(message, DefWindowMsgs)) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); } else if (!FDEFWINDOWMSG(message, DefWindowSpecMsgs)) { return 0; }
/*
* Important: If you add cases to the switch statement below, * add the messages to server.c's gawDefWindowSpecMsgs. * Similarly if you add cases to dwp.c's DefWindowProc * which can come from the client, add the messages * to gawDefWindowMsgs. */
switch (message) { #ifdef LAME_BUTTON
case WM_NCLBUTTONDOWN: if (wParam == HTLAMEBUTTON && TestWF(pwnd, WEFLAMEBUTTON)) { CallLameButtonHandler(pwnd, hwnd); } return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi);
case WM_SYSCHAR: if (wParam == LAMEBUTTONHOTKEY && (HIWORD(lParam) & SYS_ALTERNATE) && TestWF(pwnd, WEFLAMEBUTTON)) { CallLameButtonHandler(pwnd, hwnd); } return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi);
case WM_SYSCOMMAND: if (wParam == SC_LAMEBUTTON && TestWF(pwnd, WEFLAMEBUTTON)) { CallLameButtonHandler(pwnd, hwnd); } return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); #endif // LAME_BUTTON
case WM_HELP: { PWND pwndDest;
/*
* If this window is a child window, Help message must be passed on * to it's parent; Else, this must be passed on to the owner window. */ pwndDest = (TestwndChild(pwnd) ? pwnd->spwndParent : pwnd->spwndOwner); if (pwndDest) { pwndDest = REBASEPTR(pwnd, pwndDest); if (pwndDest != _GetDesktopWindow()) return SendMessageW(HWq(pwndDest), WM_HELP, wParam, lParam);; } return(0L); }
case WM_MOUSEWHEEL: if (TestwndChild(pwnd)) { pwndParent = REBASEPWND(pwnd, spwndParent); SendMessageW(HW(pwndParent), WM_MOUSEWHEEL, wParam, lParam); } break;
case WM_CONTEXTMENU: if (TestwndChild(pwnd)) { pwndParent = REBASEPWND(pwnd, spwndParent); SendMessageW(HW(pwndParent), WM_CONTEXTMENU, (WPARAM)hwnd, lParam); } break;
/*
* Default handling for WM_CONTEXTMENU support */ case WM_RBUTTONUP: if (TestWF(pwnd, WEFLAYOUTRTL)) { lParam = MAKELONG(pwnd->rcClient.right - GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) + pwnd->rcClient.top); } else { lParam = MAKELONG(GET_X_LPARAM(lParam) + pwnd->rcClient.left, GET_Y_LPARAM(lParam) + pwnd->rcClient.top); } SendMessageWorker(pwnd, WM_CONTEXTMENU, (WPARAM)hwnd, lParam, fAnsi); break;
case WM_APPCOMMAND: if (TestwndChild(pwnd)) { /*
* Bubble the message to the parent */ pwndParent = REBASEPWND(pwnd, spwndParent); return SendMessageW(HW(pwndParent), WM_APPCOMMAND, wParam, lParam); } else { /*
* Call the server side to send the shell hook HSHELL_APPCOMMAND */ return CsSendMessage(hwnd, WM_APPCOMMAND, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); } break;
/*
* Default handling for WM_APPCOMMAND support */ case WM_NCXBUTTONUP: case WM_XBUTTONUP: { WORD cmd; WORD keystate; LPARAM lParamAppCommand;
switch (GET_XBUTTON_WPARAM(wParam)) { case XBUTTON1: cmd = APPCOMMAND_BROWSER_BACKWARD; break;
case XBUTTON2: cmd = APPCOMMAND_BROWSER_FORWARD; break;
default: cmd = 0; break; }
if (cmd == 0) { break; }
cmd |= FAPPCOMMAND_MOUSE; if (message == WM_XBUTTONUP) { keystate = GET_KEYSTATE_WPARAM(wParam); } else { keystate = GetMouseKeyState(); }
lParamAppCommand = MAKELPARAM(keystate, cmd); SendMessageWorker(pwnd, WM_APPCOMMAND, (WPARAM)hwnd, lParamAppCommand, fAnsi); break; }
case WM_WINDOWPOSCHANGED: { PWINDOWPOS ppos = (PWINDOWPOS)lParam;
if (!(ppos->flags & SWP_NOCLIENTMOVE)) { POINT pt = {pwnd->rcClient.left, pwnd->rcClient.top}; pwndParent = REBASEPWND(pwnd, spwndParent);
if (pwndParent != _GetDesktopWindow()) { pt.x -= pwndParent->rcClient.left; pt.y -= pwndParent->rcClient.top; }
SendMessageWorker(pwnd, WM_MOVE, FALSE, MAKELPARAM(pt.x, pt.y), fAnsi); }
if ((ppos->flags & SWP_STATECHANGE) || !(ppos->flags & SWP_NOCLIENTSIZE)) { UINT cmd; RECT rc;
if (TestWF(pwnd, WFMINIMIZED)) cmd = SIZEICONIC; else if (TestWF(pwnd, WFMAXIMIZED)) cmd = SIZEFULLSCREEN; else cmd = SIZENORMAL;
/*
* HACK ALERT: * If the window is minimized then the real client width and height are * zero. But, in win3.1 they were non-zero. Under Chicago, PrintShop * Deluxe ver 1.2 hits a divide by zero. To fix this we fake the width * and height for old apps to be non-zero values. * GetClientRect does that job for us. */ _GetClientRect(pwnd, &rc); SendMessageWorker(pwnd, WM_SIZE, cmd, MAKELONG(rc.right - rc.left, rc.bottom - rc.top), fAnsi); } return 0; }
case WM_MOUSEACTIVATE: { PWND pwndT; LRESULT lt;
/*
* GetChildParent returns either a kernel pointer or NULL. */ pwndT = GetChildParent(pwnd); if (pwndT != NULL) { pwndT = REBASEPTR(pwnd, pwndT); lt = SendMessageWorker(pwndT, WM_MOUSEACTIVATE, wParam, lParam, fAnsi); if (lt != 0) return lt; }
/*
* Moving, sizing or minimizing? Activate AFTER we take action. */ return ((LOWORD(lParam) == HTCAPTION) && (HIWORD(lParam) == WM_LBUTTONDOWN )) ? (LONG)MA_NOACTIVATE : (LONG)MA_ACTIVATE; }
case WM_CTLCOLORSCROLLBAR: if ((gpsi->BitCount < 8) || (SYSRGB(3DHILIGHT) != SYSRGB(SCROLLBAR)) || (SYSRGB(3DHILIGHT) == SYSRGB(WINDOW))) { /*
* Remove call to UnrealizeObject(). GDI Handles this for * brushes on NT. * * UnrealizeObject(ghbrGray); */
SetBkColor((HDC)wParam, SYSRGB(3DHILIGHT)); SetTextColor((HDC)wParam, SYSRGB(3DFACE)); return((LRESULT)gpsi->hbrGray); }
icolBack = COLOR_3DHILIGHT; icolFore = COLOR_BTNTEXT; goto SetColor;
case WM_CTLCOLORBTN: if (pwnd == NULL) goto ColorDefault;
if (TestWF(pwnd, WFWIN40COMPAT)) { icolBack = COLOR_3DFACE; icolFore = COLOR_BTNTEXT; } else { goto ColorDefault; } goto SetColor;
case WM_CTLCOLORSTATIC: case WM_CTLCOLORDLG: case WM_CTLCOLORMSGBOX: // We want static controls in dialogs to have the 3D
// background color, but statics in windows to inherit
// their parents' background.
if (pwnd == NULL) goto ColorDefault;
if (TestWF(pwnd, WFWIN40COMPAT)) { icolBack = COLOR_3DFACE; icolFore = COLOR_WINDOWTEXT; goto SetColor; } // ELSE FALL THRU...
case WM_CTLCOLOR: // here for WOW only
case WM_CTLCOLORLISTBOX: case WM_CTLCOLOREDIT: ColorDefault: icolBack = COLOR_WINDOW; icolFore = COLOR_WINDOWTEXT;
SetColor: { SetBkColor((HDC)wParam, gpsi->argbSystem[icolBack]); SetTextColor((HDC)wParam, gpsi->argbSystem[icolFore]); return (LRESULT)(SYSHBRUSH(icolBack)); }
case WM_NCHITTEST: return FindNCHit(pwnd, (LONG)lParam);
case WM_GETTEXT: if (wParam != 0) {
LPWSTR lpszText; UINT cchSrc;
if (pwnd->strName.Length) {
lpszText = REBASE(pwnd, strName.Buffer); cchSrc = (UINT)pwnd->strName.Length / sizeof(WCHAR);
if (fAnsi) {
LPSTR lpName = (LPSTR)lParam;
/*
* Non-zero retval means some text to copy out. Do not * copy out more than the requested byte count * 'chMaxCount'. */ cchSrc = WCSToMB(lpszText, cchSrc, (LPSTR *)&lpName, (UINT)(wParam - 1), FALSE);
lpName[cchSrc] = '\0';
} else {
LPWSTR lpwName = (LPWSTR)lParam;
cchSrc = min(cchSrc, (UINT)(wParam - 1)); RtlCopyMemory(lpwName, lpszText, cchSrc * sizeof(WCHAR)); lpwName[cchSrc] = 0; }
return cchSrc; }
/*
* else Null terminate the text buffer since there is no text. */ if (fAnsi) { ((LPSTR)lParam)[0] = 0; } else { ((LPWSTR)lParam)[0] = 0; } }
return 0;
case WM_GETTEXTLENGTH: if (pwnd->strName.Length) { UINT cch; if (fAnsi) { RtlUnicodeToMultiByteSize(&cch, REBASE(pwnd, strName.Buffer), pwnd->strName.Length); } else { cch = pwnd->strName.Length / sizeof(WCHAR); } return cch; } return 0L;
case WM_QUERYDRAGICON: /*
* If the window is WIN40COMPAT or has a kernel side procedure * do not attempt to look into the instance module */ if (TestWF(pwnd, WFWIN40COMPAT) || TestWF(pwnd, WFSERVERSIDEPROC)) { return 0; } /*
* For old apps, like the VB3 ones, try to load the icon from resources * This is how Win95 does. */ return (LRESULT)LoadIconW(KHANDLE_TO_HANDLE(pwnd->hModule), MAKEINTRESOURCE(1));
case WM_QUERYOPEN: case WM_QUERYENDSESSION: case WM_DEVICECHANGE: case WM_POWERBROADCAST: return TRUE;
case WM_KEYDOWN: if (wParam == VK_F10) { return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); } break;
case WM_SYSKEYDOWN: if ((HIWORD(lParam) & SYS_ALTERNATE) || (wParam == VK_F10) || (wParam == VK_ESCAPE)) return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); break;
case WM_UNICHAR: if (wParam == UNICODE_NOCHAR) { return FALSE; } break;
case WM_CHARTOITEM: case WM_VKEYTOITEM: /*
* Do default processing for keystrokes into owner draw listboxes. */ return -1;
case WM_ACTIVATE: if (LOWORD(wParam)) return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); break;
case WM_SHOWWINDOW: if (lParam != 0) return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); break;
case WM_DROPOBJECT: return DO_DROPFILE;
case WM_WINDOWPOSCHANGING: /*
* If the window's size is changing, adjust the passed-in size */ #define ppos ((WINDOWPOS *)lParam)
if (!(ppos->flags & SWP_NOSIZE)) return CsSendMessage(hwnd, message, wParam, lParam, 0L, FNID_DEFWINDOWPROC, fAnsi); #undef ppos
break;
case WM_KLUDGEMINRECT: { SHELLHOOKINFO shi; LPRECT lprc = (LPRECT)lParam;
shi.hwnd = (HWND)wParam; shi.rc.left = MAKELONG(lprc->left, lprc->top); shi.rc.top = MAKELONG(lprc->right, lprc->bottom);
if (gpsi->uiShellMsg == 0) SetTaskmanWindow(NULL); if (SendMessageWorker(pwnd, gpsi->uiShellMsg, HSHELL_GETMINRECT, (LPARAM)&shi, fAnsi)) { //
// Now convert the RECT back from two POINTS structures into two POINT
// structures.
//
lprc->left = (SHORT)LOWORD(shi.rc.left); // Sign extend
lprc->top = (SHORT)HIWORD(shi.rc.left); // Sign extend
lprc->right = (SHORT)LOWORD(shi.rc.top); // Sign extend
lprc->bottom = (SHORT)HIWORD(shi.rc.top); // Sign extend
} break; }
case WM_NOTIFYFORMAT: if (lParam == NF_QUERY) return(TestWF(pwnd, WFANSICREATOR) ? NFR_ANSI : NFR_UNICODE); break;
case WM_IME_KEYDOWN: if (fAnsi) PostMessageA(hwnd, WM_KEYDOWN, wParam, lParam); else PostMessageW(hwnd, WM_KEYDOWN, wParam, lParam); break;
case WM_IME_KEYUP: if (fAnsi) PostMessageA(hwnd, WM_KEYUP, wParam, lParam); else PostMessageW(hwnd, WM_KEYUP, wParam, lParam); break;
case WM_IME_CHAR: //if (TestCF(pwnd, CFIME))
// break;
if ( fAnsi ) { if( IsDBCSLeadByteEx(THREAD_CODEPAGE(),(BYTE)(wParam >> 8)) ) { PostMessageA(hwnd, WM_CHAR, (WPARAM)((BYTE)(wParam >> 8)), // leading byte
1L); PostMessageA(hwnd, WM_CHAR, (WPARAM)((BYTE)wParam), // trailing byte
1L); } else PostMessageA(hwnd, WM_CHAR, (WPARAM)(wParam), 1L); } else { PostMessageW(hwnd, WM_CHAR, wParam, 1L); } break;
case WM_IME_COMPOSITION: //if (TestCF(pwnd, CFIME))
// break;
if (lParam & GCS_RESULTSTR) { HIMC hImc; DWORD cbLen;
if ((hImc = fpImmGetContext(hwnd)) == NULL_HIMC) goto dwpime_ToIMEWnd_withchk;
if (fAnsi) { LPSTR pszBuffer, psz;
/*
* ImmGetComposition returns the size of buffer needed in byte. */ if (!(cbLen = fpImmGetCompositionStringA(hImc, GCS_RESULTSTR, NULL, 0))) { fpImmReleaseContext(hwnd, hImc); goto dwpime_ToIMEWnd_withchk; }
pszBuffer = psz = (LPSTR)UserLocalAlloc(HEAP_ZERO_MEMORY, cbLen + sizeof(CHAR));
if (pszBuffer == NULL) { fpImmReleaseContext(hwnd, hImc); goto dwpime_ToIMEWnd_withchk; }
fpImmGetCompositionStringA(hImc, GCS_RESULTSTR, psz, cbLen);
while (*psz) { if (IsDBCSLeadByteEx(THREAD_CODEPAGE(),*psz)) { if (*(psz+1)) { SendMessageA( hwnd, WM_IME_CHAR, MAKEWPARAM(MAKEWORD(*(psz+1), *psz), 0), 1L ); psz++; } psz++; } else SendMessageA( hwnd, WM_IME_CHAR, MAKEWPARAM(MAKEWORD(*(psz++), 0), 0), 1L ); }
UserLocalFree(pszBuffer);
fpImmReleaseContext(hwnd, hImc); } else { LPWSTR pwszBuffer, pwsz;
/*
* ImmGetComposition returns the size of buffer needed in byte */ if (!(cbLen = fpImmGetCompositionStringW(hImc, GCS_RESULTSTR, NULL, 0))) { fpImmReleaseContext(hwnd, hImc); goto dwpime_ToIMEWnd_withchk; }
pwszBuffer = pwsz = (LPWSTR)UserLocalAlloc(HEAP_ZERO_MEMORY, cbLen + sizeof(WCHAR));
if (pwszBuffer == NULL) { fpImmReleaseContext(hwnd, hImc); goto dwpime_ToIMEWnd_withchk; }
fpImmGetCompositionStringW(hImc, GCS_RESULTSTR, pwsz, cbLen);
while (*pwsz) SendMessageW(hwnd, WM_IME_CHAR, MAKEWPARAM(*pwsz++, 0), 1L);
UserLocalFree(pwszBuffer);
fpImmReleaseContext(hwnd, hImc); } }
/*
* Fall through to send to Default IME Window with checking * activated hIMC. */
case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: dwpime_ToIMEWnd_withchk: //if (TestCF(pwnd, CFIME))
// break;
if (GetClientInfo()->dwTIFlags & TIF_DISABLEIME) { break; } /*
* We assume this Wnd uses DefaultIMEWindow. * If this window has its own IME window, it have to call * ImmIsUIMessage().... */ hwndDefIme = fpImmGetDefaultIMEWnd(hwnd);
if (hwndDefIme == hwnd) { /*
* VC++ 1.51 TLW0NCL.DLL subclass IME class window * and pass IME messages to DefWindowProc(). */ RIPMSG1(RIP_WARNING, "IME Class window is hooked and IME message [%X] are sent to DefWindowProc", message); ImeWndProcWorker(pwnd, message, wParam, lParam, fAnsi); break; }
if ((pwndDefIme = ValidateHwndNoRip(hwndDefIme)) != NULL) { /*
* If hImc of this window is not activated for IME window, * we don't send WM_IME_NOTIFY. */ pimeui = ((PIMEWND)pwndDefIme)->pimeui; if (pimeui->hIMC == fpImmGetContext(hwnd)) return SendMessageWorker(pwndDefIme, message, wParam, lParam, fAnsi); else RIPMSG1(RIP_WARNING, "DefWindowProc can not send WM_IME_message [%X] now", message); } break;
dwpime_ToTopLevel_withchk: //if (TestCF(pwnd, CFIME))
// break;
/*
* We assume this Wnd uses DefaultIMEWindow. * If this window has its own IME window, it have to call * ImmIsUIMessage().... */ hwndDefIme = fpImmGetDefaultIMEWnd(hwnd);
if (hwndDefIme == hwnd) { /*
* VC++ 1.51 TLW0NCL.DLL subclass IME class window * and pass IME messages to DefWindowProc(). */ RIPMSG1(RIP_WARNING, "IME Class window is hooked and IME message [%X] are sent to DefWindowProc", message); ImeWndProcWorker(pwnd, message, wParam, lParam, fAnsi); break; }
pwndDefIme = ValidateHwndNoRip(hwndDefIme);
if ((pwndDefIme = ValidateHwndNoRip(hwndDefIme)) != NULL) { PWND pwndT, pwndParent;
pwndT = pwnd;
while (TestwndChild(pwndT)) { pwndParent = REBASEPWND(pwndT, spwndParent); if (GETPTI(pwndParent) != GETPTI(pwnd)) break; pwndT = pwndParent; }
/*
* If hImc of this window is not activated for IME window, * we don't send WM_IME_NOTIFY. */ if (pwndT != pwnd) { pimeui = ((PIMEWND)pwndDefIme)->pimeui; if (pimeui->hIMC == fpImmGetContext(hwnd)) return SendMessageWorker(pwndT, message, wParam, lParam, fAnsi); else RIPMSG1(RIP_WARNING, "DefWindowProc can not send WM_IME_message [%X] now", message); } else { /*
* Review !! * If this is the toplevel window, we pass messages to * the default IME window... */ return SendMessageWorker(pwndDefIme, message, wParam, lParam, fAnsi); } } break;
case WM_IME_NOTIFY: switch (wParam) { case IMN_OPENSTATUSWINDOW: case IMN_CLOSESTATUSWINDOW: #ifndef WKWOK_DEBUG
goto dwpime_ToIMEWnd_withchk; #endif
goto dwpime_ToTopLevel_withchk;
default: goto dwpime_ToIMEWnd_withchk; } break;
case WM_IME_REQUEST: switch (wParam) { case IMR_QUERYCHARPOSITION: goto dwpime_ToIMEWnd_withchk; default: break; } break;
case WM_IME_SYSTEM: if (wParam == IMS_SETACTIVECONTEXT) { RIPMSG0(RIP_WARNING, "DefWindowProc received unexpected WM_IME_SYSTEM"); break; }
/*
* IMS_SETOPENSTATUS is depended on the activated input context. * It needs to be sent to only the activated system window. */ if (wParam == IMS_SETOPENSTATUS) goto dwpime_ToIMEWnd_withchk;
/*
* Fall through to send to Default IME Window. */
case WM_IME_SETCONTEXT: //if (TestCF(pwnd, CFIME))
// break;
hwndDefIme = fpImmGetDefaultIMEWnd(hwnd);
if (hwndDefIme == hwnd) { /*
* VC++ 1.51 TLW0NCL.DLL subclass IME class window * and pass IME messages to DefWindowProc(). */ RIPMSG1(RIP_WARNING, "IME Class window is hooked and IME message [%X] are sent to DefWindowProc", message); ImeWndProcWorker(pwnd, message, wParam, lParam, fAnsi); break; }
if ((pwndDefIme = ValidateHwndNoRip(hwndDefIme)) != NULL) return SendMessageWorker(pwndDefIme, message, wParam, lParam, fAnsi);
break;
case WM_IME_SELECT: RIPMSG0(RIP_WARNING, "DefWindowProc should not receive WM_IME_SELECT"); break;
case WM_IME_COMPOSITIONFULL: //if (TestCF(pwnd, CFIME))
// break;
if (GETAPPVER() < VER40) { /*
* This is a temporary solution for win31app. * FEREVIEW: For M5 this will call WINNLS message mapping logic * -yutakan */ return SendMessageWorker(pwnd, WM_IME_REPORT, IR_FULLCONVERT, (LPARAM)0L, fAnsi); } break;
case WM_CHANGEUISTATE: { WORD wAction = LOWORD(wParam); WORD wFlags = HIWORD(wParam); BOOL bRealChange = FALSE;
/*
* Validate parameters and determine the flags that should actually be changed. */ if ((wFlags & ~UISF_VALID) || (wAction > UIS_LASTVALID) || lParam) { return 0; }
if (wAction == UIS_INITIALIZE) { wFlags = 0; if (TEST_KbdCuesPUSIF) { if (TEST_SRVIF(SRVIF_LASTRITWASKEYBOARD)) { wAction = UIS_CLEAR; } else { wAction = UIS_SET; } wFlags = UISF_HIDEFOCUS | UISF_HIDEACCEL; wParam = MAKEWPARAM(wAction, wFlags); } } else if (!TEST_KbdCuesPUSIF) { wFlags &= ~(UISF_HIDEFOCUS | UISF_HIDEACCEL); }
if (wFlags == 0) { return 0; }
UserAssert(wAction == UIS_SET || wAction == UIS_CLEAR); /*
* If the state is not going to change, there's nothing to do here */ if (wFlags & UISF_HIDEFOCUS) { bRealChange = (!!TestWF(pwnd, WEFPUIFOCUSHIDDEN)) ^ (wAction == UIS_SET); } if (wFlags & UISF_HIDEACCEL) { bRealChange |= (!!TestWF(pwnd, WEFPUIACCELHIDDEN)) ^ (wAction == UIS_SET); } if (wFlags & UISF_ACTIVE) { bRealChange |= (!!TestWF(pwnd, WEFPUIACTIVE)) ^ (wAction == UIS_SET); }
if (!bRealChange) { break; } /*
* Children pass this message up * Top level windows update send down to themselves WM_UPDATEUISTATE. * WM_UPDATEUISTATE will change the state bits and broadcast down the message */ if (TestwndChild(pwnd)) {
return SendMessageWorker(REBASEPWND(pwnd, spwndParent), WM_CHANGEUISTATE, wParam, lParam, fAnsi); } else { return SendMessageWorker(pwnd, WM_UPDATEUISTATE, wParam, lParam, fAnsi); }
} break;
case WM_QUERYUISTATE: return (TestWF(pwnd, WEFPUIFOCUSHIDDEN) ? UISF_HIDEFOCUS : 0) | (TestWF(pwnd, WEFPUIACCELHIDDEN) ? UISF_HIDEACCEL : 0) | (TestWF(pwnd, WEFPUIACTIVE) ? UISF_ACTIVE : 0); break; }
return 0;
#if DBG
} // gfTurboDWP
#endif
}
/***************************************************************************\
* CallWindowProc * * Calls pfn with the passed message parameters. If pfn is a server-side * window proc the server is called to deliver the message to the window. * Currently we have the following restrictions: * * 04-17-91 DarrinM Created. \***************************************************************************/
LRESULT WINAPI CallWindowProcAorW( WNDPROC pfn, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL bAnsi) // Denotes if input is Ansi or Unicode
{ PCALLPROCDATA pCPD; PWND pwnd;
/*
* Raid# 78954: SPY++ * * Under FE NT4.0 or NT5.0, the sytem sends WM_GETTEXTLENGTH * corresponding to WM_xxxGETTEXT to optimize buffer allocation. * This is really needed to avoid the buffer size inflation. * For some reasons, Spy++ passes NULL as pfn to CallWindowProc * */ if (pfn == NULL) { RIPMSG0(RIP_WARNING, "CallWidowProcAorW(): pfn == NULL!"); return 0L; }
// OPT!! check an ANSI\UNICODE table rather than fnDWORD
// OPT!! convert WM_CHAR family messages in line
/*
* Check if pfn is really a CallProcData Handle * if it is and there is no ANSI data then convert the handle * into an address; otherwise call the server for translation */ if (ISCPDTAG(pfn)) { if (pCPD = HMValidateHandleNoRip((HANDLE)pfn, TYPE_CALLPROC)) { if ((message >= WM_USER) || !MessageTable[message].bThunkMessage) { pfn = (WNDPROC)pCPD->pfnClientPrevious; } else { return CsSendMessage(hwnd, message, wParam, lParam, (ULONG_PTR)pfn, FNID_CALLWINDOWPROC, bAnsi); } } else { RIPMSG1(RIP_WARNING, "CallWindowProc tried using a deleted CPD %#p\n", pfn); return 0; } }
pwnd = ValidateHwnd(hwnd); return UserCallWinProcCheckWow(PACTCTXT(pwnd), pfn, hwnd, message, wParam, lParam, NULL, FALSE); }
FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, CallWindowProcA, WNDPROC, pfn, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI CallWindowProcA( WNDPROC pfn, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return CallWindowProcAorW(pfn, hwnd, message, wParam, lParam, TRUE); }
FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, CallWindowProcW, WNDPROC, pfn, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI CallWindowProcW( WNDPROC pfn, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return CallWindowProcAorW(pfn, hwnd, message, wParam, lParam, FALSE); }
/***************************************************************************\
* MenuWindowProc * * Calls the sever-side function xxxMenuWindowProc * * 07-27-92 Mikehar Created. \***************************************************************************/
FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, MenuWindowProcW, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI MenuWindowProcW( HWND hwnd, HWND hwndMDIClient, UINT message, WPARAM wParam, LPARAM lParam) { return CsSendMessage(hwnd, message, wParam, lParam, (ULONG_PTR)hwndMDIClient, FNID_MENU, FALSE); }
FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, MenuWindowProcA, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI MenuWindowProcA( HWND hwnd, HWND hwndMDIClient, UINT message, WPARAM wParam, LPARAM lParam) { return CsSendMessage(hwnd, message, wParam, lParam, (ULONG_PTR)hwndMDIClient, FNID_MENU, TRUE); }
/***************************************************************************\
* _ClientGetListboxString * * This special function exists because LB_GETTEXT and CB_GETLBTEXT don't have * buffer counts in them anywhere. Because there is no buffer count we have * no idea how much room to reserved in the shared memory stack for this * string to be copied into. The solution is to get the string length ahead * of time, and send the message with this buffer length. Since this buffer * length isn't a part of the original message, this routine is used for * just this purpose. * * This routine gets called from the server. * * 04-13-91 ScottLu Created. \***************************************************************************/
DWORD WINAPI _ClientGetListboxString( PWND pwnd, UINT msg, WPARAM wParam, LPSTR lParam, // May be a unicode or ANSI string
ULONG_PTR xParam, PROC xpfn) { return ((DWORD)((GENERICPROC)xpfn)(pwnd, msg, wParam, (LPARAM)lParam, xParam)); }
/***************************************************************************\
* DispatchMessageWorker * * Handles any messages that can be dealt with wholly on the client and * passes the rest to the server. * * 04-24-92 DarrinM Created. \***************************************************************************/ LRESULT DispatchMessageWorker( MSG *pmsg, BOOL fAnsi) { PWND pwnd; WPARAM wParamSaved; LRESULT lRet; BOOL bDoDbcsMessaging = FALSE;
/*
* Prevent apps from setting hi 16 bits so we can use them internally. */ if (pmsg->message & RESERVED_MSG_BITS) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"pmsg->message\" (%ld) to DispatchMessageWorker", pmsg->message);
return 0; }
if (pmsg->hwnd != NULL) { pwnd = ValidateHwnd(pmsg->hwnd); if (pwnd == NULL) { return 0; } pmsg->hwnd = HWq(pwnd); // get full 32-bit HWND in case this came from WoW
} else { pwnd = NULL; }
/*
* If this is a synchronous-only message (takes a pointer in wParam or * lParam), then don't allow this message to go through since those * parameters have not been thunked, and are pointing into outer-space * (which would case exceptions to occur). * * (This api is only called in the context of a message loop, and you * don't get synchronous-only messages in a message loop). */ if (TESTSYNCONLYMESSAGE(pmsg->message, pmsg->wParam)) { /*
* Fail if 32 bit app is calling. */ if (!(GetClientInfo()->dwTIFlags & TIF_16BIT)) { RIPERR0(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, "DispatchMessageWorker: must be sync only"); return FALSE; }
/*
* For wow apps, allow it to go through (for compatibility). Change * the message id so our code doesn't understand the message - wow * will get the message and strip out this bit before dispatching * the message to the application. */ pmsg->message |= MSGFLAG_WOW_RESERVED; }
/*
* Timer callbacks that don't go through window procs are sent with * the callback address in lParam. Identify and dispatch those timers. */ if ((pmsg->message == WM_TIMER) || (pmsg->message == WM_SYSTIMER)) { /*
* Console windows use WM_TIMER for the caret. However, they don't * use a timer callback, so if this is CSRSS and there's a WM_TIMER * for us, the only way lParam would be non-zero is if someone's trying * to make us fault. No, this isn't a nice thing to do, but there * are bad, bad people out there. Windows Bug #361246. */ if (pmsg->lParam != 0) { /*
* System timers must be executed on the server's context. */ if (pmsg->message == WM_SYSTIMER) { return NtUserDispatchMessage(pmsg); } else if (!gfServerProcess) { /*
* WM_TIMER with lParam could be an attack from * malicious apps. To make sure the call is legitimate, * let the kernel side validates it. */ if (!NtUserValidateTimerCallback(pmsg->lParam)) { RIPMSGF3(RIP_WARNING, "invalid timer: hwnd=%p, wParam=%p, lParam=%p", pmsg->hwnd, pmsg->wParam, pmsg->lParam); return 0; }
/*
* We can't really trust what's in lParam, so make sure we * handle any exceptions that occur during this call. */ try { /*
* Windows NT Bug #234292. * Since the called window/dialog proc may have a different * calling convention, we must wrap the call and, check esp * and replace with a good esp when the call returns. This * is what UserCallWinProc* does. */ lRet = UserCallWinProc(PACTCTXT(pwnd), (WNDPROC)pmsg->lParam, pmsg->hwnd, pmsg->message, pmsg->wParam, NtGetTickCount()); } except ((GetAppCompatFlags2(VER40) & GACF2_NO_TRYEXCEPT_CALLWNDPROC) ? EXCEPTION_CONTINUE_SEARCH : W32ExceptionHandler(FALSE, RIP_WARNING)) { /*
* Windows NT Bug #359866. * Some applications like Hagaki Studio 2000 need to handle * the exception in WndProc in their handler, even though it * skips the API calls. For those apps, we have to honor the * behavior of NT4, with no protection. */ lRet = 0; } return lRet; } } }
if (pwnd == NULL) { return 0; }
/*
* To be safe (in case some bizarre app wants to look at the message * again after dispatching it) save wParam so it can be restored after * RtlMBMessageWParamCharToWCS() or RtlWCSMessageToMB() mangle it. */ wParamSaved = pmsg->wParam;
/*
* Pass messages intended for server-side windows over to the server. * WM_PAINTs are passed over so the WFPAINTNOTPROCESSED code can be * executed. */ if (TestWF(pwnd, WFSERVERSIDEPROC) || (pmsg->message == WM_PAINT)) { if (fAnsi) { /*
* Setup DBCS Messaging for WM_CHAR... */ BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(pmsg->message,pmsg->wParam,TRUE);
/*
* Convert wParam to Unicode, if nessesary. */ RtlMBMessageWParamCharToWCS(pmsg->message, &pmsg->wParam); } lRet = NtUserDispatchMessage(pmsg); pmsg->wParam = wParamSaved; return lRet; }
/*
* If the dispatcher and the receiver are both ANSI or both UNICODE * then no message translation is necessary. NOTE: this test * assumes that fAnsi is FALSE or TRUE, not just zero or non-zero. */ if (!fAnsi != !TestWF(pwnd, WFANSIPROC)) { // before: if (fAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
if (PtiCurrent() != GETPTI(pwnd)) { RIPMSG0(RIP_WARNING, "message belongs to a different Q"); return 0; }
if (fAnsi) { /*
* Setup DBCS Messaging for WM_CHAR... */ BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA(pmsg->message,pmsg->wParam,TRUE);
/*
* Convert wParam to Unicode, if nessesary. */ RtlMBMessageWParamCharToWCS(pmsg->message, &pmsg->wParam); } else { /*
* Convert wParam to ANSI... */ RtlWCSMessageWParamCharToMB(pmsg->message, &pmsg->wParam);
/*
* Let's DBCS messaging for WM_CHAR.... */ BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_CLIENTW( pmsg->hwnd,pmsg->message,pmsg->wParam,pmsg->lParam, pmsg->time,pmsg->pt,bDoDbcsMessaging); } }
DispatchMessageAgain: lRet = UserCallWinProcCheckWow(pwnd->pActCtx, (WNDPROC)pwnd->lpfnWndProc, pmsg->hwnd, pmsg->message, pmsg->wParam, pmsg->lParam, &(pwnd->state), TRUE);
/*
* if we have DBCS TrailingByte that should be sent, send it here.. */ DISPATCH_DBCS_MESSAGE_IF_EXIST(pmsg->message,pmsg->wParam,bDoDbcsMessaging,DispatchMessage);
pmsg->wParam = wParamSaved; return lRet; }
/***************************************************************************\
* GetMessageTime (API) * * This API returns the time when the last message was read from * the current message queue. * * History: * 11-19-90 DavidPe Created. \***************************************************************************/
LONG GetMessageTime(VOID) { return (LONG)NtUserGetThreadState(UserThreadStateMessageTime); }
/***************************************************************************\
* GetMessageExtraInfo (API) * * History: * 28-May-1991 mikeke \***************************************************************************/
LPARAM GetMessageExtraInfo(VOID) { return (LPARAM)NtUserGetThreadState(UserThreadStateExtraInfo); }
FUNCLOG1(LOG_GENERAL, LPARAM, DUMMYCALLINGTYPE, SetMessageExtraInfo, LPARAM, lParam) LPARAM SetMessageExtraInfo(LPARAM lParam) { return (LPARAM)NtUserCallOneParam(lParam, SFI__SETMESSAGEEXTRAINFO); }
/***********************************************************************\
* InSendMessage (API) * * This function determines if the current thread is preocessing a message * from another application. * * History: * 01-13-91 DavidPe Ported. \***********************************************************************/
BOOL InSendMessage(VOID) { PCLIENTTHREADINFO pcti = GetClientInfo()->pClientThreadInfo;
if (pcti) { return TEST_BOOL_FLAG(pcti->CTIF_flags, CTIF_INSENDMESSAGE); } return NtUserGetThreadState(UserThreadStateInSendMessage) != ISMEX_NOSEND; } /***********************************************************************\
* InSendMessageEx (API) * * This function tells you what type of send message is being processed * by the application, if any * * History: * 01/22/97 GerardoB Created \***********************************************************************/
FUNCLOG1(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, InSendMessageEx, LPVOID, lpReserved) DWORD InSendMessageEx(LPVOID lpReserved) { PCLIENTTHREADINFO pcti = GetClientInfo()->pClientThreadInfo; UNREFERENCED_PARAMETER(lpReserved);
if (pcti && !TEST_FLAG(pcti->CTIF_flags, CTIF_INSENDMESSAGE)) { return ISMEX_NOSEND; } return (DWORD)NtUserGetThreadState(UserThreadStateInSendMessage); }
/***********************************************************************\
* GetCPD * * This function calls the server to allocate a CPD structure. * * History: * 11-15-94 JimA Created. \***********************************************************************/
ULONG_PTR GetCPD( KERNEL_PVOID pWndOrCls, DWORD options, ULONG_PTR dwData) { return NtUserGetCPD(HW(pWndOrCls), options, dwData); }
#ifdef BUILD_WOW6432
/***********************************************************************\
* MapKernelClientFnToClientFn * * Maps a function pointer from what the kernel expects to what the * client(user-mode) expects. * * History: * 11-15-98 PeterHal Created. \***********************************************************************/ WNDPROC_PWND MapKernelClientFnToClientFn( WNDPROC_PWND lpfnWndProc ) { KPKERNEL_ULONG_PTR pp;
for (pp = (KPKERNEL_ULONG_PTR)&gpsi->apfnClientA; pp < (KPKERNEL_ULONG_PTR) (&gpsi->apfnClientA+1); pp ++) { if ((KERNEL_ULONG_PTR)lpfnWndProc == *pp) { return (WNDPROC_PWND)((KERNEL_ULONG_PTR*) &pfnClientA) [ (pp - (KPKERNEL_ULONG_PTR)&gpsi->apfnClientA) ]; } }
for (pp = (KPKERNEL_ULONG_PTR)&gpsi->apfnClientW; pp < (KPKERNEL_ULONG_PTR) (&gpsi->apfnClientW+1); pp ++) { if ((KERNEL_ULONG_PTR)lpfnWndProc == *pp) { return (WNDPROC_PWND)((KERNEL_ULONG_PTR*) &pfnClientW) [ (pp - (KPKERNEL_ULONG_PTR)&gpsi->apfnClientW) ]; } }
return lpfnWndProc; } #endif
#ifdef GENERIC_INPUT
LRESULT APIENTRY DefRawInputProc( PRAWINPUT* paRawInput, INT nInput, UINT cbSizeHeader) { UNREFERENCED_PARAMETER(paRawInput); UNREFERENCED_PARAMETER(nInput);
if (cbSizeHeader != sizeof(RAWINPUTHEADER)) { return (LRESULT)-1; }
return 0; }
#endif
|