/**************************************************************************\ * Module Name: ntstubs.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * client side API stubs * * History: * 03-19-95 JimA Created. \**************************************************************************/ #include "precomp.h" #pragma hdrstop #define CLIENTSIDE 1 #include #include "ntsend.h" #include "cfgmgr32.h" #include "csrhlpr.h" WINUSERAPI BOOL WINAPI SetSysColors( int cElements, CONST INT * lpaElements, CONST COLORREF * lpaRgbValues) { return NtUserSetSysColors(cElements, lpaElements, lpaRgbValues, SSCF_NOTIFY | SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS); } HWND WOWFindWindow( LPCSTR pClassName, LPCSTR pWindowName) { return InternalFindWindowExA(NULL, NULL, pClassName, pWindowName, FW_16BIT); } #ifdef IMM_PER_LOGON VOID UpdatePerUserImmEnabling( VOID) { BOOL fRet = (BOOL)NtUserCallNoParam(SFI_UPDATEPERUSERIMMENABLING); if (fRet) { if (IS_IME_ENABLED()) { /* * hen ImmEnable flag is update and it gets enabled during * the last logon, we need to load Imm32.dll. */ HMODULE hModule = GetModuleHandleW(L"imm32.dll"); if (hModule == NULL) { LoadLibraryW(L"imm32.dll"); } } } } #endif FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, UpdatePerUserSystemParameters, HANDLE, hToken, DWORD, dwFlags) BOOL UpdatePerUserSystemParameters( HANDLE hToken, DWORD dwFlags) { TAGMSGF0(DBGTAG_KBD, "entering"); BEGINCALL() if ((dwFlags & UPUSP_USERLOGGEDON) || (dwFlags & (UPUSP_POLICYCHANGE | UPUSP_REMOTESETTINGS)) == 0) { /* * This is the first logon, need to initialize * the input locale. */ LANGID langidKbd; WCHAR wszKLName[KL_NAMELENGTH]; UINT uKlFlags = KLF_ACTIVATE | KLF_RESET; #ifdef IMM_PER_LOGON /* * Update the per user portion of the system metrics. * Continues even if this update fails. */ UpdatePerUserImmEnabling(); #endif /* * Initialize IME hotkeys before loading keyboard * layouts. */ CliImmInitializeHotKeys(ISHK_INITIALIZE, NULL); /* * Try to get the remote input locale first. */ if (!GetRemoteKeyboardLayout(wszKLName, &langidKbd)) { /* * If this is not a remote connection, * let's handle the input locale substition. */ uKlFlags |= KLF_SUBSTITUTE_OK; langidKbd = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); /* * Get the active keyboard layout from the registry. */ GetActiveKeyboardName(wszKLName); } LoadKeyboardLayoutWorker(NULL, wszKLName, langidKbd, uKlFlags, TRUE); /* * Now load the remaining preload keyboard layouts. */ LoadPreloadKeyboardLayouts(); } /* * Only if not just a policy change. */ if (dwFlags != UPUSP_POLICYCHANGE) { /* * FLush any MUI cach to be able to load strings latter for the new UIlangID. */ LdrFlushAlternateResourceModules(); } retval = (DWORD)NtUserUpdatePerUserSystemParameters(hToken, dwFlags); /* * Cause the wallpaper to be changed. */ SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, 0); ERRORTRAP(0); ENDCALL(BOOL); } DWORD Event( PEVENT_PACKET pep) { BEGINCALL() CheckDDECritOut; retval = (DWORD)NtUserEvent( pep); ERRORTRAP(0); ENDCALL(DWORD); } LONG GetClassWOWWords( HINSTANCE hInstance, LPCTSTR pString) { IN_STRING strClassName; PCLS pcls; /* * Make sure cleanup will work successfully */ strClassName.fAllocated = FALSE; BEGINCALL() FIRSTCOPYLPSTRW(&strClassName, pString); pcls = NtUserGetWOWClass(hInstance, strClassName.pstr); if (pcls == NULL) { MSGERRORCODE(ERROR_CLASS_DOES_NOT_EXIST); } pcls = (PCLS)((KPBYTE)pcls - GetClientInfo()->ulClientDelta); retval = _GetClassData(pcls, NULL, GCLP_WOWWORDS, TRUE); ERRORTRAP(0); CLEANUPLPSTRW(strClassName); ENDCALL(LONG); } /***************************************************************************\ * InitTask * * Initialize a WOW task. This is the first call a WOW thread makes to user. * NtUserInitTask returns NTSTATUS because if the thread fails to convert * to a GUI thread, STATUS_INVALID_SYSTEM_SERVICE is returned. * * 11-03-95 JimA Modified to use NTSTATUS. \***************************************************************************/ BOOL InitTask( UINT wVersion, DWORD dwAppCompatFlags, DWORD dwUserWOWCompatFlags, LPCSTR pszModName, LPCSTR pszBaseFileName, DWORD hTaskWow, DWORD dwHotkey, DWORD idTask, DWORD dwX, DWORD dwY, DWORD dwXSize, DWORD dwYSize) { IN_STRING strModName; IN_STRING strBaseFileName; NTSTATUS Status; /* * Make sure cleanup will work successfully */ strModName.fAllocated = FALSE; strBaseFileName.fAllocated = FALSE; BEGINCALL() FIRSTCOPYLPSTRW(&strModName, pszModName); COPYLPSTRW(&strBaseFileName, pszBaseFileName); Status = NtUserInitTask( wVersion, dwAppCompatFlags, dwUserWOWCompatFlags, strModName.pstr, strBaseFileName.pstr, hTaskWow, dwHotkey, idTask, dwX, dwY, dwXSize, dwYSize); retval = (Status == STATUS_SUCCESS); CLEANUPLPSTRW(strModName); CLEANUPLPSTRW(strBaseFileName); ERRORTRAP(FALSE); ENDCALL(BOOL); } HANDLE ConvertMemHandle( HANDLE hData, UINT cbNULL) { UINT cbData; LPBYTE lpData; BEGINCALL() if (GlobalFlags(hData) == GMEM_INVALID_HANDLE) { RIPMSG0(RIP_WARNING, "ConvertMemHandle hMem is not valid"); MSGERROR(); } if (!(cbData = (UINT)GlobalSize(hData))) { MSGERROR(); } USERGLOBALLOCK(hData, lpData); if (lpData == NULL) { MSGERROR(); } /* * Make sure text formats are NULL terminated. */ switch (cbNULL) { case 2: lpData[cbData - 2] = 0; // FALL THROUGH case 1: lpData[cbData - 1] = 0; } retval = (ULONG_PTR)NtUserConvertMemHandle(lpData, cbData); USERGLOBALUNLOCK(hData); ERRORTRAP(NULL); ENDCALL(HANDLE); } HANDLE CreateLocalMemHandle( HANDLE hMem) { UINT cbData; NTSTATUS Status; BEGINCALL() Status = NtUserCreateLocalMemHandle(hMem, NULL, 0, &cbData); if (Status != STATUS_BUFFER_TOO_SMALL) { RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure"); MSGERROR(); } if (!(retval = (ULONG_PTR)GlobalAlloc(GMEM_FIXED, cbData))) { MSGERROR(); } Status = NtUserCreateLocalMemHandle(hMem, (LPBYTE)retval, cbData, NULL); if (!NT_SUCCESS(Status)) { RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure"); UserGlobalFree((HANDLE)retval); MSGERROR(); } ERRORTRAP(0); ENDCALL(HANDLE); } HHOOK _SetWindowsHookEx( HANDLE hmod, LPTSTR pszLib, DWORD idThread, int nFilterType, PROC pfnFilterProc, DWORD dwFlags) { IN_STRING strLib; /* * Make sure cleanup will work successfully */ strLib.fAllocated = FALSE; BEGINCALL() FIRSTCOPYLPWSTROPT(&strLib, pszLib); retval = (ULONG_PTR)NtUserSetWindowsHookEx( hmod, strLib.pstr, idThread, nFilterType, pfnFilterProc, dwFlags); ERRORTRAP(0); CLEANUPLPWSTR(strLib); ENDCALL(HHOOK); } /***************************************************************************\ * SetWinEventHook * * History: * 1996-09-23 IanJa Created \***************************************************************************/ WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook( DWORD eventMin, DWORD eventMax, HMODULE hmodWinEventProc, // Must pass this if global! WINEVENTPROC lpfnWinEventProc, DWORD idProcess, // Can be zero; all processes DWORD idThread, // Can be zero; all threads DWORD dwFlags) { UNICODE_STRING str; PUNICODE_STRING pstr; WCHAR awchLib[MAX_PATH]; BEGINCALL() if ((dwFlags & WINEVENT_INCONTEXT) && (hmodWinEventProc != NULL)) { /* * If we're passing an hmod, we need to grab the file name of the * module while we're still on the client since module handles * are NOT global. */ USHORT cb; cb = (USHORT)(sizeof(WCHAR) * GetModuleFileNameW(hmodWinEventProc, awchLib, sizeof(awchLib)/sizeof(WCHAR))); if (cb == 0) { /* * hmod is bogus - return NULL. */ return NULL; } str.Buffer = awchLib; str.Length = cb - sizeof(UNICODE_NULL); str.MaximumLength = cb; pstr = &str; } else { pstr = NULL; } retval = (ULONG_PTR)NtUserSetWinEventHook( eventMin, eventMax, hmodWinEventProc, pstr, lpfnWinEventProc, idProcess, idThread, dwFlags); ERRORTRAP(0); ENDCALL(HWINEVENTHOOK); }; FUNCLOGVOID4(LOG_GENERAL, WINAPI, NotifyWinEvent, DWORD, dwEvent, HWND, hwnd, LONG, idObject, LONG, idChild) WINUSERAPI VOID WINAPI NotifyWinEvent( DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild) { BEGINCALLVOID() if (FEVENTHOOKED(dwEvent)) { NtUserNotifyWinEvent(dwEvent, hwnd, idObject, idChild); } ERRORTRAPVOID(); ENDCALLVOID(); } /***************************************************************************\ * RegisterUserApiHook * * History: * 03-Mar-2000 JerrySh Created. \***************************************************************************/ FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RegisterUserApiHook, HINSTANCE, hmod, INITUSERAPIHOOK, pfnUserApiHook) BOOL RegisterUserApiHook( HINSTANCE hmod, INITUSERAPIHOOK pfnUserApiHook) { WCHAR pwszLibFileName[MAX_PATH]; ULONG_PTR offPfnProc; IN_STRING strLib; /* * If we're passing an hmod, we need to grab the file name of the * module while we're still on the client since module handles * are NOT global. */ if (!GetModuleFileNameW(hmod, pwszLibFileName, ARRAY_SIZE(pwszLibFileName))) { return FALSE; } /* * Libraries are loaded at different linear addresses in different * process contexts. For this reason, we need to convert the window * proc address into an offset while setting the hook, and then convert * it back to a real per-process function pointer when calling a * hook. Do this by subtracting the 'hmod' (which is a pointer to the * linear and contiguous .exe header) from the function index. */ offPfnProc = (ULONG_PTR)pfnUserApiHook - (ULONG_PTR)hmod; /* * Make sure cleanup will work successfully */ strLib.fAllocated = FALSE; BEGINCALL() COPYLPWSTR(&strLib, pwszLibFileName); retval = (ULONG_PTR)NtUserRegisterUserApiHook( strLib.pstr, offPfnProc); ERRORTRAP(0); CLEANUPLPWSTR(strLib); ENDCALL(BOOL); } #ifdef MESSAGE_PUMP_HOOK /***************************************************************************\ * ResetMessagePumpHook * * ResetMessagePumpHook() resets the MessagePumpHook function pointers * to the internal "real" implementations. * * History: * 12-13-2000 JStall Created \***************************************************************************/ void ResetMessagePumpHook(MESSAGEPUMPHOOK * pwmh) { pwmh->cbSize = sizeof(MESSAGEPUMPHOOK); pwmh->pfnInternalGetMessage = NtUserRealInternalGetMessage; pwmh->pfnWaitMessageEx = NtUserRealWaitMessageEx; pwmh->pfnGetQueueStatus = RealGetQueueStatus; pwmh->pfnMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx; } /***************************************************************************\ * RegisterMessagePumpHook * * RegisterMessagePumpHook() sets up MPH's on the current thread. If this is * the first thread to be initialized in the process, the process-wide * initialization is also performed. If a thread has already been * initialized with MPH's, its "ref-count" is incremented on the existing * MPH's. * * NOTE: Unlike UserApiHook's, we make a callback while holding a critical * section. This is because it is infinitely easier to synchronize this * inside USER32.DLL rather than allowing re-entrancy in the DLL. It is * designed after DllMain(), where the loader also has a lock that is * sychronized. * * NOTE: Under the current implementation of MPH's, only one set of MPH's * per process can be installed. Each process may have a different set of * WMH's. * * History: * 12-13-2000 JStall Created \***************************************************************************/ BOOL RegisterMessagePumpHook( INITMESSAGEPUMPHOOK pfnInitMPH) { BOOL fInit = FALSE; BEGINCALL() retval = FALSE; RtlEnterCriticalSection(&gcsMPH); if (pfnInitMPH == NULL) { RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "Need valid pfnInitMPH"); goto errorexit; } if (gcLoadMPH == 0) { MESSAGEPUMPHOOK mphTemp; /* * First time we are initializing. */ UserAssertMsg0(gpfnInitMPH == NULL, "MPH callback should not already be initialized"); gpfnInitMPH = pfnInitMPH; ResetMessagePumpHook(&mphTemp); if (!(gpfnInitMPH)(UIAH_INITIALIZE, &mphTemp) || (mphTemp.cbSize == 0)) { goto errorexit; } CopyMemory(&gmph, &mphTemp, mphTemp.cbSize); fInit = TRUE; } else { if (gpfnInitMPH == pfnInitMPH) { /* * Initializing a second time with the same callback. */ fInit = TRUE; } } if (fInit) { /* * Initialize MPH's on this thread. */ if (NtUserCallNoParam(SFI__DOINITMESSAGEPUMPHOOK)) { if (gcLoadMPH++ == 0) { InterlockedExchange(&gfMessagePumpHook, TRUE); } retval = TRUE; } } ERRORTRAP(0); RtlLeaveCriticalSection(&gcsMPH); ENDCALL(BOOL); } /***************************************************************************\ * UnregisterMessagePumpHook * * UnregisterMessagePumpHook() decrements the count of WMH's on the current * thread. When this count reaches 0, WMH's are uninstalled from the * current thread. When the global WMH count reaches 0, WMH's are uninstalled * from the entire process. * * NOTE: See RegisterMessagePumpHook() about use of the critical section. * * History: * 12-13-2000 JStall Created \***************************************************************************/ BOOL UnregisterMessagePumpHook( VOID) { BEGINCALL() RtlEnterCriticalSection(&gcsMPH); if (gcLoadMPH <= 0) { RIPMSG0(RIP_ERROR, "UninitMessagePumpHook: Called without matching Init()"); goto errorexit; } /* * Uninitialize this thread's WMH. When the reference count reaches 0, the * thread will no longer be hooked. */ if (!NtUserCallNoParam(SFI__DOUNINITMESSAGEPUMPHOOK)) { goto errorexit; } if (--gcLoadMPH == 0) { /* * Final unload: make callback and reset */ InterlockedExchange(&gfMessagePumpHook, FALSE); (gpfnInitMPH)(UIAH_UNINITIALIZE, NULL); ResetMessagePumpHook(&gmph); gpfnInitMPH = NULL; } retval = TRUE; ERRORTRAP(0); RtlLeaveCriticalSection(&gcsMPH); ENDCALL(BOOL); } #endif // MESSAGE_PUMP_HOOK /***************************************************************************\ * ThunkedMenuItemInfo * * History: * 07-22-96 GerardoB - Added header and Fixed up for 5.0 \***************************************************************************/ BOOL ThunkedMenuItemInfo( HMENU hMenu, UINT nPosition, BOOL fByPosition, BOOL fInsert, LPMENUITEMINFOW lpmii, BOOL fAnsi) { MENUITEMINFOW mii; IN_STRING strItem; /* * Make sure cleanup will work successfully */ strItem.fAllocated = FALSE; BEGINCALL() /* * Make a local copy so we can make changes */ mii = *(LPMENUITEMINFO)(lpmii); strItem.pstr = NULL; if (mii.fMask & MIIM_BITMAP) { if (((HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem)) < HBMMENU_MAX) && IS_PTR(mii.hbmpItem)) { /* * Looks like the user was trying to insert one of the * HBMMENU_* bitmaps, but stuffed some data in the HIWORD. * We know the HIWORD data is invalid because the LOWORD * handle is below the GDI minimum. */ RIPMSG1(RIP_WARNING, "Invalid HIWORD data (0x%04X) for HBMMENU_* bitmap.", HIWORD(HandleToUlong(mii.hbmpItem))); mii.hbmpItem = (HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem)); } else if (!IS_PTR(mii.hbmpItem) && mii.hbmpItem >= HBMMENU_MAX) { /* * The app is passing a 16-bit GDI handle. GDI handles this * on the client-side, but not on the kernel side. So * convert it to 32-bits. This fixes bug 201493 in * Macromedia Director. */ HBITMAP hbmNew = GdiFixUpHandle(mii.hbmpItem); if (hbmNew) { RIPMSGF2(RIP_WARNING, "Fix 16-bit bitmap handle 0x%x to 0x%x", mii.hbmpItem, hbmNew); mii.hbmpItem = hbmNew; } } } if (mii.fMask & MIIM_STRING) { if (fAnsi) { FIRSTCOPYLPSTROPTW(&strItem, mii.dwTypeData); } else { FIRSTCOPYLPWSTROPT(&strItem, mii.dwTypeData); } } retval = (DWORD)NtUserThunkedMenuItemInfo(hMenu, nPosition, fByPosition, fInsert, &mii, strItem.pstr); ERRORTRAP(FALSE); CLEANUPLPSTRW(strItem); ENDCALL(BOOL); } /***************************************************************************\ * DrawCaption * * History: * 16-April-2001 Mohamed Hooked API and created this wrapper. \***************************************************************************/ FUNCLOG4( LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DrawCaption, HWND, hwnd, HDC, hdc, CONST RECT*, lprc, UINT, flags) BOOL DrawCaption( HWND hwnd, HDC hdc, CONST RECT *lprc, UINT flags) { BOOL bRet; BEGIN_USERAPIHOOK() bRet = guah.pfnDrawCaption(hwnd, hdc, lprc, flags); END_USERAPIHOOK() return bRet; } BOOL RealDrawCaption( HWND hwnd, HDC hdc, CONST RECT *lprc, UINT flags) { HDC hdcr; BEGINCALL() if (IsMetaFile(hdc)) { return FALSE; } hdcr = GdiConvertAndCheckDC(hdc); if (hdcr == (HDC)0) { return FALSE; } retval = (DWORD)NtUserDrawCaption(hwnd, hdcr, lprc, flags); ERRORTRAP(0); ENDCALL(BOOL); } FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetAsyncKeyState, int, vKey) SHORT GetAsyncKeyState( int vKey) { BEGINCALLCONNECT() /* * Asynchronous key state reports the PHYSICAL mouse button, * regardless of whether the buttons have been swapped or not. */ if ((vKey == VK_RBUTTON || vKey == VK_LBUTTON) && SYSMET(SWAPBUTTON)) { vKey ^= (VK_RBUTTON ^ VK_LBUTTON); } /* * If this is one of the common keys, see if we can pull it out * of the cache. */ if ((UINT)vKey < CVKASYNCKEYCACHE) { PCLIENTINFO pci = GetClientInfo(); if ((pci->dwAsyncKeyCache == gpsi->dwAsyncKeyCache) && !TestKeyRecentDownBit(pci->afAsyncKeyStateRecentDown, vKey)) { if (TestKeyDownBit(pci->afAsyncKeyState, vKey)) { retval = 0x8000; } else { retval = 0; } return (SHORT)retval; } } retval = (DWORD)NtUserGetAsyncKeyState(vKey); ERRORTRAP(0); ENDCALL(SHORT); } FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetKeyState, int, vKey) SHORT GetKeyState( int vKey) { BEGINCALLCONNECT() /* * If this is one of the common keys, see if we can pull it out * of the cache. */ if ((UINT)vKey < CVKKEYCACHE) { PCLIENTINFO pci = GetClientInfo(); if (pci->dwKeyCache == gpsi->dwKeyCache) { retval = 0; if (TestKeyToggleBit(pci->afKeyState, vKey)) retval |= 0x0001; if (TestKeyDownBit(pci->afKeyState, vKey)) { /* * Used to be retval |= 0x8000.Fix for bug 28820; Ctrl-Enter * accelerator doesn't work on Nestscape Navigator Mail 2.0 */ retval |= 0xff80; // This is what 3.1 returned!!!! } return (SHORT)retval; } } retval = (DWORD)NtUserGetKeyState( vKey); ERRORTRAP(0); ENDCALL(SHORT); } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, OpenClipboard, HWND, hwnd) BOOL OpenClipboard( HWND hwnd) { BOOL fEmptyClient; BEGINCALL() retval = (DWORD)NtUserOpenClipboard(hwnd, &fEmptyClient); if (fEmptyClient) ClientEmptyClipboard(); ERRORTRAP(0); ENDCALL(BOOL); } BOOL _PeekMessage( LPMSG pmsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg, BOOL bAnsi) { BEGINCALL() if (bAnsi) { // // If we have pushed message for DBCS messaging, we should pass this one // to Apps at first... // GET_DBCS_MESSAGE_IF_EXIST( PeekMessage,pmsg,wMsgFilterMin,wMsgFilterMax,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE)); } retval = (DWORD)NtUserPeekMessage( pmsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); if (retval) { // May have a bit more work to do if this MSG is for an ANSI app if (bAnsi) { if (RtlWCSMessageWParamCharToMB(pmsg->message, &(pmsg->wParam))) { WPARAM dwAnsi = pmsg->wParam; // // Build DBCS-ware wParam. (for EM_SETPASSWORDCHAR...) // BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_SERVER( pmsg,dwAnsi,TRUE,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE)); } else { retval = 0; } } else { // // Only LOWORD of WPARAM is valid for WM_CHAR.... // (Mask off DBCS messaging information.) // BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_SERVER(pmsg->message,pmsg->wParam); } } ExitPeekMessage: ERRORTRAP(0); ENDCALL(BOOL); } LONG_PTR _SetWindowLongPtr( HWND hwnd, int nIndex, LONG_PTR dwNewLong, BOOL bAnsi) { PWND pwnd; LONG_PTR dwOldLong; DWORD dwCPDType = 0; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) return 0; if (TestWF(pwnd, WFDIALOGWINDOW)) { switch (nIndex) { case DWLP_DLGPROC: // See similar case GWL_WNDPROC /* * Hide the window proc from other processes */ if (!TestWindowProcess(pwnd)) { RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied to hwnd (%#lx) in _SetWindowLong", hwnd); return 0; } /* * Get the old window proc address */ dwOldLong = (LONG_PTR)PDLG(pwnd)->lpfnDlg; /* * We always store the actual address in the wndproc; We only * give the CallProc handles to the application */ UserAssert(!ISCPDTAG(dwOldLong)); /* * May need to return a CallProc handle if there is an * Ansi/Unicode tranistion */ if (bAnsi != ((PDLG(pwnd)->flags & DLGF_ANSI) ? TRUE : FALSE)) { dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI; } /* * If we detected a transition create a CallProc handle for * this type of transition and this wndproc (dwOldLong) */ if (dwCPDType) { ULONG_PTR cpd; cpd = GetCPD(pwnd, dwCPDType | CPD_DIALOG, dwOldLong); if (cpd) { dwOldLong = cpd; } else { RIPMSGF0(RIP_WARNING, "[DWL_DLGPROC]: Unable to alloc CPD handle"); } } /* * Convert a possible CallProc Handle into a real address. * The app may have kept the CallProc Handle from some * previous mixed GetClassinfo or SetWindowLong. * * WARNING bAnsi is modified here to represent real type of * proc rather than if SetWindowLongA or W was called */ if (ISCPDTAG(dwNewLong)) { PCALLPROCDATA pCPD; if (pCPD = HMValidateHandleNoRip((HANDLE)dwNewLong, TYPE_CALLPROC)) { dwNewLong = KERNEL_ULONG_PTR_TO_ULONG_PTR(pCPD->pfnClientPrevious); bAnsi = pCPD->wType & CPD_UNICODE_TO_ANSI; } } /* * If an app 'unsubclasses' a server-side window proc we need to * restore everything so SendMessage and friends know that it's * a server-side proc again. Need to check against client side * stub addresses. */ PDLG(pwnd)->lpfnDlg = (DLGPROC)dwNewLong; if (bAnsi) { PDLG(pwnd)->flags |= DLGF_ANSI; } else { PDLG(pwnd)->flags &= ~DLGF_ANSI; } return dwOldLong; case DWLP_USER: #ifdef BUILD_WOW6432 // kernel has special handling of DWLP_USER nIndex = sizeof(KERNEL_LRESULT) + sizeof(KERNEL_PVOID); #endif case DWLP_MSGRESULT: break; default: if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) { RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, ""); return 0; } } } BEGINCALL() /* * If this is a listbox window and the listbox structure has * already been initialized, don't allow the app to override the * owner draw styles. We need to do this since Windows only * used the styles in creating the structure, but we also use * them to determine if strings need to be thunked. * */ if (nIndex == GWL_STYLE && GETFNID(pwnd) == FNID_LISTBOX && ((PLBWND)pwnd)->pLBIV != NULL && (!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) { #if DBG LONG_PTR dwDebugLong = dwNewLong; #endif dwNewLong &= ~(LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS); dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS); #if DBG if (dwDebugLong != dwNewLong) { RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS."); } #endif } retval = (ULONG_PTR)NtUserSetWindowLongPtr( hwnd, nIndex, dwNewLong, bAnsi); ERRORTRAP(0); ENDCALL(LONG_PTR); } #ifdef _WIN64 LONG _SetWindowLong( HWND hwnd, int nIndex, LONG dwNewLong, BOOL bAnsi) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) return 0; if (TestWF(pwnd, WFDIALOGWINDOW)) { switch (nIndex) { case DWLP_DLGPROC: // See similar case GWLP_WNDPROC RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetWindowLong: invalid index %d", nIndex); return 0; case DWLP_MSGRESULT: case DWLP_USER: break; default: if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) { RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, ""); return 0; } } } BEGINCALL() /* * If this is a listbox window and the listbox structure has * already been initialized, don't allow the app to override the * owner draw styles. We need to do this since Windows only * used the styles in creating the structure, but we also use * them to determine if strings need to be thunked. * */ if (nIndex == GWL_STYLE && GETFNID(pwnd) == FNID_LISTBOX && ((PLBWND)pwnd)->pLBIV != NULL && (!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) { #if DBG LONG dwDebugLong = dwNewLong; #endif dwNewLong &= ~(LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS); dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS); #if DBG if (dwDebugLong != dwNewLong) { RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS."); } #endif } retval = (DWORD)NtUserSetWindowLong( hwnd, nIndex, dwNewLong, bAnsi); ERRORTRAP(0); ENDCALL(LONG); } #endif BOOL TranslateMessageEx( CONST MSG *pmsg, UINT flags) { BEGINCALL() /* * Don't bother going over to the kernel if this isn't * key message. */ switch (pmsg->message) { case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: break; default: if (pmsg->message & RESERVED_MSG_BITS) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"pmsg->message\" (%ld) to TranslateMessageEx", pmsg->message); } MSGERROR(); } retval = (DWORD)NtUserTranslateMessage( pmsg, flags); ERRORTRAP(0); ENDCALL(BOOL); } BOOL TranslateMessage( CONST MSG *pmsg) { // // IME special key handling // if (LOWORD(pmsg->wParam) == VK_PROCESSKEY) { BOOL fResult; // // This vkey should be processed by IME. // fResult = fpImmTranslateMessage(pmsg->hwnd, pmsg->message, pmsg->wParam, pmsg->lParam); if (fResult) { return fResult; } } return TranslateMessageEx(pmsg, 0); } FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowRgn, HWND, hwnd, HRGN, hrgn, BOOL, bRedraw) BOOL SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw) { BOOL ret; BEGIN_USERAPIHOOK() ret = guah.pfnSetWindowRgn(hwnd, hrgn, bRedraw); END_USERAPIHOOK() return ret; } BOOL RealSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw) { BEGINCALL() retval = (DWORD)NtUserSetWindowRgn( hwnd, hrgn, bRedraw); if (retval) { DeleteObject(hrgn); } ERRORTRAP(0); ENDCALL(BOOL); } FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, InternalGetWindowText, HWND, hwnd, LPWSTR, pString, int, cchMaxCount) BOOL InternalGetWindowText( HWND hwnd, LPWSTR pString, int cchMaxCount) { BEGINCALL() retval = (DWORD)NtUserInternalGetWindowText( hwnd, pString, cchMaxCount); if (!retval) { *pString = (WCHAR)0; } ERRORTRAP(0); ENDCALL(BOOL); } int ToUnicode( UINT wVirtKey, UINT wScanCode, CONST BYTE *pKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags) { BEGINCALL() retval = (DWORD)NtUserToUnicodeEx( wVirtKey, wScanCode, pKeyState, pwszBuff, cchBuff, wFlags, (HKL)NULL); if (!retval) { *pwszBuff = L'\0'; } ERRORTRAP(0); ENDCALL(int); } int ToUnicodeEx( UINT wVirtKey, UINT wScanCode, CONST BYTE *pKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags, HKL hkl) { BEGINCALL() retval = (DWORD)NtUserToUnicodeEx( wVirtKey, wScanCode, pKeyState, pwszBuff, cchBuff, wFlags, hkl); if (!retval) { *pwszBuff = L'\0'; } ERRORTRAP(0); ENDCALL(int); } #if DBG FUNCLOGVOID2(LOG_GENERAL, DUMMYCALLINGTYPE, DbgWin32HeapFail, DWORD, dwFlags, BOOL, bFail) VOID DbgWin32HeapFail( DWORD dwFlags, BOOL bFail) { if ((dwFlags | WHF_VALID) != WHF_VALID) { RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags); return; } if (dwFlags & WHF_CSRSS) { // Tell csr about it CsrWin32HeapFail(dwFlags, bFail); } NtUserDbgWin32HeapFail(dwFlags, bFail); } FUNCLOG3(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, DbgWin32HeapStat, PDBGHEAPSTAT, phs, DWORD, dwLen, DWORD, dwFlags) DWORD DbgWin32HeapStat( PDBGHEAPSTAT phs, DWORD dwLen, DWORD dwFlags) { if ((dwFlags | WHF_VALID) != WHF_VALID) { RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags); return 0; } if (dwFlags & WHF_CSRSS) { return CsrWin32HeapStat(phs, dwLen); } else if (dwFlags & WHF_DESKTOP) { return NtUserDbgWin32HeapStat(phs, dwLen); } return 0; } #endif // DBG FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowStationUser, HWINSTA, hwinsta, PLUID, pluidUser, PSID, psidUser, DWORD, cbsidUser) BOOL SetWindowStationUser( HWINSTA hwinsta, PLUID pluidUser, PSID psidUser, DWORD cbsidUser) { LUID luidNone = { 0, 0 }; BEGINCALL() retval = (DWORD)NtUserSetWindowStationUser(hwinsta, pluidUser, psidUser, cbsidUser); /* * Load global atoms if the logon succeeded */ if (retval) { if (!RtlEqualLuid(pluidUser,&luidNone)) { /* * Reset console and load Nls data. */ Logon(TRUE); } else { /* * Flush NLS cache. */ Logon(FALSE); } retval = TRUE; } ERRORTRAP(0); ENDCALL(BOOL); } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetSystemCursor, HCURSOR, hcur, DWORD, id) BOOL SetSystemCursor( HCURSOR hcur, DWORD id) { BEGINCALL() if (hcur == NULL) { hcur = (HANDLE)LoadIcoCur(NULL, MAKEINTRESOURCE(id), RT_CURSOR, 0, 0, LR_DEFAULTSIZE); if (hcur == NULL) MSGERROR(); } retval = (DWORD)NtUserSetSystemCursor(hcur, id); ERRORTRAP(0); ENDCALL(BOOL); } HCURSOR FindExistingCursorIcon( LPWSTR pszModName, LPCWSTR pszResName, PCURSORFIND pcfSearch) { IN_STRING strModName; IN_STRING strResName; /* * Make sure cleanup will work successfully */ strModName.fAllocated = FALSE; strResName.fAllocated = FALSE; BEGINCALL() if (pszModName == NULL) pszModName = szUSER32; COPYLPWSTR(&strModName, pszModName); COPYLPWSTRID(&strResName, pszResName); retval = (ULONG_PTR)NtUserFindExistingCursorIcon(strModName.pstr, strResName.pstr, pcfSearch); ERRORTRAP(0); CLEANUPLPWSTR(strModName); CLEANUPLPWSTR(strResName); ENDCALL(HCURSOR); } BOOL _SetCursorIconData( HCURSOR hCursor, PCURSORDATA pcur) { IN_STRING strModName; IN_STRING strResName; /* * Make sure cleanup will work successfully */ strModName.fAllocated = FALSE; strResName.fAllocated = FALSE; BEGINCALL() COPYLPWSTROPT(&strModName, KPWSTR_TO_PWSTR(pcur->lpModName)); COPYLPWSTRIDOPT(&strResName, KPWSTR_TO_PWSTR(pcur->lpName)); retval = (DWORD)NtUserSetCursorIconData(hCursor, strModName.pstr, strResName.pstr, pcur); ERRORTRAP(0); CLEANUPLPWSTR(strModName); CLEANUPLPWSTR(strResName); ENDCALL(BOOL); } BOOL _DefSetText( HWND hwnd, LPCWSTR lpszText, BOOL bAnsi) { LARGE_STRING str; BEGINCALL() if (lpszText) { if (bAnsi) { RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&str, (LPSTR)lpszText, (UINT)-1); } else { RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&str, lpszText, (UINT)-1); } } retval = (DWORD)NtUserDefSetText(hwnd, lpszText ? &str : NULL); ERRORTRAP(0); ENDCALL(BOOL); } HWND _CreateWindowEx( DWORD dwExStyle, LPCTSTR pClassName, LPCTSTR pWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HMENU hmenu, HANDLE hModule, LPVOID pParam, DWORD dwFlags) { LARGE_IN_STRING strClassName; LARGE_STRING strWindowName; PLARGE_STRING pstrClassName; PLARGE_STRING pstrWindowName; DWORD dwExpWinVerAndFlags; /* * Make sure cleanup will work successfully */ strClassName.fAllocated = FALSE; /* * To be compatible with Chicago, we test the validity of * the ExStyle bits and fail if any invalid bits are found. * And for backward compatibilty with NT apps, we only fail for * new apps (post NT 3.1). */ // BOGUS if (dwExStyle & 0x00000800L) { dwExStyle |= WS_EX_TOOLWINDOW; dwExStyle &= 0xfffff7ffL; } dwExpWinVerAndFlags = (DWORD)(WORD)GETEXPWINVER(hModule); if ((dwExStyle & ~WS_EX_ALLVALID) && Is400Compat(dwExpWinVerAndFlags)) { RIPMSG1(RIP_WARNING, "Invalid 5.1 ExStyle 0x%x", dwExStyle); return NULL; } { BOOL fMDIchild = FALSE; MDICREATESTRUCT mdics; HMENU hSysMenu; BEGINCALL() if ((fMDIchild = (BOOL)(dwExStyle & WS_EX_MDICHILD))) { SHORTCREATE sc; PWND pwndParent; pwndParent = ValidateHwnd(hwndParent); if (pwndParent == NULL || GETFNID(pwndParent) != FNID_MDICLIENT) { RIPMSG0(RIP_WARNING, "Invalid parent for MDI child window"); MSGERROR(); } mdics.lParam = (LPARAM)pParam; pParam = &mdics; mdics.x = sc.x = x; mdics.y = sc.y = y; mdics.cx = sc.cx = nWidth; mdics.cy = sc.cy = nHeight; mdics.style = sc.style = dwStyle; mdics.hOwner = hModule; mdics.szClass = pClassName; mdics.szTitle = pWindowName; if (!CreateMDIChild(&sc, &mdics, dwExpWinVerAndFlags, &hSysMenu, pwndParent)) MSGERROR(); x = sc.x; y = sc.y; nWidth = sc.cx; nHeight = sc.cy; dwStyle = sc.style; hmenu = sc.hMenu; } /* * Set up class and window name. If the window name is an * ordinal, make it look like a string so the callback thunk * will be able to ensure it is in the correct format. */ pstrWindowName = NULL; if (dwFlags & CW_FLAGS_ANSI) { dwExStyle = dwExStyle | WS_EX_ANSICREATOR; if (IS_PTR(pClassName)) { RtlCaptureLargeAnsiString(&strClassName, (PCHAR)pClassName, TRUE); pstrClassName = (PLARGE_STRING)strClassName.pstr; } else { pstrClassName = (PLARGE_STRING)pClassName; } if (pWindowName != NULL) { if (*(PBYTE)pWindowName == 0xff) { strWindowName.bAnsi = TRUE; strWindowName.Buffer = (PVOID)pWindowName; strWindowName.Length = 3; strWindowName.MaximumLength = 3; } else { RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&strWindowName, (LPSTR)pWindowName, (UINT)-1); } pstrWindowName = &strWindowName; } } else { if (IS_PTR(pClassName)) { RtlInitLargeUnicodeString( (PLARGE_UNICODE_STRING)&strClassName.strCapture, pClassName, (UINT)-1); pstrClassName = (PLARGE_STRING)&strClassName.strCapture; } else { pstrClassName = (PLARGE_STRING)pClassName; } if (pWindowName != NULL) { if (pWindowName != NULL && *(PWORD)pWindowName == 0xffff) { strWindowName.bAnsi = FALSE; strWindowName.Buffer = (PVOID)pWindowName; strWindowName.Length = 4; strWindowName.MaximumLength = 4; } else { RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&strWindowName, pWindowName, (UINT)-1); } pstrWindowName = &strWindowName; } } dwExpWinVerAndFlags |= (dwFlags & (CW_FLAGS_DIFFHMOD | CW_FLAGS_VERSIONCLASS)); retval = (ULONG_PTR)VerNtUserCreateWindowEx( dwExStyle, pstrClassName, pstrWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, hmenu, hModule, pParam, dwExpWinVerAndFlags); // If this is an MDI child, we need to do some more to complete the // process of creating an MDI child. if (retval && fMDIchild) { MDICompleteChildCreation((HWND)retval, hSysMenu, ((dwStyle & WS_VISIBLE) != 0L), (BOOL)((dwStyle & WS_DISABLED)!= 0L)); } ERRORTRAP(0); CLEANUPLPSTRW(strClassName); ENDCALL(HWND); } } HKL _LoadKeyboardLayoutEx( HANDLE hFile, UINT offTable, PKBDTABLE_MULTI_INTERNAL pKbdTableMulti, HKL hkl, LPCTSTR pwszKL, UINT KbdInputLocale, UINT Flags) { IN_STRING strKL; /* * Make sure cleanup will work successfully */ strKL.fAllocated = FALSE; BEGINCALL() FIRSTCOPYLPWSTR(&strKL, pwszKL); retval = (ULONG_PTR)NtUserLoadKeyboardLayoutEx( hFile, offTable, pKbdTableMulti, hkl, strKL.pstr, KbdInputLocale, Flags); ERRORTRAP(0); CLEANUPLPWSTR(strKL); ENDCALL(HKL); } FUNCLOGVOID5(LOG_GENERAL, DUMMYCALLINGTYPE, mouse_event, DWORD, dwFlags, DWORD, dx, DWORD, dy, DWORD, dwData, ULONG_PTR, dwExtraInfo) VOID mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo) { INPUT ms; BEGINCALLVOID() ms.type = INPUT_MOUSE; ms.mi.dwFlags = dwFlags; ms.mi.dx = dx; ms.mi.dy = dy; ms.mi.mouseData = dwData; ms.mi.time = 0; ms.mi.dwExtraInfo = dwExtraInfo; NtUserSendInput(1, &ms, sizeof(INPUT)); ENDCALLVOID() } FUNCLOGVOID4(LOG_GENERAL, DUMMYCALLINGTYPE, keybd_event, BYTE, bVk, BYTE, bScan, DWORD, dwFlags, ULONG_PTR, dwExtraInfo) VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, ULONG_PTR dwExtraInfo) { INPUT kbd; BEGINCALLVOID() kbd.type = INPUT_KEYBOARD; kbd.ki.dwFlags = dwFlags; kbd.ki.wVk = bVk; kbd.ki.wScan = bScan; kbd.ki.time = 0; kbd.ki.dwExtraInfo = dwExtraInfo; NtUserSendInput(1, &kbd, sizeof(INPUT)); ENDCALLVOID() } /* * Message thunks */ MESSAGECALL(fnINWPARAMDBCSCHAR) { BEGINCALL() /* * The server always expects the characters to be unicode so * if this was generated from an ANSI routine convert it to Unicode */ if (bAnsi) { /* * Setup for DBCS Messaging.. */ BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(msg,wParam,TRUE); /* * Convert DBCS/SBCS to Unicode... */ RtlMBMessageWParamCharToWCS(msg, &wParam); } retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lParam, xParam, xpfnProc, bAnsi); ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnCOPYGLOBALDATA) { PBYTE pData; BEGINCALL() if (wParam == 0) { MSGERROR(); } USERGLOBALLOCK((HGLOBAL)lParam, pData); if (pData == NULL) { MSGERROR(); } retval = NtUserMessageCall( hwnd, msg, wParam, (LPARAM)pData, xParam, xpfnProc, bAnsi); USERGLOBALUNLOCK((HGLOBAL)lParam); UserGlobalFree((HGLOBAL)lParam); ERRORTRAP(0); ENDCALL(ULONG_PTR); } MESSAGECALL(fnINPAINTCLIPBRD) { LPPAINTSTRUCT lpps; BEGINCALL() USERGLOBALLOCK((HGLOBAL)lParam, lpps); if (lpps) { retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, (LPARAM)lpps, xParam, xpfnProc, bAnsi); USERGLOBALUNLOCK((HGLOBAL)lParam); } else { RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINPAINTCLIPBRD): USERGLOBALLOCK failed on %p!", lParam); MSGERROR(); } ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnINSIZECLIPBRD) { LPRECT lprc; BEGINCALL() USERGLOBALLOCK((HGLOBAL)lParam, lprc); if (lprc) { retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, (LPARAM)lprc, xParam, xpfnProc, bAnsi); USERGLOBALUNLOCK((HGLOBAL)lParam); } else { RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINSIZECLIPBRD): USERGLOBALLOCK failed on %p!", lParam); MSGERROR(); } ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnINDEVICECHANGE) { struct _DEV_BROADCAST_HEADER *pHdr; PDEV_BROADCAST_PORT_W pPortW = NULL; PDEV_BROADCAST_PORT_A pPortA; PDEV_BROADCAST_DEVICEINTERFACE_W pInterfaceW = NULL; PDEV_BROADCAST_DEVICEINTERFACE_A pInterfaceA; PDEV_BROADCAST_HANDLE pHandleW = NULL; PDEV_BROADCAST_HANDLE pHandleA; LPWSTR lpStr; int iStr, iSize; BEGINCALL() if (!(wParam &0x8000) || !lParam || !bAnsi) goto shipit; pHdr = (struct _DEV_BROADCAST_HEADER *)lParam; switch (pHdr->dbcd_devicetype) { case DBT_DEVTYP_PORT: pPortA = (PDEV_BROADCAST_PORT_A)lParam; iStr = strlen(pPortA->dbcp_name); iSize = FIELD_OFFSET(DEV_BROADCAST_PORT_W, dbcp_name) + sizeof(WCHAR)*(iStr+1); pPortW = UserLocalAlloc(0, iSize); if (pPortW == NULL) return 0; RtlCopyMemory(pPortW, pPortA, sizeof(DEV_BROADCAST_PORT_A)); lpStr = pPortW->dbcp_name; if (iStr) { MBToWCS(pPortA->dbcp_name, -1, &lpStr, iStr, FALSE); lpStr[iStr] = 0; } else { lpStr[0] = 0; } pPortW->dbcp_size = iSize; lParam = (LPARAM)pPortW; bAnsi = FALSE; break; case DBT_DEVTYP_DEVICEINTERFACE: pInterfaceA = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam; iStr = strlen(pInterfaceA->dbcc_name); iSize = FIELD_OFFSET(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name) + sizeof(WCHAR)*(iStr+1); pInterfaceW = UserLocalAlloc(0, iSize); if (pInterfaceW == NULL) return 0; RtlCopyMemory(pInterfaceW, pInterfaceA, sizeof(DEV_BROADCAST_DEVICEINTERFACE_A)); lpStr = pInterfaceW->dbcc_name; if (iStr) { MBToWCS(pInterfaceA->dbcc_name, -1, &lpStr, iStr, FALSE); lpStr[iStr] = 0; } else { lpStr[0] = 0; } pInterfaceW->dbcc_size = iSize; lParam = (LPARAM)pInterfaceW; bAnsi = FALSE; break; case DBT_DEVTYP_HANDLE: pHandleA = (PDEV_BROADCAST_HANDLE)lParam; bAnsi = FALSE; if ((wParam != DBT_CUSTOMEVENT) || (pHandleA->dbch_nameoffset < 0)) break; iStr = strlen(pHandleA->dbch_data+pHandleA->dbch_nameoffset); /* * Calculate size of new structure with UNICODE string instead of Ansi string */ iSize = FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset + sizeof(WCHAR)*(iStr+1); /* * Just in case there were an odd number of bytes in the non-text data */ if (iSize & 1) iSize++; pHandleW = UserLocalAlloc(0, iSize); if (pHandleW == NULL) return 0; RtlCopyMemory(pHandleW, pHandleA, FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset); /* * Make sure this is even for the UNICODE string. */ if (pHandleW->dbch_nameoffset & 1) pHandleW->dbch_nameoffset++; lpStr = (LPWSTR)(pHandleW->dbch_data+pHandleW->dbch_nameoffset); if (iStr) { MBToWCS(pHandleA->dbch_data+pHandleA->dbch_nameoffset, -1, &lpStr, iStr, FALSE); } lpStr[iStr] = 0; pHandleW->dbch_size = iSize; lParam = (LPARAM)pHandleW; break; } shipit: retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lParam, xParam, xpfnProc, bAnsi); if (pPortW) UserLocalFree(pPortW); if (pInterfaceW) UserLocalFree(pInterfaceW); if (pHandleW) UserLocalFree(pHandleW); ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnIMECONTROL) { PVOID pvData = NULL; LPARAM lData = lParam; BEGINCALL() /* * The server always expects the characters to be unicode so * if this was generated from an ANSI routine convert it to Unicode */ if (bAnsi) { switch (wParam) { case IMC_GETCOMPOSITIONFONT: case IMC_GETSOFTKBDFONT: case IMC_SETCOMPOSITIONFONT: pvData = UserLocalAlloc(0, sizeof(LOGFONTW)); if (pvData == NULL) MSGERROR(); if (wParam == IMC_SETCOMPOSITIONFONT) { // Later, we do A/W conversion based on thread hkl/CP. CopyLogFontAtoW((PLOGFONTW)pvData, (PLOGFONTA)lParam); } lData = (LPARAM)pvData; break; case IMC_SETSOFTKBDDATA: { PSOFTKBDDATA pSoftKbdData; PWORD pCodeA; PWSTR pCodeW; CHAR ch[3]; DWORD cbSize; UINT uCount, i; uCount = ((PSOFTKBDDATA)lParam)->uCount; cbSize = FIELD_OFFSET(SOFTKBDDATA, wCode[0]) + uCount * sizeof(WORD) * 256; pvData = UserLocalAlloc(0, cbSize); if (pvData == NULL) MSGERROR(); pSoftKbdData = (PSOFTKBDDATA)pvData; pSoftKbdData->uCount = uCount; ch[2] = (CHAR)'\0'; pCodeA = &((PSOFTKBDDATA)lParam)->wCode[0][0]; pCodeW = &pSoftKbdData->wCode[0][0]; i = uCount * 256; while (i--) { if (HIBYTE(*pCodeA)) { ch[0] = (CHAR)HIBYTE(*pCodeA); ch[1] = (CHAR)LOBYTE(*pCodeA); } else { ch[0] = (CHAR)LOBYTE(*pCodeA); ch[1] = (CHAR)'\0'; } MBToWCSEx(THREAD_CODEPAGE(), (LPSTR)&ch, -1, &pCodeW, 1, FALSE); pCodeA++; pCodeW++; } lData = (LPARAM)pvData; } break; default: break; } } retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lData, xParam, xpfnProc, bAnsi); if (bAnsi) { switch (wParam) { case IMC_GETCOMPOSITIONFONT: case IMC_GETSOFTKBDFONT: CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData); break; default: break; } } if (pvData != NULL) UserLocalFree(pvData); ERRORTRAP(0); ENDCALL(DWORD); } DWORD CalcCharacterPositionAtoW( DWORD dwCharPosA, LPSTR lpszCharStr, DWORD dwCodePage) { DWORD dwCharPosW = 0; while (dwCharPosA != 0) { if (IsDBCSLeadByteEx(dwCodePage, *lpszCharStr)) { if (dwCharPosA >= 2) { dwCharPosA -= 2; } else { dwCharPosA--; } lpszCharStr += 2; } else { dwCharPosA--; lpszCharStr++; } dwCharPosW++; } return dwCharPosW; } int UnicodeToMultiByteSize(DWORD dwCodePage, LPCWSTR pwstr) { char dummy[2], *lpszDummy = dummy; return WCSToMBEx((WORD)dwCodePage, pwstr, 1, &lpszDummy, sizeof(WCHAR), FALSE); } DWORD CalcCharacterPositionWtoA( DWORD dwCharPosW, LPWSTR lpwszCharStr, DWORD dwCodePage) { DWORD dwCharPosA = 0; ULONG MultiByteSize; while (dwCharPosW != 0) { MultiByteSize = UnicodeToMultiByteSize(dwCodePage, lpwszCharStr); if (MultiByteSize == 2) { dwCharPosA += 2; } else { dwCharPosA++; } dwCharPosW--; lpwszCharStr++; } return dwCharPosA; } #ifdef LATER DWORD WINAPI ImmGetReconvertTotalSize(DWORD dwSize, REQ_CALLER eCaller, BOOL bAnsiTarget) { if (dwSize < sizeof(RECONVERTSTRING)) { return 0; } if (bAnsiTarget) { dwSize -= sizeof(RECONVERTSTRING); if (eCaller == FROM_IME) { dwSize /= 2; } else { dwSize *= 2; } dwSize += sizeof(RECONVERTSTRING); } return dwSize; } FUNCLOG4(LOG_GENERAL, DWORD, WINAPI, ImmReconversionWorker, LPRECONVERTSTRING, lpRecTo, LPRECONVERTSTRING, lpRecFrom, BOOL, bToAnsi, DWORD, dwCodePage) DWORD WINAPI ImmReconversionWorker( LPRECONVERTSTRING lpRecTo, LPRECONVERTSTRING lpRecFrom, BOOL bToAnsi, DWORD dwCodePage) { INT i; DWORD dwSize = 0; UserAssert(lpRecTo); UserAssert(lpRecFrom); if (lpRecFrom->dwVersion != 0 || lpRecTo->dwVersion != 0) { RIPMSG0(RIP_WARNING, "ImmReconversionWorker: dwVersion in lpRecTo or lpRecFrom is incorrect."); return 0; } // Note: // In any IME related structures, use the following principal. // 1) xxxStrOffset is an actual offset, i.e. byte count. // 2) xxxStrLen is a number of characters, i.e. TCHAR count. // // CalcCharacterPositionXtoY() takes TCHAR count so that we // need to adjust xxxStrOffset if it's being converted. But you // should be careful, because the actual position of the string // is always at something like (LPBYTE)lpStruc + lpStruc->dwStrOffset. // if (bToAnsi) { // Convert W to A lpRecTo->dwStrOffset = sizeof *lpRecTo; i = WideCharToMultiByte(dwCodePage, (DWORD)0, (LPWSTR)((LPSTR)lpRecFrom + lpRecFrom->dwStrOffset), // src (INT)lpRecFrom->dwStrLen, (LPSTR)lpRecTo + lpRecTo->dwStrOffset, // dest (INT)lpRecFrom->dwStrLen * DBCS_CHARSIZE, (LPSTR)NULL, (LPBOOL)NULL); lpRecTo->dwCompStrOffset = CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR), (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset), dwCodePage) * sizeof(CHAR); lpRecTo->dwCompStrLen = (CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR) + lpRecFrom->dwCompStrLen, (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset), dwCodePage) * sizeof(CHAR)) - lpRecTo->dwCompStrOffset; lpRecTo->dwTargetStrOffset = CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR), (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset), dwCodePage) * sizeof(CHAR); lpRecTo->dwTargetStrLen = (CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR) + lpRecFrom->dwTargetStrLen, (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset), dwCodePage) * sizeof(CHAR)) - lpRecTo->dwTargetStrOffset; ((LPSTR)lpRecTo)[lpRecTo->dwStrOffset + i] = '\0'; lpRecTo->dwStrLen = i * sizeof(CHAR); dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(CHAR)); } else { // AtoW lpRecTo->dwStrOffset = sizeof *lpRecTo; i = MultiByteToWideChar(dwCodePage, (DWORD)MB_PRECOMPOSED, (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, // src (INT)lpRecFrom->dwStrLen, (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset), // dest (INT)lpRecFrom->dwStrLen); lpRecTo->dwCompStrOffset = CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset, (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, dwCodePage) * sizeof(WCHAR); lpRecTo->dwCompStrLen = ((CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset + lpRecFrom->dwCompStrLen, (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, dwCodePage) * sizeof(WCHAR)) - lpRecTo->dwCompStrOffset) / sizeof(WCHAR); lpRecTo->dwTargetStrOffset = CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset, (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, dwCodePage) * sizeof(WCHAR); lpRecTo->dwTargetStrLen = ((CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset + lpRecFrom->dwTargetStrLen, (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, dwCodePage) * sizeof(WCHAR)) - lpRecTo->dwTargetStrOffset) / sizeof(WCHAR); lpRecTo->dwStrLen = i; // Length is TCHAR count. if (lpRecTo->dwSize >= (DWORD)(lpRecTo->dwStrOffset + (i + 1)* sizeof(WCHAR))) { LPWSTR lpW = (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset); lpW[i] = L'\0'; } dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(WCHAR)); } return dwSize; } #define GETCOMPOSITIONSTRING(hImc, index, buf, buflen) \ (bAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)((hImc), (index), (buf), (buflen)) MESSAGECALL(fnIMEREQUEST) { PVOID pvData = NULL; LPARAM lData = lParam; BEGINCALL() if (!IS_IME_ENABLED()) { // If IME is not enabled, save time. MSGERROR(); } /* * The server always expects the characters to be unicode so * if this was generated from an ANSI routine convert it to Unicode */ if (wParam == IMR_QUERYCHARPOSITION) { // // Store the UNICODE character count in PrivateIMECHARPOSITION. // // No need to save the original dwCharPos, since dwCharPositionA/W are not // overwritten in the kernel. // if (bAnsi) { ((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionW; } } else if (bAnsi) { switch (wParam) { case IMR_COMPOSITIONFONT: pvData = UserLocalAlloc(0, sizeof(LOGFONTW)); if (pvData == NULL) MSGERROR(); lData = (LPARAM)pvData; break; case IMR_CONFIRMRECONVERTSTRING: case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: if ((LPVOID)lParam != NULL) { // IME wants not only the buffer size but the real reconversion information DWORD dwSize = ImmGetReconvertTotalSize(((LPRECONVERTSTRING)lParam)->dwSize, FROM_IME, FALSE); LPRECONVERTSTRING lpReconv; pvData = UserLocalAlloc(0, dwSize + sizeof(WCHAR)); if (pvData == NULL) { RIPMSG0(RIP_WARNING, "fnIMEREQUEST: failed to allocate a buffer for reconversion."); MSGERROR(); } lpReconv = (LPRECONVERTSTRING)pvData; // setup the information in the allocated structure lpReconv->dwVersion = 0; lpReconv->dwSize = dwSize; // // if it's confirmation message, we need to translate the contents // if (wParam == IMR_CONFIRMRECONVERTSTRING) { ImmReconversionWorker(lpReconv, (LPRECONVERTSTRING)lParam, FALSE, CP_ACP); } } break; default: break; } } retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lData, xParam, xpfnProc, bAnsi); if (bAnsi) { switch (wParam) { case IMR_COMPOSITIONFONT: if (retval) { CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData); } break; case IMR_QUERYCHARPOSITION: ((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionA; break; case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: // // Note: by definition, we don't need back-conversion for IMR_CONFIRMRECONVERTSTRING // if (retval) { // IME wants the buffer size retval = ImmGetReconvertTotalSize((DWORD)retval, FROM_APP, FALSE); if (retval < sizeof(RECONVERTSTRING)) { RIPMSG2(RIP_WARNING, "WM_IME_REQUEST(%x): return value from application %d is invalid.", wParam, retval); retval = 0; } else if (lParam) { // We need to perform the A/W conversion of the contents if (!ImmReconversionWorker((LPRECONVERTSTRING)lParam, (LPRECONVERTSTRING)pvData, TRUE, CP_ACP)) { MSGERROR(); } } } break; } } ERRORTRAP(0); if (pvData != NULL) UserLocalFree(pvData); ENDCALL(DWORD); } #endif MESSAGECALL(fnEMGETSEL) { PWND pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) return 0; BEGINCALL() retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lParam, xParam, xpfnProc, bAnsi); // // temp for our beta... // // !!! THIS CODE SHOULD BE IN KERNEL MODE !!! // // to reduce user <-> kernel mode transition... // if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) { ULONG cchTextLength; LONG lOriginalLengthW; LONG lOriginalLengthL; LONG wParamLocal; LONG lParamLocal; if (wParam) { lOriginalLengthW = *(LONG *)wParam; } else { lOriginalLengthW = (LONG)(LOWORD(retval)); } if (lParam) { lOriginalLengthL = *(LONG *)lParam; } else { lOriginalLengthL = (LONG)(HIWORD(retval)); } cchTextLength = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0, xParam, xpfnProc, bAnsi); if (cchTextLength) { PVOID pvString; ULONG cbTextLength; cchTextLength++; if (!bAnsi) { cbTextLength = cchTextLength * sizeof(WCHAR); } else { cbTextLength = cchTextLength; } pvString = UserLocalAlloc(0,cbTextLength); if (pvString) { retval = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXT, cchTextLength, (LPARAM)pvString, xParam, xpfnProc, bAnsi); if (retval) { if (bAnsi) { /* * ansiString/unicodeLenght -> ansiLength */ CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal) CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal); } else { /* * unicodeString/ansiLenght -> unicodeLength */ CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal); CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal); } retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF)); if (wParam) { *(LONG *)wParam = wParamLocal; } if (lParam) { *(LONG *)lParam = lParamLocal; } } else { UserLocalFree(pvString); MSGERROR(); } UserLocalFree(pvString); } else { MSGERROR(); } } else { MSGERROR(); } } ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnEMSETSEL) { PWND pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return 0; } BEGINCALL() // // temp for our beta... // // !!! THIS CODE SHOULD BE IN KERNEL MODE !!! // // to reduce user <-> kernel mode transition... // if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) { if (((LONG)wParam <= 0) && ((LONG)lParam <=0)) { // // if (wParam == 0 or wParam == -1) // and // (lParam == 0 or lParam == -1) // // In this case, we don't need to convert the value... // } else { ULONG cchTextLength; LONG lOriginalLengthW = (LONG)wParam; LONG lOriginalLengthL = (LONG)lParam; cchTextLength = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0, xParam, xpfnProc, bAnsi); if (cchTextLength) { PVOID pvString; ULONG cbTextLength; cchTextLength++; if (!bAnsi) { cbTextLength = cchTextLength * sizeof(WCHAR); } else { cbTextLength = cchTextLength; } pvString = UserLocalAlloc(0,cbTextLength); if (pvString) { retval = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXT, cchTextLength, (LPARAM)pvString, xParam, xpfnProc, bAnsi); if (retval) { if ((LONG)retval < lOriginalLengthW) { lOriginalLengthW = (LONG)retval; } if ((LONG)retval < lOriginalLengthL) { lOriginalLengthL = (LONG)retval; } if (bAnsi) { if (lOriginalLengthW > 0) { CalcUnicodeStringLengthA(pvString, lOriginalLengthW, &wParam); } if (lOriginalLengthL > 0) { CalcUnicodeStringLengthA(pvString, lOriginalLengthL, &lParam); } } else { if (lOriginalLengthW > 0) { CalcAnsiStringLengthW(pvString, lOriginalLengthW, &wParam); } if (lOriginalLengthL > 0) { CalcAnsiStringLengthW(pvString, lOriginalLengthL, &lParam); } } } else { UserLocalFree(pvString); MSGERROR(); } UserLocalFree(pvString); } else { MSGERROR(); } } else { MSGERROR(); } } } retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lParam, xParam, xpfnProc, bAnsi); ERRORTRAP(0); ENDCALL(DWORD); } MESSAGECALL(fnCBGETEDITSEL) { PWND pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) return 0; BEGINCALL() retval = (DWORD)NtUserMessageCall( hwnd, msg, wParam, lParam, xParam, xpfnProc, bAnsi); // // temp for our beta... // // !!! THIS CODE SHOULD BE IN KERNEL MODE !!! // // to reduce user <-> kernel mode transition... // if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) { ULONG cchTextLength; LONG lOriginalLengthW = *(LONG *)wParam; LONG lOriginalLengthL = *(LONG *)lParam; LONG wParamLocal; LONG lParamLocal; if (wParam) { lOriginalLengthW = *(LONG *)wParam; } else { lOriginalLengthW = (LONG)(LOWORD(retval)); } if (lParam) { lOriginalLengthL = *(LONG *)lParam; } else { lOriginalLengthL = (LONG)(HIWORD(retval)); } cchTextLength = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0, xParam, xpfnProc, bAnsi); if (cchTextLength) { PVOID pvString; ULONG cbTextLength; cchTextLength++; if (!bAnsi) { cbTextLength = cchTextLength * sizeof(WCHAR); } else { cbTextLength = cchTextLength; } pvString = UserLocalAlloc(0,cbTextLength); if (pvString) { retval = (DWORD)NtUserMessageCall( hwnd, WM_GETTEXT, cchTextLength, (LPARAM)pvString, xParam, xpfnProc, bAnsi); if (retval) { if (bAnsi) { /* * ansiString/unicodeLenght -> ansiLength */ CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal); CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal); } else { /* * unicodeString/ansiLenght -> unicodeLength */ CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal); CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal); } retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF)); if (wParam) { *(LONG *)wParam = wParamLocal; } if (lParam) { *(LONG *)lParam = lParamLocal; } } else { UserLocalFree(pvString); MSGERROR(); } UserLocalFree(pvString); } else { MSGERROR(); } } else { MSGERROR(); } } ERRORTRAP(0); ENDCALL(DWORD); } LONG BroadcastSystemMessageWorker( DWORD dwFlags, LPDWORD lpdwRecipients, UINT message, WPARAM wParam, LPARAM lParam, PBSMINFO pBSMInfo, BOOL fAnsi) { DWORD dwRecipients; /* * 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 message 0x%x for BroadcastSystemMessage", message); return 0; } if (dwFlags & ~BSF_VALID) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid dwFlags 0x%x for BroadcastSystemMessage", dwFlags); return 0; } if ((dwFlags & (BSF_RETURNHDESK | BSF_LUID)) && pBSMInfo == NULL) { RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid BSF_RETURNHDESK or BSF_LUID is set and pBSMInfo is NULL for BroadcastSystemMessageEx"); return 0; } if (pBSMInfo != NULL && pBSMInfo->cbSize != sizeof(BSMINFO)) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid pBSMInfo->cbSize (%x) for BroadcastSystemMessageEx", pBSMInfo->cbSize); return 0; } // // Check if the message number is in the private message range. // If so, do not send it to Win4.0 windows. // (This is required because apps like SimCity broadcast a message // that has the value 0x500 and that confuses MsgSrvr's // MSGSRVR_NOTIFY handler. // if (message >= WM_USER && message < 0xC000) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid message (%x) for BroadcastSystemMessage", message); return 0; } if (dwFlags & BSF_FORCEIFHUNG) { dwFlags |= BSF_NOHANG; } // // If BSF_QUERY or message has a pointer, it can not be posted. // if (dwFlags & BSF_QUERY) { if (dwFlags & BSF_ASYNC) { RIPMSGF0(RIP_WARNING, "BSF_QUERY can't be BSF_ASYNC"); } dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags. } if (dwFlags & BSF_ASYNC) { if (TESTSYNCONLYMESSAGE(message, wParam)) { RIPERR0(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, "BSM: Can't post messages with pointers"); dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags. } } /* * Let us find out who the intended recipients are. */ if (lpdwRecipients != NULL) { dwRecipients = *lpdwRecipients; } else { dwRecipients = BSM_ALLCOMPONENTS; } /* * If they want all components, add the corresponding bits. */ if ((dwRecipients & BSM_COMPONENTS) == BSM_ALLCOMPONENTS) { dwRecipients |= (BSM_VXDS | BSM_NETDRIVER | BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS); } if (dwRecipients & ~BSM_VALID) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "BSM: Invalid dwRecipients 0x%x", dwRecipients); return 0; } /* * Does this need to be sent to all apps? */ if (dwRecipients & BSM_APPLICATIONS) { BROADCASTSYSTEMMSGPARAMS bsmParams; LONG lret; bsmParams.dwFlags = dwFlags; bsmParams.dwRecipients = dwRecipients; bsmParams.hwnd = NULL; bsmParams.hdesk = NULL; if (dwFlags & BSF_LUID) { bsmParams.luid = pBSMInfo->luid; } lret = (LONG)CsSendMessage(GetDesktopWindow(), message, wParam, lParam, (ULONG_PTR)&bsmParams, FNID_SENDMESSAGEBSM, fAnsi); /* * Give the caller back the recipients that actually receive the message. */ if (lpdwRecipients != NULL) { *lpdwRecipients = bsmParams.dwRecipients; } // // If the query was denied, then return who denied it. // if (lret == 0 && (dwFlags & BSF_QUERY) && pBSMInfo != NULL) { pBSMInfo->hwnd = bsmParams.hwnd; pBSMInfo->hdesk = bsmParams.hdesk; } return lret; } return -1; } HDEVNOTIFY RegisterDeviceNotificationWorker( IN HANDLE hRecipient, IN LPVOID NotificationFilter, IN DWORD Flags) { HINSTANCE hLib; FARPROC fpRegisterNotification; PVOID Context = NULL; HDEVNOTIFY notifyHandle = NULL; CONFIGRET Status = CR_SUCCESS; extern CONFIGRET CMP_RegisterNotification(IN HANDLE hRecipient, IN LPBYTE NotificationFilter, IN DWORD Flags, OUT PVOID *Context); // // Load the config manager client dll and retrieve entry pts. // hLib = LoadLibrary(TEXT("SETUPAPI.DLL")); if (hLib != NULL) { fpRegisterNotification = GetProcAddress(hLib, "CMP_RegisterNotification"); if (fpRegisterNotification != NULL) { Status = (CONFIGRET)(*fpRegisterNotification)(hRecipient, NotificationFilter, Flags, &Context); } FreeLibrary(hLib); } if (Status != CR_SUCCESS) { /* * Something went wrong, map the CR errors to a Win32 style error * code. */ switch (Status) { case CR_INVALID_POINTER: SetLastError(ERROR_INVALID_PARAMETER); break; case CR_INVALID_DATA: SetLastError(ERROR_INVALID_DATA); break; case CR_OUT_OF_MEMORY: SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; case CR_FAILURE: default: SetLastError(ERROR_SERVICE_SPECIFIC_ERROR); break; } } if (Context != NULL && (ULONG_PTR)Context != -1) { notifyHandle = (HDEVNOTIFY)Context; } return notifyHandle; } BOOL UnregisterDeviceNotification( IN HDEVNOTIFY Handle) { HINSTANCE hLib; FARPROC fpUnregisterNotification; CONFIGRET crStatus = CR_SUCCESS; extern CONFIGRET CMP_UnregisterNotification(IN ULONG Context); /* * Load the config manager client dll and retrieve entry pts. */ hLib = LoadLibrary(TEXT("SETUPAPI.DLL")); if (hLib != NULL) { fpUnregisterNotification = GetProcAddress(hLib, "CMP_UnregisterNotification"); if (fpUnregisterNotification != NULL) { crStatus = (CONFIGRET)(*fpUnregisterNotification)((ULONG_PTR)Handle); } FreeLibrary(hLib); } if (crStatus != CR_SUCCESS) { /* * Something went wrong, map the CR errors to a Win32 style error * code. */ switch (crStatus) { case CR_INVALID_POINTER: SetLastError(ERROR_INVALID_PARAMETER); break; case CR_INVALID_DATA: SetLastError(ERROR_INVALID_DATA); break; case CR_FAILURE: default: SetLastError(ERROR_SERVICE_SPECIFIC_ERROR); break; } } return (BOOL)(crStatus == CR_SUCCESS); }