/* * 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" extern BOOL GetRemoteKeyboardLayout(PWCHAR); 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); } BOOL UpdatePerUserSystemParameters(HANDLE hToken, BOOL bUserLoggedOn) { WCHAR pwszKLID[KL_NAMELENGTH]; BEGINCALL() /* * Initialize IME hotkeys before loading keyboard * layouts. */ CliImmInitializeHotKeys(ISHK_INITIALIZE, NULL); /* * Load initial keyboard layout. */ if (!GetRemoteKeyboardLayout(pwszKLID)) { GetActiveKeyboardName(pwszKLID); } LoadKeyboardLayoutWorker(NULL, pwszKLID, KLF_ACTIVATE | KLF_RESET | KLF_SUBSTITUTE_OK, TRUE); /* * Now load the remaining preload keyboard layouts. */ LoadPreloadKeyboardLayouts(); retval = (DWORD)NtUserUpdatePerUserSystemParameters(hToken, bUserLoggedOn); /* * 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)((PBYTE)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, 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, 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\n"); 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\n"); 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\n"); 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); }; WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild) { BEGINCALLVOID() if (FWINABLE()) { NtUserNotifyWinEvent(dwEvent, hwnd, idObject, idChild); } ERRORTRAPVOID(); ENDCALLVOID(); } /* * 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) { RIPMSG2(RIP_WARNING, "Menu bitmap change, fix 16-bit bitmap handle %lx to %lx\n", 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); } BOOL DrawCaption(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); } 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); } 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); } 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 { RIPMSG0(RIP_WARNING, "SetWindowLong (DWL_DLGPROC) unable to alloc CPD returning handle\n"); } } /* * 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)); } BOOL SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL bRedraw) { BEGINCALL() retval = (DWORD)NtUserSetWindowRgn(hwnd, hrgn, bRedraw); if (retval) { DeleteObject(hrgn); } ERRORTRAP(0); ENDCALL(BOOL); } 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 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); } 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 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); } 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, pcur->lpModName); COPYLPWSTRIDOPT(&strResName, 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_VALID50) && (dwExpWinVerAndFlags >= VER40)) { RIPMSG0(RIP_ERROR, "Invalid 5.0 ExStyle\n"); 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_ERROR, "Invalid parent for MDI child window\n"); 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; } } if (dwFlags & CW_FLAGS_DIFFHMOD) { dwExpWinVerAndFlags |= CW_FLAGS_DIFFHMOD; } retval = (ULONG_PTR)NtUserCreateWindowEx(dwExStyle, pstrClassName, pstrWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, hmenu, hModule, pParam, dwExpWinVerAndFlags); if (retval && fMDIchild) {// If this is an MDI child, we need to do some more to complete the process of creating an MDI child. 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, 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, hkl, strKL.pstr, KbdInputLocale, Flags); ERRORTRAP(0); CLEANUPLPWSTR(strKL); ENDCALL(HKL); } 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() } 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 = (DWORD)NtUserMessageCall(hwnd, msg, wParam, (LPARAM)pData, xParam, xpfnProc, bAnsi); USERGLOBALUNLOCK((HGLOBAL)lParam); UserGlobalFree((HGLOBAL)lParam); ERRORTRAP(0); ENDCALL(DWORD); } 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); } 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); } 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); } #ifdef LATER 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; } 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; } 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, 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 (%x) for BroadcastSystemMessage\n", message); return(0); } if (dwFlags & ~BSF_VALID) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid dwFlags (%x) for BroadcastSystemMessage\n", dwFlags); 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\n", message); return(0L); } 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 DBG if (dwFlags & BSF_ASYNC) { RIPMSG0(RIP_ERROR, "BroadcastSystemMessage: Can't post queries\n"); } #endif dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags. } if (dwFlags & BSF_ASYNC) { if (TESTSYNCONLYMESSAGE(message, wParam)) { RIPERR0(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, "BroadcastSystemMessage: Can't post messages with pointers\n"); 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, "invalid dwRecipients (%x) for BroadcastSystemMessage\n", dwRecipients); return(0); } // Check if this is a WM_USERCHANGED message; If so, we want to reload // the per-user settings before anyone else sees this message. // LATER -- FritzS // if (uiMessage == WM_USERCHANGED) // ReloadPerUserSettings(); // Does this need to be sent to all apps? if (dwRecipients & BSM_APPLICATIONS) { BROADCASTSYSTEMMSGPARAMS bsmParams; bsmParams.dwFlags = dwFlags; bsmParams.dwRecipients = dwRecipients; return (LONG)CsSendMessage(GetDesktopWindow(), message, wParam, lParam, (ULONG_PTR)&bsmParams, FNID_SENDMESSAGEBSM, fAnsi); } return -1; } HDEVNOTIFY RegisterDeviceNotificationWorker( IN HANDLE hRecipient, IN LPVOID NotificationFilter, IN DWORD Flags, IN BOOL IsAnsi ) { HINSTANCE hLib = NULL; FARPROC fpRegisterNotification = NULL; 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 ); UNREFERENCED_PARAMETER(IsAnsi); try { // load the config manager client dll and retrieve entry pts hLib = LoadLibrary(TEXT("SETUPAPI.DLL")); if (hLib == NULL) { goto Clean0; // use last error set by LoadLibrary } fpRegisterNotification = GetProcAddress(hLib, "CMP_RegisterNotification"); if (fpRegisterNotification == NULL) { goto Clean0; // use last error set by GetProcAddress } Status = (CONFIGRET)(fpRegisterNotification)(hRecipient, NotificationFilter, Flags, &Context); Clean0: ; } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { } if (hLib != NULL) { FreeLibrary(hLib); } if (Status != CR_SUCCESS) { //Something went wrong, map the CR errors to a W32 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) { BOOL status = TRUE; HINSTANCE hLib = NULL; FARPROC fpUnregisterNotification = NULL; CONFIGRET crStatus = CR_SUCCESS; extern CONFIGRET CMP_UnregisterNotification(IN ULONG Context); try { // load the config manager client dll and retrieve entry pts hLib = LoadLibrary(TEXT("SETUPAPI.DLL")); if (hLib == NULL) { status = FALSE; goto Clean0; // use last error set by LoadLibrary } fpUnregisterNotification = GetProcAddress(hLib, "CMP_UnregisterNotification"); if (fpUnregisterNotification == NULL) { status = FALSE; goto Clean0; // use last error set by GetProcAddress } crStatus = (CONFIGRET)(fpUnregisterNotification)((ULONG_PTR)Handle); if (crStatus != CR_SUCCESS) { status = FALSE; //Something went wrong, map the CR errors to a //W32 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; } } Clean0: ; } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { status = FALSE; } if (hLib != NULL) { FreeLibrary(hLib); } return status; }