Windows2000/private/ntos/w32/ntuser/client/ntstubs.c
2020-09-30 17:12:32 +02:00

2343 lines
68 KiB
C

/*
* 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 <dbt.h>
#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;
}