Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

14744 lines
386 KiB

/****************************** Module Header ******************************\
* Module Name: ntstubs.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Kernel-mode stubs
*
* History:
* 03-16-95 JimA Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "cscall.h"
#include <dbt.h>
#define PROTOS_ONLY 1
#include "msgdef.h"
#if DBG
UINT gcMaxNestedCalls;
ULONG_PTR gcMaxUsedStack;
#if defined(_IA64_)
ULONG_PTR gcMaxUsedBStore;
#endif // _IA64_
int ThreadLockCount(
BOOL fInc)
{
PTHREADINFO ptiCurrent = PtiCurrentShared();
PTL ptl = ptiCurrent->ptl;
int nLocks = 0;
ULONG_PTR CurrentUsedSize;
if (fInc) {
(ptiCurrent->cNestedCalls)++;
if (GetNestedCallsCounter() > 50) {
RIPMSG1(RIP_WARNING, "ThreadLockCount: This thread did %d nested calls.", GetNestedCallsCounter());
}
if (ptiCurrent->cNestedCalls > gcMaxNestedCalls) {
gcMaxNestedCalls = ptiCurrent->cNestedCalls;
}
} else {
(ptiCurrent->cNestedCalls)--;
}
if (!ISCSRSS()) {
CurrentUsedSize = GET_USED_STACK_SIZE();
if (CurrentUsedSize > gcMaxUsedStack) {
gcMaxUsedStack = CurrentUsedSize;
}
#ifdef _IA64_
CurrentUsedSize = GET_USED_BSTORE_SIZE();
if (CurrentUsedSize > gcMaxUsedBStore) {
gcMaxUsedBStore = CurrentUsedSize;
}
#endif
}
while (ptl != NULL) {
nLocks++;
ptl = ptl->next;
}
ptl = ptiCurrent->ptlW32;
while (ptl != NULL) {
nLocks++;
ptl = ptl->next;
}
return nLocks;
}
VOID ThreadLockCheck(
int nLocks)
{
int nNewCount = ThreadLockCount(FALSE);
if (nLocks != nNewCount) {
RIPMSG2(RIP_ERROR, "ThreadLocks mismatch %d %d", nLocks, nNewCount);
}
}
// The parameter is used to ensure BEGINRECV* matches ENDRECV* in each stub.
#define DBG_THREADLOCK_START(s) { int nLocks ## s = ThreadLockCount(TRUE);
#define DBG_THREADLOCK_END(s) ThreadLockCheck(nLocks ## s); }
#else
#define DBG_THREADLOCK_START(s)
#define DBG_THREADLOCK_END(s)
#endif
/*
* Setup and control macros
*/
#define BEGINRECV(type, err) \
type retval; \
type errret = err; \
EnterCrit(); \
DBG_THREADLOCK_START(_)
#define ENDRECV() ENDRECV_(_)
#define BEGINATOMICRECV(type, err) \
type retval; \
type errret = err; \
EnterCrit(); \
DBG_THREADLOCK_START(_) \
BEGINATOMICCHECK()
#define ENDATOMICRECV() ENDATOMICRECV_(_)
#define BEGINRECVCSRSS(type, err) \
type retval; \
type errret = err; \
EnterCrit(); \
DBG_THREADLOCK_START(CSRSS) \
if (!ISCSRSS()) { \
retval = STATUS_ACCESS_DENIED; \
goto errorexit; \
}
#define ENDRECVCSRSS() ENDRECV_(CSRSS)
#define BEGINRECV_SHARED(type, err) \
type retval; \
type errret = err; \
EnterSharedCrit(); \
DBG_THREADLOCK_START(SHARED)
#define ENDRECV_SHARED() ENDRECV_(SHARED)
#define BEGINRECV_NOCRIT(type, err) \
type retval; \
type errret = err;
#define BEGINRECV_VOID() \
EnterCrit(); \
DBG_THREADLOCK_START(_VOID)
#define ENDRECV_VOID() ENDRECV_VOID_(_VOID)
#define BEGINRECV_HWND(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
EnterCrit(); \
DBG_THREADLOCK_START(HWND) \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit; \
}
#define ENDRECV_HWND() ENDRECV_HWND_(HWND)
#define BEGINATOMICRECV_HWND(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
EnterCrit(); \
DBG_THREADLOCK_START(HWND) \
BEGINATOMICCHECK() \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit; \
}
#define ENDATOMICRECV_HWND() ENDATOMICRECV_HWND_(HWND)
#define BEGINRECV_HWND_VOID(hwnd) \
PWND pwnd; \
EnterCrit(); \
DBG_THREADLOCK_START(HWND_VOID) \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
goto errorexit; \
}
#define ENDRECV_HWND_VOID() ENDRECV_VOID_(HWND_VOID)
#define BEGINRECV_HWND_SHARED(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
EnterSharedCrit(); \
DBG_THREADLOCK_START(HWND_SHARED) \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit; \
}
#define ENDRECV_HWND_SHARED() ENDRECV_HWND_(HWND_SHARED)
#define BEGINRECV_HWNDOPT_SHARED(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
EnterSharedCrit(); \
DBG_THREADLOCK_START(HWND_OPT_SHARED) \
if (hwnd) { \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit; \
} \
} else { \
pwnd = NULL; \
}
#define ENDRECV_HWNDOPT_SHARED() ENDRECV_HWND_(HWND_OPT_SHARED)
#define BEGINRECV_HWNDLOCK(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
TL tlpwnd; \
PTHREADINFO ptiCurrent; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK) \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit2; \
} \
ptiCurrent = PtiCurrent(); \
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
#define BEGINRECV_HWNDLOCKFF(type, err, hwnd, xpfnProc) \
type retval; \
type errret = err; \
PWND pwnd; \
TL tlpwnd; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK) \
if ((hwnd == HWND_BROADCAST || hwnd == (HWND)-1) && \
(xpfnProc == FNID_SENDNOTIFYMESSAGE || \
xpfnProc == FNID_SENDMESSAGECALLBACK)) { \
\
if (hwnd == (HWND)-1) { \
RIPMSG0(RIP_VERBOSE, \
"Use HWND_BROADCAST, not -1"); \
} \
\
pwnd = PWND_BROADCAST; \
} else if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
retval = errret; \
goto errorexit2; \
} else { \
PTHREADINFO ptiCurrent = PtiCurrent(); \
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); \
}
#define ENDRECV_HWNDLOCK() ENDRECV_HWNDLOCK_(HWNDLOCK)
#define ENDRECV_HWNDLOCKFF() ENDRECV_HWNDLOCK_FF(HWNDLOCK)
#define BEGINRECV_HWNDLOCK_ND(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwndND; \
TL tlpwnd; \
PTHREADINFO ptiCurrent; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK_ND) \
if (((pwndND = ValidateHwnd((hwnd))) == NULL) || \
(GETFNID(pwndND) == FNID_DESKTOP) || \
(GETFNID(pwndND) == FNID_MESSAGEWND)) { \
retval = errret; \
goto errorexit2; \
} \
ptiCurrent = PtiCurrent(); \
ThreadLockAlwaysWithPti(ptiCurrent, pwndND, &tlpwnd);
#define ENDRECV_HWNDLOCK_ND() ENDRECV_HWNDLOCK_(HWNDLOCK_ND)
/*
* This macro performs normal HWNDLOCK stub handling and
* optionally rejects desktop hwnd arguments for certain
* APIs.
*/
#define BEGINRECV_HWNDLOCK_COND_ND(type, err, hwnd, xpfnProc) \
type retval; \
type errret = err; \
PWND pwndCondND; \
TL tlpwnd; \
PTHREADINFO ptiCurrent; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK_COND_ND) \
if ((pwndCondND = ValidateHwnd(hwnd)) == NULL) { \
retval = errret; \
goto errorexit2; \
} \
switch(xpfnProc) { \
case SFI_XXXDRAWMENUBAR: \
case SFI_XXXENABLEWINDOW: \
if ((GETFNID(pwndCondND) == FNID_DESKTOP) || \
(GETFNID(pwndCondND) == FNID_MESSAGEWND)) { \
retval = errret; \
goto errorexit2; \
} \
break; \
} \
ptiCurrent = PtiCurrent(); \
ThreadLockAlwaysWithPti(ptiCurrent, pwndCondND, &tlpwnd);
#define ENDRECV_HWNDLOCK_COND_ND() ENDRECV_HWNDLOCK_(HWNDLOCK_COND_ND)
#define BEGINRECV_HWNDLOCK_OPT(type, err, hwnd) \
type retval; \
type errret = err; \
PWND pwnd; \
TL tlpwnd; \
PTHREADINFO ptiCurrent; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK_OPT) \
if (hwnd) { \
if ((pwnd = ValidateHwnd(hwnd)) == NULL) { \
retval = errret; \
goto errorexit2; \
} \
} else { \
pwnd = NULL; \
} \
ptiCurrent = PtiCurrent(); \
ThreadLockWithPti(ptiCurrent, pwnd, &tlpwnd);
#define ENDRECV_HWNDLOCK_OPT() ENDRECV_HWNDLOCK_(HWNDLOCK_OPT)
#define BEGINRECV_HWNDLOCK_VOID(hwnd) \
PWND pwnd; \
TL tlpwnd; \
PTHREADINFO ptiCurrent; \
EnterCrit(); \
DBG_THREADLOCK_START(HWNDLOCK_VOID) \
if ((pwnd = ValidateHwnd((hwnd))) == NULL) { \
goto errorexit2; \
} \
ptiCurrent = PtiCurrent(); \
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
#define ISXPFNPROCINRANGE(range) \
((xpfnProc >= SFI_BEGINTRANSLATE ## range) && \
(xpfnProc < SFI_ENDTRANSLATE ## range))
#define VALIDATEXPFNPROC(range) \
UserAssert(SFI_ENDTRANSLATETABLE == ulMaxSimpleCall); \
UserAssert(SFI_ENDTRANSLATE ## range <= ulMaxSimpleCall); \
if (!ISXPFNPROCINRANGE(range)) { \
MSGERROR(0); \
}
#define CLEANUPRECV() \
cleanupexit:
#define ENDRECV_(s) \
goto errorexit; \
errorexit: \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDATOMICRECV_(s) \
goto errorexit; \
errorexit: \
ENDATOMICCHECK() \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDRECV_NOCRIT() \
goto errorexit; \
errorexit: \
return retval;
#define ENDRECV_VOID_(s) \
goto errorexit; \
errorexit: \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return;
#define ENDRECV_HWND_(s) \
goto errorexit; \
errorexit: \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDATOMICRECV_HWND_(s) \
goto errorexit; \
errorexit: \
ENDATOMICCHECK() \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDRECV_HWNDLOCK_(s) \
goto errorexit; \
errorexit: \
ThreadUnlock(&tlpwnd); \
errorexit2: \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDRECV_HWNDLOCK_FF(s) \
goto errorexit; \
errorexit: \
if (pwnd != PWND_BROADCAST) { \
ThreadUnlock(&tlpwnd); \
} \
errorexit2: \
DBG_THREADLOCK_END(s) \
LeaveCrit(); \
return retval;
#define ENDRECV_HWNDLOCK_VOID() \
goto errorexit; \
errorexit: \
ThreadUnlock(&tlpwnd); \
errorexit2: \
DBG_THREADLOCK_END(HWNDLOCK_VOID) \
LeaveCrit(); \
return;
/*
* MSGERROR - exit the stub with an error condition.
* Parameters:
* LastError (OPTIONAL):
* == 0 If LastError is 0, the compiler will optimize away the call to
* UserSetLastError(). The last error will not be set to zero!
* != 0 If you want to SetLastError, provide a non-zero value.
*/
#define MSGERROR(LastError) { \
retval = errret; \
if (LastError) { \
UserSetLastError(LastError); \
} \
goto errorexit; }
#define MSGERROR_VOID() { \
goto errorexit; }
/*
* Same as MSGERROR but jumps to cleanup code instead of straight to the return
*/
#define MSGERRORCLEANUP(LastError) { \
retval = errret; \
if (LastError) { \
UserSetLastError(LastError); \
} \
goto cleanupexit; }
#define StubExceptionHandler(fSetLastError) W32ExceptionHandler((fSetLastError), RIP_WARNING)
#define TESTFLAGS(flags, mask) \
if (((flags) & ~(mask)) != 0) { \
RIPERR2(ERROR_INVALID_FLAGS, RIP_WARNING, "Invalid flags, %x & ~%x != 0 " #mask, \
flags, mask); \
MSGERROR(0); \
}
#define LIMITVALUE(value, limit, szText) \
if ((UINT)(value) > (UINT)(limit)) { \
RIPERR3(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter, %d > %d in %s", \
value, limit, szText); \
MSGERROR(0); \
}
#define MESSAGECALL(api) \
LRESULT NtUserfn ## api( \
PWND pwnd, \
UINT msg, \
WPARAM wParam, \
LPARAM lParam, \
ULONG_PTR xParam, \
DWORD xpfnProc, \
BOOL bAnsi)
#define BEGINRECV_MESSAGECALL(err) \
LRESULT retval; \
LRESULT errret = err; \
PTHREADINFO ptiCurrent = PtiCurrent(); \
CheckCritIn();
#define ENDRECV_MESSAGECALL() \
goto errorexit; \
errorexit: \
return retval;
#define BEGINRECV_HOOKCALL() \
LRESULT retval; \
LRESULT errret = 0; \
CheckCritIn();
#define ENDRECV_HOOKCALL() \
goto errorexit; \
errorexit: \
return retval;
#define CALLPROC(p) FNID(p)
/*
* Validation macros
*/
#define ValidateHWNDNoRIP(p,h) \
if ((p = ValidateHwnd(h)) == NULL) \
MSGERROR(0);
#define ValidateHWND(p,h) \
if ((p = ValidateHwnd(h)) == NULL) \
MSGERROR(0);
#define ValidateHWNDND(p,h) \
if ( ((p = ValidateHwnd(h)) == NULL) || \
(GETFNID(p) == FNID_DESKTOP) || \
(GETFNID(p) == FNID_MESSAGEWND) \
) \
MSGERROR(0);
#define ValidateHWNDOPT(p,h) \
if (h) { \
if ((p = ValidateHwnd(h)) == NULL) \
MSGERROR(0); \
} else { \
p = NULL; \
}
#define ValidateHWNDIA(p,h) \
if (h != HWND_TOP && \
h != HWND_BOTTOM && \
h != HWND_TOPMOST && \
h != HWND_NOTOPMOST) { \
if ( ((p = ValidateHwnd(h)) == NULL) || \
(GETFNID(p) == FNID_DESKTOP) || \
(GETFNID(p) == FNID_MESSAGEWND) \
) \
MSGERROR(0); \
} else { \
p = (PWND)h; \
}
#define ValidateHMENUOPT(p,h) \
if (h) { \
if ((p = ValidateHmenu(h)) == NULL) \
MSGERROR(0); \
} else { \
p = NULL; \
}
#define ValidateHMENU(p,h) \
if ((p = ValidateHmenu(h)) == NULL) \
MSGERROR(0);
#define ValidateHMENUMODIFY(p,h) \
if ((p = ValidateHmenu(h)) == NULL) { \
MSGERROR(0); \
} else if (TestMF(p, MFDESKTOP)) { \
RIPMSG1(RIP_WARNING, "ValidateHMENUMODIFY: Attempt to modify desktop menu:%#p", p); \
MSGERROR(0); \
}
#define ValidateHMENUMODIFYCHECKLOCK(p,h) \
if ((p = ValidateHmenu(h)) == NULL) { \
MSGERROR(0); \
} else if (TestMF(p, MFDESKTOP)) { \
RIPMSG1(RIP_WARNING, "ValidateHMENUMODIFYCHECKLOCK: Attempt to modify desktop menu:%#p", p); \
MSGERROR(0); \
} else if (TestMF(p, MFREADONLY)) { \
RIPMSG1(RIP_WARNING, "ValidateHMENUMODIFYCHECKLOCK: Attempt to modify RO menu: %#p", p); \
MSGERROR(0); \
}
#define ValidateHACCEL(p,h) \
if ((p = HMValidateHandle(h, TYPE_ACCELTABLE)) == NULL) \
MSGERROR(0);
#define ValidateHCURSOR(p,h) \
if ((p = HMValidateHandle(h, TYPE_CURSOR)) == NULL) \
MSGERROR(0);
#define ValidateHCURSOROPT(p,h) \
if (h) { \
if ((p = HMValidateHandle(h, TYPE_CURSOR)) == NULL) \
MSGERROR(0); \
} else { \
p = NULL; \
}
#define ValidateHICON(p,h) \
if ((p = HMValidateHandle(h, TYPE_CURSOR)) == NULL) \
MSGERROR(0);
#define ValidateHHOOK(p,h) \
if ((p = HMValidateHandle(h, TYPE_HOOK)) == NULL) \
MSGERROR(0);
#define ValidateHWINEVENTHOOK(p,h) \
if ((p = HMValidateHandle(h, TYPE_WINEVENTHOOK)) == NULL) \
MSGERROR(0);
#define ValidateHDWP(p,h) \
if ((p = HMValidateHandle(h, TYPE_SETWINDOWPOS)) == NULL) \
MSGERROR(0);
#define ValidateHMONITOR(p,h) \
if ((p = ValidateHmonitor(h)) == NULL) \
MSGERROR(0);
#define ValidateHIMC(p,h) \
if ((p = HMValidateHandle((HANDLE)h, TYPE_INPUTCONTEXT)) == NULL) \
MSGERROR(0);
#define ValidateHIMCOPT(p,h) \
if (h) { \
if ((p = HMValidateHandle((HANDLE)h, TYPE_INPUTCONTEXT)) == NULL) \
MSGERROR(0); \
} else { \
p = NULL; \
}
#define ValidateIMMEnabled() \
if (!IS_IME_ENABLED()) { \
RIPERR0(ERROR_CALL_NOT_IMPLEMENTED, RIP_VERBOSE, "IME is disabled in this system."); \
MSGERROR(0); \
}
#define ValidateIMMEnabledVOID() \
if (!IS_IME_ENABLED()) { \
RIPERR0(ERROR_CALL_NOT_IMPLEMENTED, RIP_VERBOSE, "IME is disabled in this system."); \
MSGERROR_VOID(); \
}
#define DOWNCAST(type, value) ((type)(ULONG_PTR)(value))
NTSTATUS
NtUserRemoteConnect(
IN PDOCONNECTDATA pDoConnectData,
IN ULONG cchDisplayDriverNameLength,
IN PWCHAR DisplayDriverName)
{
UINT chMax;
DOCONNECTDATA CapturedDoConnectData;
WCHAR CapturedDriverName[DR_DISPLAY_DRIVER_NAME_LENGTH + 1];
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (!ISTS()) {
errret = STATUS_ACCESS_DENIED;
MSGERROR(0);
}
/*
* Probe all read arguments.
*/
try {
CapturedDoConnectData = ProbeAndReadStructure(pDoConnectData, DOCONNECTDATA);
ProbeForRead(DisplayDriverName, cchDisplayDriverNameLength, sizeof(WCHAR));
UserAssert(DR_DISPLAY_DRIVER_NAME_LENGTH + 1 >= cchDisplayDriverNameLength);
chMax = min((sizeof(CapturedDriverName)/sizeof(WCHAR)) - 1, cchDisplayDriverNameLength);
wcsncpycch(CapturedDriverName, DisplayDriverName, chMax);
CapturedDriverName[chMax] = 0;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = RemoteConnect(&CapturedDoConnectData,
chMax * sizeof(WCHAR),
CapturedDriverName);
TRACE("NtUserRemoteConnect");
ENDRECVCSRSS();
}
NTSTATUS
NtUserRemoteRedrawRectangle(
IN WORD Left,
IN WORD Top,
IN WORD Right,
IN WORD Bottom)
{
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (!ISTS()) {
errret = STATUS_ACCESS_DENIED;
MSGERROR(0);
}
retval = RemoteRedrawRectangle(Left, Top, Right, Bottom);
TRACE("NtUserRemoteRedrawRectangle");
ENDRECVCSRSS();
}
NTSTATUS
NtUserRemoteRedrawScreen(
VOID)
{
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (!ISTS()) {
errret = STATUS_ACCESS_DENIED;
MSGERROR(0);
}
/*
* If there are any shadow connections, or it's not disconnected.
*/
if (gnShadowers > 0 || gbConnected) {
retval = RemoteRedrawScreen();
} else {
retval = STATUS_UNSUCCESSFUL;
}
TRACE("NtUserRemoteRedrawScreen");
ENDRECVCSRSS();
}
NTSTATUS
NtUserRemoteStopScreenUpdates(
VOID)
{
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (!ISTS()) {
errret = STATUS_ACCESS_DENIED;
MSGERROR(0);
}
if (!gfSwitchInProgress) {
retval = xxxRemoteStopScreenUpdates();
} else {
retval = STATUS_UNSUCCESSFUL;
}
TRACE("NtUserRemoteStopScreenUpdates");
ENDRECVCSRSS();
}
NTSTATUS
NtUserCtxDisplayIOCtl(
IN ULONG DisplayIOCtlFlags,
IN PUCHAR pDisplayIOCtlData,
IN ULONG cbDisplayIOCtlData)
{
PUCHAR pCapturedDisplayIOCtlData = NULL;
TL tlBuffer;
PTHREADINFO ptiCurrent;
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (!ISTS()) {
errret = STATUS_ACCESS_DENIED;
MSGERROR(0);
}
ptiCurrent = PtiCurrent();
/*
* Probe all read arguments.
*/
try {
ProbeForRead(pDisplayIOCtlData, cbDisplayIOCtlData, sizeof(BYTE));
pCapturedDisplayIOCtlData = UserAllocPoolWithQuota(cbDisplayIOCtlData, TAG_SYSTEM);
if (pCapturedDisplayIOCtlData) {
ThreadLockPool(ptiCurrent, pCapturedDisplayIOCtlData, &tlBuffer);
RtlCopyMemory(pCapturedDisplayIOCtlData, pDisplayIOCtlData, cbDisplayIOCtlData);
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = CtxDisplayIOCtl(DisplayIOCtlFlags,
pCapturedDisplayIOCtlData,
cbDisplayIOCtlData);
CLEANUPRECV();
if (pCapturedDisplayIOCtlData) {
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
}
TRACE("NtUserCtxDisplayIOCtl");
ENDRECVCSRSS();
}
UINT NtUserHardErrorControl(
IN HARDERRORCONTROL dwCmd,
IN HANDLE handle,
OUT PDESKRESTOREDATA pdrdRestore OPTIONAL)
{
DESKRESTOREDATA drdRestore;
BEGINRECVCSRSS(BOOL, HEC_ERROR);
/*
* Probe all arguments. Try block necessary even with CSRSS as
* the calling process because it can incurr an in-page exception.
*/
try {
if (ARGUMENT_PRESENT(pdrdRestore)) {
ProbeForRead(pdrdRestore, sizeof(DESKRESTOREDATA), sizeof(DWORD));
RtlCopyMemory(&drdRestore, pdrdRestore, sizeof(DESKRESTOREDATA));
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxHardErrorControl(dwCmd, handle, (ARGUMENT_PRESENT(pdrdRestore))? &drdRestore : NULL);
try {
if (ARGUMENT_PRESENT(pdrdRestore)) {
ProbeForWrite(pdrdRestore, sizeof(DESKRESTOREDATA), sizeof(DWORD));
RtlCopyMemory(pdrdRestore, &drdRestore, sizeof(DESKRESTOREDATA));
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserHardErrorControl");
ENDRECVCSRSS();
}
BOOL NtUserGetObjectInformation( // API GetUserObjectInformationA/W
IN HANDLE hObject,
IN int nIndex,
OUT PVOID pvInfo,
IN DWORD nLength,
OUT OPTIONAL LPDWORD pnLengthNeeded)
{
DWORD dwAlign;
DWORD dwLocalLength;
BEGINATOMICRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
#if defined(_X86_)
dwAlign = sizeof(BYTE);
#else
if (nIndex == UOI_FLAGS) {
dwAlign = sizeof(DWORD);
} else {
dwAlign = sizeof(WCHAR);
}
#endif
ProbeForWrite(pvInfo, nLength, dwAlign);
if (ARGUMENT_PRESENT(pnLengthNeeded))
ProbeForWriteUlong(pnLengthNeeded);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Make sure the handle doesn't get closed while we're playing with it.
*/
SetHandleInUse(hObject);
/*
* pvInfo is client-side. GetUserObjectInformation
* protects use of this pointer with try blocks.
*/
retval = _GetUserObjectInformation(hObject,
nIndex, pvInfo,
nLength, &dwLocalLength);
/*
* OK, we're done with the handle.
*/
SetHandleInUse(NULL);
if (ARGUMENT_PRESENT(pnLengthNeeded)) {
try {
*pnLengthNeeded = dwLocalLength;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetObjectInformation");
ENDATOMICRECV();
}
BOOL NtUserWin32PoolAllocationStats(
IN LPDWORD parrTags,
IN SIZE_T tagsCount,
OUT SIZE_T* lpdwMaxMem,
OUT SIZE_T* lpdwCrtMem,
OUT LPDWORD lpdwMaxAlloc,
OUT LPDWORD lpdwCrtAlloc)
{
#ifdef POOL_INSTR_API
SIZE_T dwMaxMem, dwCrtMem;
DWORD dwMaxAlloc, dwCrtAlloc;
BEGINRECV(BOOL, FALSE);
retval = _Win32PoolAllocationStats(parrTags,
tagsCount,
&dwMaxMem,
&dwCrtMem,
&dwMaxAlloc,
&dwCrtAlloc);
/*
* Probe and copy
*/
try {
if (lpdwMaxMem != NULL) {
ProbeForWrite(lpdwMaxMem, sizeof(SIZE_T), sizeof(DWORD));
*lpdwMaxMem = dwMaxMem;
}
if (lpdwCrtMem != NULL) {
ProbeForWrite(lpdwCrtMem, sizeof(SIZE_T), sizeof(DWORD));
*lpdwCrtMem = dwCrtMem;
}
if (lpdwMaxAlloc != NULL) {
ProbeForWrite(lpdwMaxAlloc, sizeof(DWORD), sizeof(DWORD));
*lpdwMaxAlloc = dwMaxAlloc;
}
if (lpdwCrtAlloc != NULL) {
ProbeForWrite(lpdwCrtAlloc, sizeof(DWORD), sizeof(DWORD));
*lpdwCrtAlloc = dwCrtAlloc;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserWin32PoolAllocationStats");
ENDRECV();
#else
UNREFERENCED_PARAMETER(parrTags);
UNREFERENCED_PARAMETER(tagsCount);
UNREFERENCED_PARAMETER(lpdwMaxMem);
UNREFERENCED_PARAMETER(lpdwCrtMem);
UNREFERENCED_PARAMETER(lpdwMaxAlloc);
UNREFERENCED_PARAMETER(lpdwCrtAlloc);
return FALSE;
#endif // POOL_INSTR_API
}
#if DBG
VOID NtUserDbgWin32HeapFail( // private DbgWin32HeapFail
IN DWORD dwFlags,
IN BOOL bFail)
{
BEGINRECV_VOID();
if ((dwFlags | WHF_VALID) != WHF_VALID) {
RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags);
MSGERROR_VOID();
}
Win32HeapFailAllocations(bFail);
TRACEVOID("NtUserDbgWin32HeapFail");
ENDRECV_VOID();
}
DWORD NtUserDbgWin32HeapStat( // private DbgWin32HeapStat
PDBGHEAPSTAT phs,
DWORD dwLen)
{
extern DWORD Win32HeapStat(PDBGHEAPSTAT phs, DWORD dwLen, BOOL bTagsAreShift);
DBGHEAPSTAT localHS[30];
BEGINRECV(DWORD, 0);
LIMITVALUE(dwLen, sizeof(localHS), "DbgWin32HeapStat");
try{
ProbeForRead(phs, dwLen, CHARALIGN);
RtlCopyMemory(localHS, phs, dwLen);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = Win32HeapStat(localHS, dwLen, FALSE);
try {
ProbeForWrite(phs, dwLen, CHARALIGN);
RtlCopyMemory(phs, localHS, dwLen);
} except (StubExceptionHandler(FALSE)) {
}
TRACE("NtUserDbgWin32HeapStat");
ENDRECV();
}
#endif // DBG
BOOL NtUserSetObjectInformation( // API SetUserObjectInformationA/W
IN HANDLE hObject,
IN int nIndex,
IN PVOID pvInfo,
IN DWORD nLength)
{
BEGINATOMICRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
ProbeForRead(pvInfo, nLength, DATAALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Make sure the handle doesn't get closed while we're playing with it.
*/
SetHandleInUse(hObject);
/*
* pvInfo is client-side. SetUserObjectInformation
* protects use of this pointer with try blocks.
*/
retval = _SetUserObjectInformation(hObject,
nIndex, pvInfo, nLength);
/*
* OK, we're done with the handle.
*/
SetHandleInUse(NULL);
TRACE("NtUserSetObjectInformation");
ENDATOMICRECV();
}
NTSTATUS NtUserConsoleControl( // private NtUserConsoleControl
IN CONSOLECONTROL ConsoleCommand,
IN PVOID ConsoleInformation,
IN DWORD ConsoleInformationLength)
{
union {
CONSOLEDESKTOPCONSOLETHREAD DesktopConsole;
ATOM ClassAtom;
CONSOLE_PROCESS_INFO ProcessInfo;
RECT rc;
HPALETTE hPalette;
CONSOLEWINDOWSTATIONPROCESS WindowStationConsole;
CONSOLE_REGISTER_CONSOLEIME IMEConsole;
CONSOLE_FULLSCREEN_SWITCH FullScreenConsole;
CONSOLE_CARET_INFO CaretInfo;
} ConsoleInformationUnion;
PVOID pConsoleInformation = &ConsoleInformationUnion;
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (ConsoleInformationLength > sizeof(ConsoleInformationUnion)) {
FRE_RIPMSG2(
RIP_ERROR,
"ConsoleInformationLength: %x is greater than union size: %x.",
ConsoleInformationLength,
sizeof(ConsoleInformationUnion));
}
/*
* Probe all arguments. Try block necessary even with CSRSS as
* the calling process because it can incurr an in-page exception.
*/
try {
if (ARGUMENT_PRESENT(ConsoleInformation)) {
ProbeForRead(ConsoleInformation, ConsoleInformationLength, sizeof(ATOM));
RtlCopyMemory(pConsoleInformation, ConsoleInformation, ConsoleInformationLength);
} else {
pConsoleInformation = NULL;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxConsoleControl(
ConsoleCommand,
pConsoleInformation,
ConsoleInformationLength);
try {
if (ARGUMENT_PRESENT(ConsoleInformation)) {
ProbeForWrite(ConsoleInformation, ConsoleInformationLength, sizeof(ATOM));
RtlCopyMemory(ConsoleInformation, pConsoleInformation, ConsoleInformationLength);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserConsoleControl");
ENDRECVCSRSS();
}
HWINSTA NtUserCreateWindowStation( // API CreateWindowStationA/W
IN POBJECT_ATTRIBUTES pObja,
IN ACCESS_MASK amRequest,
IN HANDLE hKbdLayoutFile,
IN DWORD offTable,
IN PKBDTABLE_MULTI_INTERNAL pKbdTableMulti,
IN PUNICODE_STRING pstrKLID,
UINT uKbdInputLocale)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES CapturedAttributes;
SECURITY_QUALITY_OF_SERVICE qosCaptured;
PSECURITY_DESCRIPTOR psdCaptured = NULL;
LUID luidService;
UNICODE_STRING strWinSta;
UNICODE_STRING strKLID;
KBDTABLE_MULTI_INTERNAL kbdTableMulti;
WCHAR awchName[MAX_SESSION_PATH];
WCHAR awchKF[KL_NAMELENGTH];
UINT chMax;
KPROCESSOR_MODE OwnershipMode;
BEGINRECV(HWINSTA, NULL);
/*
* Set status so we can clean up in case of failure
*/
Status = STATUS_SUCCESS;
try {
/*
* Probe and capture the ??? string
*/
strKLID = ProbeAndReadUnicodeString(pstrKLID);
ProbeForReadUnicodeStringBuffer(strKLID);
chMax = min(sizeof(awchKF) - sizeof(WCHAR), strKLID.Length) / sizeof(WCHAR);
wcsncpycch(awchKF, strKLID.Buffer, chMax);
awchKF[chMax] = 0;
kbdTableMulti = ProbeAndReadStructure(pKbdTableMulti, KBDTABLE_MULTI_INTERNAL);
if (kbdTableMulti.multi.nTables >= KBDTABLE_MULTI_MAX) {
RIPMSG1(RIP_WARNING, "NtUserCreateWindowStation: kbdTableMulti.multi.nTables too big: %x", kbdTableMulti.multi.nTables);
MSGERROR(ERROR_INVALID_PARAMETER);
}
/*
* Probe and capture the object attributes
*/
CapturedAttributes = ProbeAndReadStructure(pObja, OBJECT_ATTRIBUTES);
/*
* Probe and capture all other components of the object attributes.
*/
if (CapturedAttributes.ObjectName == NULL && CapturedAttributes.RootDirectory == NULL) {
/*
* Use the logon authentication id to form the windowstation
* name.
*/
Status = GetProcessLuid(NULL, &luidService);
if (NT_SUCCESS(Status)) {
swprintf(awchName, L"%ws\\Service-0x%x-%x$",
szWindowStationDirectory,
luidService.HighPart, luidService.LowPart);
RtlInitUnicodeString(&strWinSta, awchName);
CapturedAttributes.ObjectName = &strWinSta;
}
OwnershipMode = KernelMode;
} else {
strWinSta = ProbeAndReadUnicodeString(CapturedAttributes.ObjectName);
ProbeForReadUnicodeStringBuffer(strWinSta);
/*
* Use the StaticUnicodeBuffer on the TEB as the buffer for the
* object name. Even if this is client side and we pass
* KernelMode to the Ob call in _OpenWindowStation this is
* safe because the TEB is not going to go away during this
* call. The worst it can happen is to have the buffer in the
* TEB trashed.
*/
strWinSta.Length = min(strWinSta.Length, STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR));
RtlCopyMemory(NtCurrentTeb()->StaticUnicodeBuffer,
strWinSta.Buffer,
strWinSta.Length);
strWinSta.Buffer = NtCurrentTeb()->StaticUnicodeBuffer;
CapturedAttributes.ObjectName = &strWinSta;
OwnershipMode = UserMode;
}
if (CapturedAttributes.SecurityQualityOfService) {
PSECURITY_QUALITY_OF_SERVICE pqos;
pqos = CapturedAttributes.SecurityQualityOfService;
qosCaptured = ProbeAndReadStructure(pqos, SECURITY_QUALITY_OF_SERVICE);
CapturedAttributes.SecurityQualityOfService = &qosCaptured;
}
if (NT_SUCCESS(Status) && CapturedAttributes.SecurityDescriptor != NULL) {
Status = SeCaptureSecurityDescriptor(
CapturedAttributes.SecurityDescriptor,
UserMode,
PagedPool,
FALSE,
&psdCaptured);
if (!NT_SUCCESS(Status)) {
psdCaptured = NULL;
}
CapturedAttributes.SecurityDescriptor = psdCaptured;
}
} except (StubExceptionHandler(FALSE)) {
Status = GetExceptionCode();
}
if (!NT_SUCCESS(Status)) {
MSGERRORCLEANUP(RtlNtStatusToDosError(Status));
}
/*
* Create the windowstation and return a kernel handle.
*/
retval = xxxCreateWindowStation(&CapturedAttributes,
OwnershipMode,
amRequest,
hKbdLayoutFile,
offTable,
&kbdTableMulti,
awchKF,
uKbdInputLocale);
CLEANUPRECV();
/*
* Release captured security descriptor.
*/
if (psdCaptured != NULL) {
SeReleaseSecurityDescriptor(psdCaptured, UserMode, FALSE);
}
TRACE("NtUserCreateWindowStation");
ENDRECV();
}
HWINSTA NtUserOpenWindowStation(
IN OUT POBJECT_ATTRIBUTES pObja,
IN ACCESS_MASK amRequest)
{
NTSTATUS Status;
LUID luidService;
WCHAR awchName[sizeof(L"Service-0x0000-0000$") / sizeof(WCHAR)];
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING ObjectName;
BEGINRECV(HWINSTA, NULL);
/*
* NT Bug 387849: We want to allow the caller to pass in a "template" to
* be filled in for the Service windowstation. So, we need to walk
* through the pObja structure and check the string out, replacing it
* with the real object name if necessary.
*
* It is VERY important that we pass the pObja object to the executive
* (through _OpenWindowStation) and not the Obja object. This is
* because we will request UserMode for this object, and the executive
* will check that it is actually getting a user-mode address.
*
* We will still make a copy of the structures to manipulate while we
* are walking everything so that we don't need to worry about the rug
* being removed from beneath us. The executive will do its own checking.
*/
try {
/*
* Probe the object attributes. We need to be able to read the
* OBJECT_ATTRIBUTES and to write the ObjectName (UNICODE_STRING).
*/
Obja = ProbeAndReadStructure(pObja, OBJECT_ATTRIBUTES);
ProbeForWrite(Obja.ObjectName, sizeof(*(Obja.ObjectName)), DATAALIGN);
ObjectName = ProbeAndReadUnicodeString(Obja.ObjectName);
/*
* If we are trying to open the NULL or "" WindowStation, remap this
* benign name to Service-0x????-????$.
*/
if (Obja.RootDirectory != NULL &&
ObjectName.Buffer != NULL &&
ObjectName.MaximumLength == sizeof(awchName) &&
ObjectName.Length == (sizeof(awchName) - sizeof(UNICODE_NULL))) {
/*
* Use the logon authentication id to form the windowstation
* name. Put this in the user's buffer since we were the one
* who allocated it in _OpenWindowStation.
*/
ProbeForWrite(ObjectName.Buffer, ObjectName.MaximumLength, CHARALIGN);
if (!_wcsicmp(ObjectName.Buffer, L"Service-0x0000-0000$")) {
Status = GetProcessLuid(NULL, &luidService);
if (NT_SUCCESS(Status)) {
swprintf(ObjectName.Buffer,
L"Service-0x%x-%x$",
luidService.HighPart,
luidService.LowPart);
/*
* We need to re-initialize the string to get the counted
* length correct. Otherwise the hashing function used
* by ObpLookupDirectoryEntry will fail.
*/
RtlInitUnicodeString(Obja.ObjectName, ObjectName.Buffer);
}
}
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Open the WindowStation.
*/
retval = _OpenWindowStation(pObja, amRequest, UserMode);
TRACE("NtUserOpenWindowStation");
ENDRECV();
}
BOOL NtUserCloseWindowStation(
IN HWINSTA hwinsta)
{
PWINDOWSTATION pwinsta;
NTSTATUS Status;
BEGINRECV(BOOL, FALSE);
retval = FALSE;
Status = ValidateHwinsta(hwinsta, UserMode, 0, &pwinsta);
if (NT_SUCCESS(Status)) {
retval = _CloseWindowStation(hwinsta);
ObDereferenceObject(pwinsta);
}
TRACE("NtUserCloseWindowStation");
ENDRECV();
}
BOOL NtUserSetProcessWindowStation(
IN HWINSTA hwinsta)
{
BEGINRECV(BOOL, FALSE);
retval = NT_SUCCESS(_SetProcessWindowStation(hwinsta, UserMode));
TRACE("NtUserSetProcessWindowStation");
ENDRECV();
}
HWINSTA NtUserGetProcessWindowStation(
VOID)
{
BEGINRECV_SHARED(HWINSTA, NULL);
_GetProcessWindowStation(&retval);
TRACE("NtUserGetProcessWindowStation");
ENDRECV_SHARED();
}
BOOL NtUserLockWorkStation(
VOID)
{
BEGINRECV(BOOL, FALSE);
retval = _LockWorkStation();
TRACE("NtUserLockWorkStation");
ENDRECV();
}
HDESK NtUserCreateDesktop( // API CreateDesktopA/W
IN POBJECT_ATTRIBUTES pObja,
IN PUNICODE_STRING pstrDevice,
IN LPDEVMODEW pDevmode,
IN DWORD dwFlags,
IN ACCESS_MASK amRequest)
{
BEGINRECV(HDESK, NULL);
/*
* Fail this call for restricted threads.
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_DESKTOP)) {
RIPMSGF0(RIP_WARNING, "Failed for restricted thread");
MSGERROR(ERROR_ACCESS_DENIED);
}
/*
* Validate the dwFlags parameter. The only externally visible flag is
* DF_ALLOWOTHERACCOUNTHOOK.
*/
if (dwFlags && dwFlags != DF_ALLOWOTHERACCOUNTHOOK) {
RIPMSGF1(RIP_WARNING, "Invalid dwFlags 0x%x", dwFlags);
MSGERROR(ERROR_INVALID_PARAMETER);
}
/*
* Probe arguments.
*/
try {
ProbeForRead(pObja, sizeof(*pObja), sizeof(DWORD));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* pObja, pDevmode, and pstrDevice are all client side addresses.
*
* pstrDevice and pDevmode are put into the Context info, and they are
* used by GDI (where thay are captured before use).
*/
retval = xxxCreateDesktop(pObja,
UserMode,
pstrDevice,
pDevmode,
dwFlags,
amRequest);
TRACE("NtUserCreateDesktop");
ENDRECV();
}
HDESK NtUserOpenDesktop(
IN POBJECT_ATTRIBUTES pObja,
IN DWORD dwFlags,
IN ACCESS_MASK amRequest)
{
BOOL bShutDown;
BEGINRECV(HDESK, NULL);
retval = _OpenDesktop(pObja, UserMode, dwFlags, amRequest, &bShutDown);
TRACE("NtUserOpenDesktop");
ENDRECV();
}
HDESK NtUserOpenInputDesktop(
IN DWORD dwFlags,
IN BOOL fInherit,
IN DWORD amRequest)
{
HWINSTA hwinsta;
PWINDOWSTATION pwinsta;
PDESKTOP pdesk;
NTSTATUS Status;
BEGINRECV(HDESK, NULL);
if (grpdeskRitInput == NULL) {
MSGERROR(ERROR_OPEN_FAILED);
} else {
pwinsta = _GetProcessWindowStation(&hwinsta);
if (pwinsta == NULL) {
MSGERROR(ERROR_ACCESS_DENIED);
}
if (pwinsta->dwWSF_Flags & WSF_NOIO) {
MSGERROR(ERROR_INVALID_FUNCTION);
} else {
/*
* We should never return the 'Disconnect' desktop to an app. We
* should instead return the desktop that we will restore to
* from the Disconnect desktop.
*/
pdesk = (gbDesktopLocked ? gspdeskShouldBeForeground : grpdeskRitInput);
if (pdesk == NULL) {
MSGERROR(ERROR_OPEN_FAILED);
}
/*
* Require read/write access
*/
amRequest |= DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS;
Status = ObOpenObjectByPointer(
pdesk,
fInherit ? OBJ_INHERIT : 0,
NULL,
amRequest,
*ExDesktopObjectType,
UserMode,
&retval);
if (NT_SUCCESS(Status)) {
BOOL bShutDown;
/*
* Complete the desktop open
*/
if (!OpenDesktopCompletion(pdesk, retval, dwFlags, &bShutDown)) {
CloseProtectedHandle(retval);
retval = NULL;
} else {
SetHandleFlag(retval, HF_PROTECTED, TRUE);
}
} else {
MSGERROR(RtlNtStatusToDosError(Status));
}
}
}
TRACE("NtUserOpenInputDesktop");
ENDRECV();
}
NTSTATUS NtUserResolveDesktopForWOW ( // WOW ResolveDesktopForWOW
IN OUT PUNICODE_STRING pstrDesktop)
{
UNICODE_STRING strDesktop, strDesktop2;
PTHREADINFO ptiCurrent;
TL tlBuffer;
LPWSTR lpBuffer = NULL;
BOOL fFreeBuffer = FALSE;
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
retval = STATUS_SUCCESS;
ptiCurrent = PtiCurrent();
/*
* Probe arguments
*/
try {
strDesktop = ProbeAndReadUnicodeString(pstrDesktop);
ProbeForReadUnicodeStringFullBuffer(strDesktop);
RtlCopyMemory(&strDesktop2, &strDesktop, sizeof(strDesktop));
if (strDesktop.MaximumLength > 0) {
PWSTR pszCapture = strDesktop.Buffer;
strDesktop.Buffer = UserAllocPoolWithQuota(strDesktop.MaximumLength, TAG_TEXT2);
if (strDesktop.Buffer) {
fFreeBuffer = TRUE;
ThreadLockPool(ptiCurrent, strDesktop.Buffer, &tlBuffer);
RtlCopyMemory(strDesktop.Buffer, pszCapture, strDesktop.Length);
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} else {
strDesktop.Buffer = NULL;
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = xxxResolveDesktopForWOW(&strDesktop);
if (NT_SUCCESS(retval)) {
try {
/*
* The string structure at pstrDesktop could have changed
* so we will ignore it and drop the one we have already
* probed down on top of it. We have already performed the
* ResolveDesktopForWOW action, so we should not return an
* error if this copy fails.
*/
RtlCopyUnicodeString(&strDesktop2, &strDesktop);
RtlCopyMemory(pstrDesktop, &strDesktop2, sizeof(strDesktop2));
} except (StubExceptionHandler(FALSE)) {
}
}
CLEANUPRECV();
if (fFreeBuffer)
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
TRACE("NtUserResolveDesktopForWOW");
ENDRECV();
}
HDESK NtUserResolveDesktop(
IN HANDLE hProcess,
IN PUNICODE_STRING pstrDesktop,
IN BOOL fInherit,
OUT HWINSTA *phwinsta)
{
UNICODE_STRING strDesktop;
HWINSTA hwinsta = NULL;
PTHREADINFO pti;
TL tlBuffer;
BOOL fFreeBuffer = FALSE;
BOOL bShutDown = FALSE;
BEGINRECV(HDESK, NULL);
pti = PtiCurrent();
/*
* Probe and capture desktop path
*/
try {
strDesktop = ProbeAndReadUnicodeString(pstrDesktop);
if (strDesktop.Length > 0) {
PWSTR pszCapture = strDesktop.Buffer;
ProbeForReadUnicodeStringBuffer(strDesktop);
strDesktop.Buffer = UserAllocPoolWithQuota(strDesktop.Length, TAG_TEXT2);
if (strDesktop.Buffer) {
fFreeBuffer = TRUE;
ThreadLockPool(pti, strDesktop.Buffer, &tlBuffer);
RtlCopyMemory(strDesktop.Buffer, pszCapture, strDesktop.Length);
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} else {
strDesktop.Buffer = NULL;
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = xxxResolveDesktop(hProcess, &strDesktop, &hwinsta,
fInherit, &bShutDown);
CLEANUPRECV();
if (fFreeBuffer)
ThreadUnlockAndFreePool(pti, &tlBuffer);
if (retval != NULL) {
try {
ProbeAndWriteHandle((PHANDLE)phwinsta, hwinsta);
} except (StubExceptionHandler(TRUE)) {
xxxCloseDesktop(retval, KernelMode);
if (hwinsta) {
_CloseWindowStation(hwinsta);
}
MSGERROR(0);
}
} else {
UserAssert(hwinsta == NULL);
}
TRACE("NtUserResolveDesktop");
ENDRECV();
}
BOOL NtUserCloseDesktop(
IN HDESK hdesk)
{
BEGINRECV(BOOL, FALSE);
retval = xxxCloseDesktop(hdesk, UserMode);
TRACE("NtUserCloseDesktop");
ENDRECV();
}
BOOL NtUserSetThreadDesktop(
IN HDESK hdesk)
{
PDESKTOP pdesk = NULL;
NTSTATUS Status = STATUS_SUCCESS;
BEGINRECV(BOOL, FALSE);
Status = ValidateHdesk(hdesk, UserMode, 0, &pdesk);
if (NT_SUCCESS(Status)) {
retval = xxxSetThreadDesktop(hdesk, pdesk);
LogDesktop(pdesk, LD_DEREF_VALIDATE_HDESK1, FALSE, (ULONG_PTR)PtiCurrent());
ObDereferenceObject(pdesk);
} else if (hdesk == NULL && PsGetCurrentProcess() == gpepCSRSS) {
retval = xxxSetThreadDesktop(NULL, NULL);
} else {
retval = FALSE;
}
TRACE("NtUserSetThreadDesktop");
ENDRECV();
}
HDESK NtUserGetThreadDesktop(
IN DWORD dwThreadId,
IN HDESK hdeskConsole)
{
BEGINRECV_SHARED(HDESK, NULL);
retval = xxxGetThreadDesktop(dwThreadId, hdeskConsole, UserMode);
TRACE("NtUserGetThreadDesktop");
ENDRECV_SHARED();
}
BOOL NtUserSwitchDesktop(
IN HDESK hdesk)
{
PDESKTOP pdesk;
TL tlpdesk;
PTHREADINFO ptiCurrent;
NTSTATUS Status;
BEGINRECV(BOOL, FALSE);
ptiCurrent = PtiCurrent();
/*
* Fail this call for restricted threads
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_DESKTOP)) {
RIPMSG0(RIP_WARNING, "NtUserSwitchDesktop failed for restricted thread");
MSGERROR(0);
}
Status = ValidateHdesk(hdesk, UserMode, DESKTOP_SWITCHDESKTOP, &pdesk);
if (NT_SUCCESS(Status)) {
if (pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) {
LogDesktop(pdesk, LD_DEREF_VALIDATE_HDESK2, FALSE, (ULONG_PTR)PtiCurrent());
ObDereferenceObject(pdesk);
RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "");
retval = FALSE;
} else {
ThreadLockDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_NTUSERSWITCHDESKTOP);
LogDesktop(pdesk, LD_DEREF_VALIDATE_HDESK3, FALSE, (ULONG_PTR)PtiCurrent());
ObDereferenceObject(pdesk);
retval = xxxSwitchDesktop(NULL, pdesk, 0);
ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_NTUSERSWITCHDESKTOP);
}
} else {
retval = FALSE;
}
TRACE("NtUserSwitchDesktop");
ENDRECV();
}
NTSTATUS NtUserInitializeClientPfnArrays( // private
IN CONST PFNCLIENT *ppfnClientA OPTIONAL,
IN CONST PFNCLIENT *ppfnClientW OPTIONAL,
IN CONST PFNCLIENTWORKER *ppfnClientWorker OPTIONAL,
IN HANDLE hModUser)
{
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* Probe all read arguments
*/
try {
if (ARGUMENT_PRESENT(ppfnClientA)) {
ProbeForRead(ppfnClientA, sizeof(*ppfnClientA), sizeof(DWORD));
}
if (ARGUMENT_PRESENT(ppfnClientW)) {
ProbeForRead(ppfnClientW, sizeof(*ppfnClientW), sizeof(DWORD));
}
if (ARGUMENT_PRESENT(ppfnClientWorker)) {
ProbeForRead(ppfnClientWorker, sizeof(*ppfnClientWorker), sizeof(DWORD));
}
retval = InitializeClientPfnArrays(
ppfnClientA, ppfnClientW, ppfnClientWorker, hModUser);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserInitializeThreadInfo");
ENDRECV();
}
BOOL NtUserWaitForMsgAndEvent(
IN HANDLE hevent)
{
BEGINRECV(BOOL, FALSE);
retval = xxxSleepTask(FALSE, hevent);
TRACE("NtUserWaitForMsgAndEvent");
ENDRECV();
}
DWORD NtUserDragObject(
IN HWND hwndParent,
IN HWND hwndFrom,
IN UINT wFmt,
IN ULONG_PTR dwData,
IN HCURSOR hcur)
{
PWND pwndFrom;
PCURSOR pcur;
TL tlpwndFrom;
TL tlpcur;
BEGINRECV_HWNDLOCK(DWORD, 0, hwndParent);
ValidateHWNDOPT(pwndFrom, hwndFrom);
ValidateHCURSOROPT(pcur, hcur);
ThreadLockWithPti(ptiCurrent, pwndFrom, &tlpwndFrom);
ThreadLockWithPti(ptiCurrent, pcur, &tlpcur);
retval = xxxDragObject(
pwnd,
pwndFrom,
wFmt,
dwData,
pcur);
ThreadUnlock(&tlpcur);
ThreadUnlock(&tlpwndFrom);
TRACE("NtUserDragObject");
ENDRECV_HWNDLOCK();
}
BOOL NtUserGetIconInfo( // API GetIconInfo
IN HICON hIcon,
OUT PICONINFO piconinfo,
IN OUT OPTIONAL PUNICODE_STRING pstrInstanceName,
IN OUT OPTIONAL PUNICODE_STRING pstrResName,
OUT LPDWORD pbpp,
IN BOOL fInternal)
{
PICON pIcon;
UNICODE_STRING strInstanceName, *pstrInstanceLocal;
UNICODE_STRING strResName, *pstrResLocal;
BEGINATOMICRECV(BOOL, FALSE);
/*
* NOTE -- this can't be _SHARED since it calls Gre code with system HDC's.
*/
ValidateHCURSOR(pIcon, hIcon);
/*
* Probe arguments
*/
try {
if (pstrInstanceName != NULL) {
strInstanceName = ProbeAndReadUnicodeString(pstrInstanceName);
ProbeForWrite(strInstanceName.Buffer, strInstanceName.MaximumLength, CHARALIGN);
pstrInstanceLocal = &strInstanceName;
} else {
pstrInstanceLocal = NULL;
}
if (pstrResName != NULL) {
strResName = ProbeAndReadUnicodeString(pstrResName);
ProbeForWrite(strResName.Buffer, strResName.MaximumLength, CHARALIGN);
pstrResLocal = &strResName;
} else {
pstrResLocal = NULL;
}
if (pbpp != NULL) {
ProbeForWrite(pbpp, sizeof(DWORD), sizeof(DWORD));
}
ProbeForWrite(piconinfo, sizeof(*piconinfo), DATAALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* All use of client-side pointers in InternalGetIconInfo
* is protected by try/except.
*/
retval = _InternalGetIconInfo(
pIcon,
piconinfo,
pstrInstanceLocal,
pstrResLocal,
pbpp,
fInternal);
try {
if (pstrInstanceName != NULL) {
RtlCopyMemory(pstrInstanceName, pstrInstanceLocal, sizeof(UNICODE_STRING));
}
if (pstrResName != NULL) {
RtlCopyMemory(pstrResName, pstrResLocal, sizeof(UNICODE_STRING));
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetIconInfo");
ENDATOMICRECV();
}
BOOL NtUserGetIconSize( // private
IN HICON hIcon,
IN UINT istepIfAniCur,
OUT int *pcx,
OUT int *pcy)
{
PCURSOR picon;
BEGINRECV_SHARED(BOOL, FALSE);
ValidateHICON(picon, hIcon);
if (picon->CURSORF_flags & CURSORF_ACON) {
PACON pacon = (PACON)picon;
if (istepIfAniCur < (UINT)pacon->cpcur) {
picon = pacon->aspcur[pacon->aicur[istepIfAniCur]];
} else {
RIPMSG2(RIP_WARNING, "NtUserGetIconSize: Invalid istepIfAniCur:%#lx. picon:%#p",
istepIfAniCur, picon);
MSGERROR(0);
}
}
/*
* Probe arguments
*/
try {
ProbeAndWriteLong(pcx, picon->cx);
ProbeAndWriteLong(pcy, picon->cy);
retval = 1;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserGetIconSize");
ENDRECV_SHARED();
}
BOOL NtUserDrawIconEx( // API DrawIconEx
IN HDC hdc,
IN int x,
IN int y,
IN HICON hicon,
IN int cx,
IN int cy,
IN UINT istepIfAniCur,
IN HBRUSH hbrush,
IN UINT diFlags,
IN BOOL fMeta,
OUT DRAWICONEXDATA *pdid)
{
PCURSOR picon;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHICON(picon, hicon);
if (fMeta) {
if (picon->CURSORF_flags & CURSORF_ACON)
picon = ((PACON)picon)->aspcur[((PACON)picon)->aicur[0]];
/*
* Probe arguments
*/
try {
ProbeForWrite(pdid, sizeof(*pdid), DATAALIGN);
pdid->hbmMask = picon->hbmMask;
pdid->hbmColor = picon->hbmColor;
pdid->hbmUserAlpha = picon->hbmUserAlpha;
pdid->cx = picon->cx;
pdid->cy = picon->cy;
retval = 1;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
} else {
retval = _DrawIconEx(hdc,
x,
y,
picon,
cx,
cy,
istepIfAniCur,
hbrush,
diFlags);
}
TRACE("NtUserDrawIconEx");
ENDATOMICRECV();
}
HANDLE NtUserDeferWindowPos(
IN HDWP hWinPosInfo,
IN HWND hwnd,
IN HWND hwndInsertAfter,
IN int x,
IN int y,
IN int cx,
IN int cy,
IN UINT wFlags)
{
PWND pwnd;
PWND pwndInsertAfter;
PSMWP psmwp;
BEGINATOMICRECV(HANDLE, NULL);
TESTFLAGS(wFlags, SWP_VALID);
ValidateHWNDND(pwnd, hwnd);
ValidateHWNDIA(pwndInsertAfter, hwndInsertAfter);
ValidateHDWP(psmwp, hWinPosInfo);
if (wFlags & ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
SWP_NOREDRAW | SWP_NOACTIVATE | SWP_FRAMECHANGED |
SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOCOPYBITS |
SWP_NOOWNERZORDER)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid flags (0x%lx) passed to DeferWindowPos",
wFlags);
MSGERROR(0);
}
/*
* Make sure the window coordinates can fit in WORDs.
*/
if (!(wFlags & SWP_NOMOVE)) {
if (x > SHRT_MAX) {
x = SHRT_MAX;
} else if (x < SHRT_MIN) {
x = SHRT_MIN;
}
if (y > SHRT_MAX) {
y = SHRT_MAX;
} else if (y < SHRT_MIN) {
y = SHRT_MIN;
}
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (!(wFlags & SWP_NOSIZE)) {
if (cx < 0) {
cx = 0;
} else if (cx > SHRT_MAX) {
cx = SHRT_MAX;
}
if (cy < 0) {
cy = 0;
} else if (cy > SHRT_MAX) {
cy = SHRT_MAX;
}
}
#ifdef NEVER
//
// do not fail these conditions because real apps use them.
//
if (!(wFlags & SWP_NOMOVE) &&
(x > SHRT_MAX || x < SHRT_MIN ||
y > SHRT_MAX || y < SHRT_MIN)) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid coordinate passed to SetWindowPos");
MSGERROR(0);
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (!(wFlags & SWP_NOSIZE) &&
(cx < 0 || cx > SHRT_MAX ||
cy < 0 || cy > SHRT_MAX)) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid width/height passed to SetWindowPos");
MSGERROR(0);
}
#endif
retval = _DeferWindowPos(
psmwp,
pwnd,
pwndInsertAfter,
x,
y,
cx,
cy,
wFlags);
retval = PtoH((PVOID)retval);
TRACE("NtUserDeferWindowPos");
ENDATOMICRECV();
}
BOOL NtUserEndDeferWindowPosEx(
IN HDWP hWinPosInfo,
IN BOOL fAsync)
{
PSMWP psmwp;
TL tlpsmp;
BEGINRECV(BOOL, FALSE);
ValidateHDWP(psmwp, hWinPosInfo);
ThreadLockAlways(psmwp, &tlpsmp);
retval = xxxEndDeferWindowPosEx(
psmwp,
fAsync);
ThreadUnlock(&tlpsmp);
TRACE("NtUserEndDeferWindowPosEx");
ENDRECV();
}
BOOL NtUserGetMessage( // API GetMessageA/W
OUT LPMSG pmsg,
IN HWND hwnd,
IN UINT wMsgFilterMin,
IN UINT wMsgFilterMax)
{
MSG msg;
BEGINRECV(BOOL, FALSE);
retval = xxxGetMessage(
&msg,
hwnd,
wMsgFilterMin,
wMsgFilterMax);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure(pmsg, msg, MSG);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetMessage");
ENDRECV();
}
#ifdef MESSAGE_PUMP_HOOK
BOOL NtUserRealInternalGetMessage( // API RealInternalGetMessage
OUT LPMSG pmsg,
IN HWND hwnd,
IN UINT wMsgFilterMin,
IN UINT wMsgFilterMax,
IN UINT flags,
BOOL fGetMessage)
{
MSG msg;
BEGINRECV(BOOL, FALSE);
TESTFLAGS(flags, PM_VALID);
if (!IsInsideMPH()) {
RIPMSG0(RIP_WARNING, "NtUserRealInternalGetMessage: Calling MPH function on non-initialized thread");
}
retval = xxxRealInternalGetMessage(
&msg,
hwnd,
wMsgFilterMin,
wMsgFilterMax,
flags,
fGetMessage);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure(pmsg, msg, MSG);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserRealInternalGetMessage");
ENDRECV();
}
#endif // MESSAGE_PUMP_HOOK
BOOL NtUserMoveWindow(
IN HWND hwnd,
IN int x,
IN int y,
IN int cx,
IN int cy,
IN BOOL fRepaint)
{
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
/*
* Make sure the window coordinates can fit in WORDs.
*/
if (x > SHRT_MAX) {
x = SHRT_MAX;
} else if (x < SHRT_MIN) {
x = SHRT_MIN;
}
if (y > SHRT_MAX) {
y = SHRT_MAX;
} else if (y < SHRT_MIN) {
y = SHRT_MIN;
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (cx < 0) {
cx = 0;
} else if (cx > SHRT_MAX) {
cx = SHRT_MAX;
}
if (cy < 0) {
cy = 0;
} else if (cy > SHRT_MAX) {
cy = SHRT_MAX;
}
#ifdef NEVER
//
// do not fail these conditions because real apps use them.
//
if (x > SHRT_MAX || x < SHRT_MIN ||
y > SHRT_MAX || y < SHRT_MIN) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid coordinate passed to MoveWindow");
MSGERROR(0);
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (cx < 0 || cx > SHRT_MAX ||
cy < 0 || cy > SHRT_MAX) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid width/height passed to MoveWindow");
MSGERROR(0);
}
#endif
retval = xxxMoveWindow(
pwndND,
x,
y,
cx,
cy,
fRepaint);
TRACE("NtUserMoveWindow");
ENDRECV_HWNDLOCK_ND();
}
int NtUserTranslateAccelerator( // API TranslateAcceleratorA/W
IN HWND hwnd,
IN HACCEL haccel,
IN LPMSG lpmsg)
{
PWND pwnd;
LPACCELTABLE pat;
TL tlpwnd;
TL tlpat;
PTHREADINFO ptiCurrent;
MSG msg;
BEGINRECV(int, 0);
/*
* Probe arguments
*/
try {
msg = ProbeAndReadMessage(lpmsg);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* This is called within a message loop. If the window gets destroyed,
* there still may be other messages in the queue that get returned
* after the window is destroyed. The app will call TranslateAccelerator()
* on every one of these, causing RIPs.... Make it nice so it just
* returns FALSE.
*/
ValidateHWNDNoRIP(pwnd, hwnd);
ValidateHACCEL(pat, haccel);
ptiCurrent = PtiCurrent();
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
ThreadLockAlwaysWithPti(ptiCurrent, pat, &tlpat);
retval = xxxTranslateAccelerator(
pwnd,
pat,
&msg);
ThreadUnlock(&tlpat);
ThreadUnlock(&tlpwnd);
TRACE("NtUserTranslateAccelerator");
ENDRECV();
}
LONG_PTR NtUserSetClassLongPtr( // API SetClassLongPtrA/W
IN HWND hwnd,
IN int nIndex,
OUT LONG_PTR dwNewLong,
IN BOOL bAnsi)
{
UNICODE_STRING strMenuName;
CLSMENUNAME cmn, *pcmnSave;
BEGINRECV_HWNDLOCK(ULONG_PTR, 0, hwnd);
switch (nIndex) {
case GCLP_MENUNAME:
try {
/*
* There is no callback from the routine for
* this value, so we can protect it with a try/except.
* This is cheaper than capturing the name
* and copying it back. FritzS
*/
pcmnSave = (PCLSMENUNAME) dwNewLong;
cmn = ProbeAndReadStructure(pcmnSave, CLSMENUNAME);
strMenuName = ProbeAndReadUnicodeString(cmn.pusMenuName);
ProbeForReadUnicodeStringBufferOrId(strMenuName);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
cmn.pusMenuName = &strMenuName;
dwNewLong = (ULONG_PTR) &cmn;
retval = xxxSetClassLongPtr(
pwnd,
nIndex,
dwNewLong,
bAnsi);
try {
ProbeAndWriteStructure(pcmnSave, cmn, CLSMENUNAME);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
break;
case GCL_STYLE:
/*
* I'm not sure how CS_VALID mask will affect existing apps,
* so leave it for now --- except CS_IME flag, on which the system
* deeply depends.
*/
#if DBG
if (dwNewLong & ~CS_VALID) {
RIPMSG1(RIP_WARNING, "NtUserSetClassLongPtr: Invalid style (%x) specified.", dwNewLong);
}
#endif
if (dwNewLong & CS_IME) {
RIPERR1(ERROR_INVALID_DATA, RIP_VERBOSE, "NtUserSetClassLongPtr: CS_IME is specified in new style (%x).", dwNewLong);
MSGERROR(0);
}
default:
retval = xxxSetClassLongPtr(
pwnd,
nIndex,
dwNewLong,
bAnsi);
}
TRACE("NtUserSetClassLongPtr");
ENDRECV_HWNDLOCK();
}
#ifdef _WIN64
LONG NtUserSetClassLong(
IN HWND hwnd,
IN int nIndex,
OUT LONG dwNewLong,
IN BOOL bAnsi)
{
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
switch (nIndex) {
case GCL_STYLE:
/*
* I'm not sure how CS_VALID mask will affect existing apps,
* so leave it for now --- except CS_IME flag, on which the system
* deeply depends.
*/
#if DBG
if (dwNewLong & ~CS_VALID) {
RIPMSG1(RIP_WARNING, "NtUserSetClassLong: Invalid style (%x) specified.", dwNewLong);
}
#endif
if (dwNewLong & CS_IME) {
RIPERR1(ERROR_INVALID_DATA, RIP_VERBOSE, "NtUserSetClassLong: CS_IME is specified in new style (%x).", dwNewLong);
MSGERROR(0);
}
}
retval = xxxSetClassLong(
pwnd,
nIndex,
dwNewLong,
bAnsi);
TRACE("NtUserSetClassLong");
ENDRECV_HWNDLOCK();
}
#endif
BOOL NtUserSetKeyboardState( // API SetKeyboardState
IN CONST BYTE *lpKeyState)
{
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
ProbeForRead(lpKeyState, 256, sizeof(BYTE));
retval = _SetKeyboardState(lpKeyState);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserSetKeyboardState");
ENDRECV();
}
BOOL NtUserSetWindowPos(
IN HWND hwnd,
IN HWND hwndInsertAfter,
IN int x,
IN int y,
IN int cx,
IN int cy,
IN UINT dwFlags)
{
PWND pwndT;
PWND pwndInsertAfter;
TL tlpwndT;
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
TESTFLAGS(dwFlags, SWP_VALID);
ValidateHWNDIA(pwndInsertAfter, hwndInsertAfter);
/*
* Let's not allow the window to be shown/hidden once we
* started the destruction of the window.
*/
if (TestWF(pwndND, WFINDESTROY)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"SetWindowPos: Window is being destroyed (pwnd == %#p)",
pwndND);
MSGERROR(0);
}
if (dwFlags & ~SWP_VALID) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"SetWindowPos: Invalid flags passed in (flags == 0x%lx)",
dwFlags);
MSGERROR(0);
}
/*
* Make sure the window coordinates can fit in WORDs.
*/
if (!(dwFlags & SWP_NOMOVE)) {
if (x > SHRT_MAX) {
x = SHRT_MAX;
} else if (x < SHRT_MIN) {
x = SHRT_MIN;
}
if (y > SHRT_MAX) {
y = SHRT_MAX;
} else if (y < SHRT_MIN) {
y = SHRT_MIN;
}
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (!(dwFlags & SWP_NOSIZE)) {
if (cx < 0) {
cx = 0;
} else if (cx > SHRT_MAX) {
cx = SHRT_MAX;
}
if (cy < 0) {
cy = 0;
} else if (cy > SHRT_MAX) {
cy = SHRT_MAX;
}
}
#ifdef NEVER
//
// do not fail these conditions because real apps use them.
//
if (!(dwFlags & SWP_NOMOVE) &&
(x > SHRT_MAX || x < SHRT_MIN ||
y > SHRT_MAX || y < SHRT_MIN)) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid coordinate passed to SetWindowPos");
MSGERROR(0);
}
/*
* Actually, if we were going to be really strict about this we'd
* make sure that x + cx < SHRT_MAX, etc but since we do maintain
* signed 32-bit coords internally this case doesn't cause a problem.
*/
if (!(dwFlags & SWP_NOSIZE) &&
(cx < 0 || cx > SHRT_MAX ||
cy < 0 || cy > SHRT_MAX)) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid width/height passed to SetWindowPos");
MSGERROR(0);
}
#endif
switch((ULONG_PTR)pwndInsertAfter) {
case (ULONG_PTR)HWND_TOPMOST:
case (ULONG_PTR)HWND_NOTOPMOST:
case (ULONG_PTR)HWND_TOP:
case (ULONG_PTR)HWND_BOTTOM:
pwndT = NULL;
break;
default:
pwndT = pwndInsertAfter;
break;
}
ThreadLockWithPti(ptiCurrent, pwndT, &tlpwndT);
retval = xxxSetWindowPos(
pwndND,
pwndInsertAfter,
x,
y,
cx,
cy,
dwFlags);
ThreadUnlock(&tlpwndT);
TRACE("NtUserSetWindowPos");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserSetShellWindowEx(
IN HWND hwnd,
IN HWND hwndBkGnd)
{
PWND pwndBkGnd;
TL tlpwndBkGnd;
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
ValidateHWNDND(pwndBkGnd, hwndBkGnd);
ThreadLockAlwaysWithPti(ptiCurrent, pwndBkGnd, &tlpwndBkGnd);
retval = xxxSetShellWindow(pwndND, pwndBkGnd);
ThreadUnlock(&tlpwndBkGnd);
TRACE("NtUserSetShellWindowEx");
ENDRECV_HWNDLOCK_ND();
}
DWORD
NtUserGetGuiResources(
HANDLE hProcess,
DWORD dwFlags)
{
PEPROCESS Process;
PW32PROCESS pW32Process;
BEGINRECV_SHARED(DWORD, 0);
/*
* Probe arguments
*/
if (dwFlags > GR_MAXOBJECT) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"GetGuiResources: Invalid flag bits 0x%x",
dwFlags);
MSGERROR(0);
}
if (hProcess == NtCurrentProcess()) {
pW32Process = W32GetCurrentProcess();
} else {
NTSTATUS Status;
Status = ObReferenceObjectByHandle(hProcess,
PROCESS_QUERY_INFORMATION,
*PsProcessType,
UserMode,
&Process,
NULL);
if (!NT_SUCCESS(Status)) {
RIPERR2(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"GetGuiResources: Failed with process 0x%x, Status = 0x%x",
hProcess,
Status);
MSGERROR(0);
}
/*
* Make sure they are from the same session
*/
if (PsGetProcessSessionId(Process) != gSessionId) {
RIPERR2(ERROR_INVALID_PARAMETER,
RIP_VERBOSE,
"GetGuiResources: Different session. Failed with process 0x%x, Status = 0x%x",
hProcess,
Status);
ObDereferenceObject(Process);
MSGERROR(0);
}
pW32Process = PsGetProcessWin32Process(Process);
}
if (pW32Process) {
switch(dwFlags) {
case GR_GDIOBJECTS:
retval = pW32Process->GDIHandleCount;
break;
case GR_USEROBJECTS:
retval = pW32Process->UserHandleCount;
break;
}
} else {
retval = 0;
}
if (hProcess != NtCurrentProcess()) {
ObDereferenceObject(Process);
}
TRACE("NtUserGetGuiResources");
ENDRECV_SHARED();
}
BOOL NtUserSystemParametersInfo( // API SystemParametersInfoA/W
IN UINT wFlag,
IN DWORD wParam,
IN OUT LPVOID lpData,
IN UINT flags)
{
UNICODE_STRING strData;
ULONG ulLength, ulLength2;
LPVOID lpDataSave;
union {
INT MouseData[3];
LOGFONTW LogFont;
MOUSEKEYS MouseKeys;
FILTERKEYS FilterKeys;
STICKYKEYS StickyKeys;
TOGGLEKEYS ToggleKeys;
SOUNDSENTRY SoundSentry;
ACCESSTIMEOUT AccessTimeout;
RECT Rect;
ANIMATIONINFO AnimationInfo;
NONCLIENTMETRICS NonClientMetrics;
MINIMIZEDMETRICS MinimizedMetrics;
ICONMETRICS IconMetrics;
HKL hkl;
INTERNALSETHIGHCONTRAST ihc;
HIGHCONTRAST hc;
WCHAR szTemp[MAX_PATH];
} CaptureBuffer;
PTHREADINFO pti;
TL tlBuffer;
BOOL fFreeBuffer = FALSE;
BOOL fWrite = FALSE;
BEGINRECV(BOOL, FALSE);
/*
* Prevent restricted processes from setting system
* parameters.
*
* clupu: this is ineficient and temporary. I'll change this
* soon !!!
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS)) {
switch (wFlag) {
case SPI_SETBEEP:
case SPI_SETMOUSE:
case SPI_SETBORDER:
case SPI_SETKEYBOARDSPEED:
case SPI_ICONHORIZONTALSPACING:
case SPI_SETSCREENSAVETIMEOUT:
case SPI_SETBLOCKSENDINPUTRESETS:
case SPI_SETSCREENSAVEACTIVE:
case SPI_SETGRIDGRANULARITY:
case SPI_SETDESKWALLPAPER:
case SPI_SETDESKPATTERN:
case SPI_SETKEYBOARDDELAY:
case SPI_ICONVERTICALSPACING:
case SPI_SETICONTITLEWRAP:
case SPI_SETMENUDROPALIGNMENT:
case SPI_SETDOUBLECLKWIDTH:
case SPI_SETDOUBLECLKHEIGHT:
case SPI_SETDOUBLECLICKTIME:
case SPI_SETMOUSEBUTTONSWAP:
case SPI_SETICONTITLELOGFONT:
case SPI_SETFASTTASKSWITCH:
case SPI_SETDRAGFULLWINDOWS:
case SPI_SETNONCLIENTMETRICS:
case SPI_SETMINIMIZEDMETRICS:
case SPI_SETICONMETRICS:
case SPI_SETWORKAREA:
case SPI_SETPENWINDOWS:
case SPI_SETHIGHCONTRAST:
case SPI_SETKEYBOARDPREF:
case SPI_SETSCREENREADER:
case SPI_SETANIMATION:
case SPI_SETFONTSMOOTHING:
case SPI_SETDRAGWIDTH:
case SPI_SETDRAGHEIGHT:
case SPI_SETHANDHELD:
case SPI_SETLOWPOWERTIMEOUT:
case SPI_SETPOWEROFFTIMEOUT:
case SPI_SETLOWPOWERACTIVE:
case SPI_SETPOWEROFFACTIVE:
case SPI_SETCURSORS:
case SPI_SETICONS:
case SPI_SETDEFAULTINPUTLANG:
case SPI_SETLANGTOGGLE:
case SPI_SETMOUSETRAILS:
case SPI_SETSCREENSAVERRUNNING:
case SPI_SETFILTERKEYS:
case SPI_SETTOGGLEKEYS:
case SPI_SETMOUSEKEYS:
case SPI_SETSHOWSOUNDS:
case SPI_SETSTICKYKEYS:
case SPI_SETACCESSTIMEOUT:
case SPI_SETSOUNDSENTRY:
case SPI_SETSNAPTODEFBUTTON:
case SPI_SETMOUSEHOVERWIDTH:
case SPI_SETMOUSEHOVERHEIGHT:
case SPI_SETMOUSEHOVERTIME:
case SPI_SETWHEELSCROLLLINES:
case SPI_SETMENUSHOWDELAY:
case SPI_SETSHOWIMEUI:
case SPI_SETMOUSESPEED:
case SPI_SETACTIVEWINDOWTRACKING:
case SPI_SETMENUANIMATION:
case SPI_SETCOMBOBOXANIMATION:
case SPI_SETLISTBOXSMOOTHSCROLLING:
case SPI_SETGRADIENTCAPTIONS:
case SPI_SETKEYBOARDCUES:
case SPI_SETACTIVEWNDTRKZORDER:
case SPI_SETHOTTRACKING:
case SPI_SETMENUFADE:
case SPI_SETSELECTIONFADE:
case SPI_SETTOOLTIPANIMATION:
case SPI_SETTOOLTIPFADE:
#ifdef MOUSE_IP
case SPI_SETMOUSESONAR:
case SPI_SETMOUSECLICKLOCK:
#endif
case SPI_SETFOREGROUNDLOCKTIMEOUT:
case SPI_SETACTIVEWNDTRKTIMEOUT:
case SPI_SETFOREGROUNDFLASHCOUNT:
case SPI_SETMOUSECLICKLOCKTIME:
case SPI_SETFOCUSBORDERWIDTH:
case SPI_SETFOCUSBORDERHEIGHT:
MSGERROR(0);
break;
}
}
try {
switch(wFlag) {
case SPI_SETDESKPATTERN:
/*
* If wParam is -1, that means read the new wallpaper from
* win.ini. If wParam is not -1, lParam points to the wallpaper
* string.
*/
if (wParam == (WPARAM)-1) {
break;
}
/*
* SetDeskPattern may take a string in lpData; if lpData
* is one of the magic values it obviously is not a string
*/
if (lpData == IntToPtr(0xFFFFFFFF) || lpData == NULL) {
/*
* These are not really magic values, but in order not to break
* apps we have to keep them valid. wParam == -1 will make
* lParam be ignored.
*/
wParam = -1;
break;
}
goto ProbeString;
case SPI_SETDESKWALLPAPER:
/*
* If the caller passed in (-1) in the wParam, then the
* wallpaper name is to be loaded later. Otherwise,
* they passed in a unicode string in the lParam.
*/
if (wParam == (WPARAM)-1) {
break;
}
if (((LPWSTR)lpData == NULL) ||
((LPWSTR)lpData == SETWALLPAPER_METRICS) ||
((LPWSTR)lpData == SETWALLPAPER_DEFAULT)) {
break;
}
ProbeString:
/*
* Probe and capture the string. Capture is necessary to
* the pointer to be passed directly to the registry routines
* which cannot cleanly handle exceptions.
*/
strData = ProbeAndReadUnicodeString((PUNICODE_STRING)lpData);
#if defined(_X86_)
ProbeForRead(strData.Buffer, strData.Length, sizeof(BYTE));
#else
ProbeForRead(strData.Buffer, strData.Length, sizeof(WCHAR));
#endif
lpData = UserAllocPoolWithQuota(strData.Length + sizeof(WCHAR), TAG_TEXT2);
if (lpData == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
pti = PtiCurrent();
ThreadLockPool(pti, lpData, &tlBuffer);
fFreeBuffer = TRUE;
RtlCopyMemory(lpData,
strData.Buffer,
strData.Length);
((PWSTR)lpData)[strData.Length / sizeof(WCHAR)] = 0;
break;
case SPI_SETBLOCKSENDINPUTRESETS:
/*
* This must be done a we must allow our value to be passed in wparam
* to be consistent with xxxUpdatePerUserSystemParameters(). If we allow
* This to fall through the default it will assert on us and the value will
* not get set properly.
*/
break;
case SPI_SETMOUSE:
ulLength = sizeof(INT) * 3;
goto ProbeRead;
case SPI_SETICONTITLELOGFONT:
if (!ARGUMENT_PRESENT(lpData))
break;
ulLength = sizeof(LOGFONTW);
goto ProbeRead;
case SPI_SETMOUSEKEYS:
ulLength = sizeof(MOUSEKEYS);
goto ProbeRead;
case SPI_SETFILTERKEYS:
ulLength = sizeof(FILTERKEYS);
goto ProbeRead;
case SPI_SETSTICKYKEYS:
ulLength = sizeof(STICKYKEYS);
goto ProbeRead;
case SPI_SETTOGGLEKEYS:
ulLength = sizeof(TOGGLEKEYS);
goto ProbeRead;
case SPI_SETSOUNDSENTRY:
ulLength = sizeof(SOUNDSENTRY);
goto ProbeRead;
case SPI_SETACCESSTIMEOUT:
ulLength = sizeof(ACCESSTIMEOUT);
goto ProbeRead;
case SPI_SETWORKAREA:
ulLength = sizeof(RECT);
goto ProbeRead;
case SPI_SETANIMATION:
ulLength = sizeof(ANIMATIONINFO);
goto ProbeRead;
case SPI_SETNONCLIENTMETRICS:
ulLength = sizeof(NONCLIENTMETRICS);
goto ProbeRead;
case SPI_SETMINIMIZEDMETRICS:
ulLength = sizeof(MINIMIZEDMETRICS);
goto ProbeRead;
case SPI_SETICONMETRICS:
ulLength = sizeof(ICONMETRICS);
goto ProbeRead;
case SPI_SETDEFAULTINPUTLANG:
ulLength = sizeof(HKL);
goto ProbeRead;
case SPI_SETHIGHCONTRAST:
CaptureBuffer.ihc = ProbeAndReadStructure((INTERNALSETHIGHCONTRAST *)lpData, INTERNALSETHIGHCONTRAST);
lpData = &CaptureBuffer.ihc;
/*
* Now probe High Contrast string -- note that we send a client-side
* buffer pointer to the routine.
*/
ProbeForReadUnicodeStringBuffer(CaptureBuffer.ihc.usDefaultScheme);
if (CaptureBuffer.ihc.usDefaultScheme.Length == 0) {
CaptureBuffer.ihc.usDefaultScheme.Buffer = NULL;
}
break;
/*
* Probe and capture the data. Capture is necessary to
* allow the pointer to be passed to the worker routines
* where exceptions cannot be cleanly handled.
*/
ProbeRead:
#if defined(_X86_)
ProbeForRead(lpData, ulLength, sizeof(BYTE));
#else
ProbeForRead(lpData, ulLength, sizeof(DWORD));
#endif
RtlCopyMemory(&CaptureBuffer, lpData, ulLength);
lpData = &CaptureBuffer;
break;
case SPI_ICONHORIZONTALSPACING: // returns INT
case SPI_ICONVERTICALSPACING: // returns INT
if (!IS_PTR(lpData))
break;
/*
* Fall through and probe the data
*/
case SPI_GETBEEP: // returns BOOL
case SPI_GETBORDER: // returns INT
case SPI_GETKEYBOARDSPEED: // returns DWORD
case SPI_GETKEYBOARDDELAY: // returns INT
case SPI_GETSCREENSAVETIMEOUT: // returns INT
case SPI_GETLOWPOWERTIMEOUT: // returns INT
case SPI_GETPOWEROFFTIMEOUT: // returns INT
case SPI_GETSCREENSAVEACTIVE: // returns BOOL
case SPI_GETBLOCKSENDINPUTRESETS: // returns BOOL
case SPI_GETLOWPOWERACTIVE: // returns BOOL
case SPI_GETPOWEROFFACTIVE: // returns BOOL
case SPI_GETGRIDGRANULARITY: // returns INT
case SPI_GETICONTITLEWRAP: // returns BOOL
case SPI_GETMENUDROPALIGNMENT: // returns BOOL
case SPI_GETFASTTASKSWITCH: // returns BOOL
case SPI_GETDRAGFULLWINDOWS: // returns INT
case SPI_GETSHOWSOUNDS: // returns BOOL
case SPI_GETFONTSMOOTHING: // returns INT
case SPI_GETSNAPTODEFBUTTON: // returns BOOL
case SPI_GETKEYBOARDPREF: // returns BOOL
case SPI_GETSCREENREADER: // returns BOOL
case SPI_GETMOUSEHOVERWIDTH:
case SPI_GETMOUSEHOVERHEIGHT:
case SPI_GETMOUSEHOVERTIME:
case SPI_GETWHEELSCROLLLINES:
case SPI_GETMENUSHOWDELAY:
case SPI_GETMOUSESPEED:
case SPI_GETMOUSETRAILS: // returns int
case SPI_GETSCREENSAVERRUNNING:
case SPI_GETSHOWIMEUI:
goto ProbeWriteUlong;
case SPI_GETDEFAULTINPUTLANG: // returns HKL
ulLength = sizeof(HKL);
goto ProbeWrite;
case SPI_GETICONTITLELOGFONT: // returns LOGFONT
ulLength = sizeof(LOGFONT);
goto ProbeWrite;
case SPI_GETMOUSE: // returns 3 INTs
ulLength = sizeof(INT) * 3;
goto ProbeWrite;
case SPI_GETFILTERKEYS: // returns FILTERKEYS
ulLength = sizeof(FILTERKEYS);
goto ProbeWrite;
case SPI_GETSTICKYKEYS: // returns STICKYKEYS
ulLength = sizeof(STICKYKEYS);
goto ProbeWrite;
case SPI_GETMOUSEKEYS: // returns MOUSEKEYS
ulLength = sizeof(MOUSEKEYS);
goto ProbeWrite;
case SPI_GETTOGGLEKEYS: // returns TOGGLEKEYS
ulLength = sizeof(TOGGLEKEYS);
goto ProbeWrite;
case SPI_GETSOUNDSENTRY: // returns SOUNDSENTRY
ulLength = sizeof(SOUNDSENTRY);
goto ProbeWrite;
case SPI_GETACCESSTIMEOUT: // returns ACCESSTIMEOUT
ulLength = sizeof(ACCESSTIMEOUT);
goto ProbeWrite;
case SPI_GETANIMATION: // returns ANIMATIONINFO
ulLength = sizeof(ANIMATIONINFO);
goto ProbeWrite;
case SPI_GETNONCLIENTMETRICS: // returns NONCLIENTMETRICS
ulLength = sizeof(NONCLIENTMETRICS);
goto ProbeWrite;
case SPI_GETMINIMIZEDMETRICS: // returns MINIMIZEDMETRICS
ulLength = sizeof(MINIMIZEDMETRICS);
goto ProbeWrite;
case SPI_GETICONMETRICS: // returns ICONMETRICS
ulLength = sizeof(ICONMETRICS);
goto ProbeWrite;
case SPI_GETHIGHCONTRAST: // returns HIGHCONTRAST
ulLength = sizeof(HIGHCONTRASTW);
ProbeForWrite(lpData, ulLength, DATAALIGN);
lpDataSave = lpData;
CaptureBuffer.hc = *((LPHIGHCONTRAST)lpData);
lpData = &CaptureBuffer.hc;
/*
* now probe string address
*/
ulLength2 = MAX_SCHEME_NAME_SIZE * sizeof(WCHAR);
ProbeForWrite(((LPHIGHCONTRAST)lpData)->lpszDefaultScheme, ulLength2, CHARALIGN);
fWrite = TRUE;
break;
case SPI_GETWORKAREA: // returns RECT
ulLength = sizeof(RECT);
goto ProbeWrite;
case SPI_GETDESKWALLPAPER:
lpDataSave = lpData;
lpData = CaptureBuffer.szTemp;
ProbeForWriteBuffer((PWSTR)lpDataSave, wParam, CHARALIGN);
wParam = (wParam < MAX_PATH) ? wParam : MAX_PATH;
ulLength = wParam * sizeof(WCHAR);
fWrite = TRUE;
break;
default:
if (wFlag < SPI_MAX) {
break;
} else if (!UPIsBOOLRange(wFlag)
&& !UPIsDWORDRange(wFlag)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserSystemParametersInfo: Invalid SPI_:%#lx", wFlag);
MSGERRORCLEANUP(0);
}
/*
* Let's enforce this or this parameter is gone for good.
*/
if (wParam != 0) {
/*
* Too late, Winstone98 is alreay using it (incorrectly).
* Bummer, this has never been shipped and it's hacked already
* Allow a special case to go through
*/
if (LOWORD((PtiCurrent()->dwExpWinVer) > VER40)
|| (wFlag != SPI_SETUIEFFECTS)
|| (wParam != 1)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserSystemParametersInfo: uiParam must be zero for SPI %#lx", wFlag);
MSGERRORCLEANUP(0);
}
}
UserAssert(wFlag & SPIF_RANGETYPEMASK);
if (wFlag & SPIF_SET) {
/*
* If your dword data needs to be validated (i.e, range, value),
* switch here on wFlag and do it here
*/
switch (wFlag) {
case SPI_SETFOREGROUNDLOCKTIMEOUT:
if (!CanForceForeground(PpiCurrent() FG_HOOKLOCK_PARAM(PtiCurrent()))) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "");
MSGERRORCLEANUP(0);
}
break;
case SPI_SETFONTSMOOTHINGTYPE:
if (PtrToInt(lpData) & ~FE_FONTSMOOTHINGTYPE_VALID) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "");
MSGERRORCLEANUP(0);
}
break;
case SPI_SETFONTSMOOTHINGORIENTATION:
if (PtrToInt(lpData) & ~FE_FONTSMOOTHINGORIENTATION_VALID) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "");
MSGERRORCLEANUP(0);
}
break;
}
} else {
ProbeWriteUlong:
ulLength = sizeof(ULONG);
lpDataSave = lpData;
lpData = &CaptureBuffer;
ProbeForWriteUlong((PULONG)lpDataSave);
fWrite = TRUE;
}
break;
/*
* Probe the data. wParam contains the length.
*/
ProbeWrite:
lpDataSave = lpData;
lpData = &CaptureBuffer;
ProbeForWrite(lpDataSave, ulLength, DATAALIGN);
fWrite = TRUE;
/*
* Copy the first DWORD of the buffer. This will make sure that
* the cbSize parameter of some structures gets copied.
*/
UserAssert(ulLength >= sizeof(DWORD));
*(LPDWORD)lpData=*(LPDWORD)lpDataSave;
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = xxxSystemParametersInfo(wFlag, wParam, lpData, flags);
/*
* Copy out any data we need to.
*/
if (fWrite) {
try {
RtlCopyMemory(lpDataSave, lpData, ulLength);
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
}
CLEANUPRECV();
if (fFreeBuffer)
ThreadUnlockAndFreePool(pti, &tlBuffer);
TRACE("NtUserSystemParametersInfo");
ENDRECV();
}
BOOL NtUserUpdatePerUserSystemParameters(
IN HANDLE hToken,
IN DWORD dwFlags)
{
BEGINRECV(BOOL, FALSE);
UNREFERENCED_PARAMETER(hToken);
retval = xxxUpdatePerUserSystemParameters(dwFlags);
TRACE("NtUserUpdatePerUserSystemParameters");
ENDRECV();
}
DWORD NtUserDdeInitialize( // API DdeInitializeA/W
OUT PHANDLE phInst,
OUT HWND *phwnd,
OUT LPDWORD pMonFlags,
IN DWORD afCmd,
IN PVOID pcii)
{
HANDLE hInst;
HWND hwnd;
DWORD MonFlags;
BEGINRECV(DWORD, DMLERR_INVALIDPARAMETER);
/*
* NOTE -- pcii is a value that is passed back to the client side
* for event callbacks. It is not probed because it is not used
* on the kernel side.
*/
retval = xxxCsDdeInitialize(&hInst, &hwnd,
&MonFlags, afCmd, pcii);
/*
* Probe arguments. pcii is not dereferenced in the kernel so probing
* is not needed.
*/
if (retval == DMLERR_NO_ERROR) {
try {
ProbeAndWriteHandle(phInst, hInst);
ProbeAndWriteHandle((PHANDLE)phwnd, hwnd);
ProbeAndWriteUlong(pMonFlags, MonFlags);
} except (StubExceptionHandler(TRUE)) {
xxxDestroyThreadDDEObject(PtiCurrent(), HtoP(hInst));
MSGERROR(0);
}
}
TRACE("NtUserDdeInitialize");
ENDRECV();
}
DWORD NtUserUpdateInstance( // private, but pMonFlags from API DdeInitializeA/W
IN HANDLE hInst,
OUT LPDWORD pMonFlags,
IN DWORD afCmd)
{
DWORD MonFlags;
BEGINRECV(DWORD, DMLERR_INVALIDPARAMETER);
/*
* Probe arguments
*/
try {
ProbeForWriteUlong(pMonFlags);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = _CsUpdateInstance(hInst, &MonFlags, afCmd);
try {
*pMonFlags = MonFlags;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserUpdateInstance");
ENDRECV();
}
DWORD NtUserEvent( // private
IN PEVENT_PACKET pep)
{
WORD cbEventData;
BEGINRECV(DWORD, 0);
/*
* Probe arguments
*/
try {
ProbeForRead(pep, sizeof(*pep), DATAALIGN);
/*
* capture so that another thread can't change it after the probe.
*/
cbEventData = pep->cbEventData;
ProbeForRead(&pep->Data, cbEventData, DATAALIGN);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* The buffer is captured within a try/except in xxxCsEvent.
*/
retval = xxxCsEvent((PEVENT_PACKET)pep, cbEventData);
TRACE("NtUserEvent");
ENDRECV();
}
BOOL NtUserFillWindow(
IN HWND hwndBrush,
IN HWND hwndPaint,
IN HDC hdc,
IN HBRUSH hbr)
{
PWND pwndBrush;
TL tlpwndBrush;
BEGINRECV_HWNDLOCK(DWORD, 0, hwndPaint);
if (hdc == NULL)
MSGERROR(0);
ValidateHWNDOPT(pwndBrush, hwndBrush);
ThreadLockWithPti(ptiCurrent, pwndBrush, &tlpwndBrush);
retval = xxxFillWindow(
pwndBrush,
pwnd,
hdc,
hbr);
ThreadUnlock(&tlpwndBrush);
TRACE("NtUserFillWindow");
ENDRECV_HWNDLOCK();
}
PCLS NtUserGetWOWClass( // wow
IN HINSTANCE hInstance,
IN PUNICODE_STRING pString)
{
UNICODE_STRING strClassName;
BEGINRECV_SHARED(PCLS, NULL);
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pString);
ProbeForReadUnicodeStringBuffer(strClassName);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = _GetWOWClass(
hInstance,
strClassName.Buffer);
TRACE("NtUserGetWOWClass");
ENDRECV_SHARED();
}
UINT NtUserGetInternalWindowPos( // private
IN HWND hwnd,
OUT LPRECT lpRect OPTIONAL,
OUT LPPOINT lpPoint OPTIONAL)
{
WINDOWPLACEMENT wp;
BEGINRECV_HWND_SHARED(DWORD, 0, hwnd);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(lpRect)) {
ProbeForWriteRect(lpRect);
}
if (ARGUMENT_PRESENT(lpPoint)) {
ProbeForWritePoint(lpPoint);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
wp.length = sizeof(WINDOWPLACEMENT);
_GetWindowPlacement(pwnd, &wp);
retval = wp.showCmd;
try {
if (ARGUMENT_PRESENT(lpRect)) {
RtlCopyMemory(lpRect, &wp.rcNormalPosition, sizeof(RECT));
}
if (ARGUMENT_PRESENT(lpPoint)) {
RtlCopyMemory(lpPoint, &wp.ptMinPosition, sizeof(POINT));
}
} except (StubExceptionHandler(FALSE)) {
}
TRACE("NtUserGetInternalWindowPos");
ENDRECV_HWND_SHARED();
}
NTSTATUS NtUserInitTask( // wow
IN UINT dwExpWinVer,
IN DWORD dwAppCompatFlags,
IN DWORD dwUserWOWCompatFlags,
IN PUNICODE_STRING pstrModName,
IN PUNICODE_STRING pstrBaseFileName,
IN DWORD hTaskWow,
IN DWORD dwHotkey,
IN DWORD idTask,
IN DWORD dwX,
IN DWORD dwY,
IN DWORD dwXSize,
IN DWORD dwYSize)
{
UNICODE_STRING strModName;
UNICODE_STRING strBaseFileName;
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* Make sure this is really a WOW process.
*/
if (PpiCurrent()->pwpi == NULL) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
strModName = ProbeAndReadUnicodeString(pstrModName);
/*
* pstrModName->Buffer has a UNICODE_NULL that's not counted in
* the length, but we want to include it for convenience. The
* probe routine does this.
*/
ProbeForReadUnicodeStringBuffer(strModName);
if (pstrBaseFileName) {
strBaseFileName = ProbeAndReadUnicodeString(pstrBaseFileName);
ProbeForReadUnicodeStringBuffer(strBaseFileName);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = zzzInitTask(
dwExpWinVer,
dwAppCompatFlags,
dwUserWOWCompatFlags,
&strModName,
pstrBaseFileName ? &strBaseFileName : NULL,
hTaskWow,
dwHotkey,
idTask,
dwX,
dwY,
dwXSize,
dwYSize);
TRACE("NtUserInitTask");
ENDRECV();
}
BOOL NtUserPostThreadMessage(
IN DWORD id,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PTHREADINFO ptiCurrent, pti;
BEGINRECV(BOOL, FALSE);
/*
* Prevent apps from setting hi 16 bits so we can use them internally.
*/
if (msg & MSGFLAG_MASK) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid message");
MSGERROR(0);
}
pti = PtiFromThreadId(id);
if (pti == NULL) {
struct tagWOWPROCESSINFO *pwpi;
PTDB ptdb;
for (pwpi=gpwpiFirstWow; pwpi; pwpi=pwpi->pwpiNext) {
for (ptdb=pwpi->ptdbHead; ptdb; ptdb=ptdb->ptdbNext) {
if (ptdb->hTaskWow == id) {
pti=ptdb->pti;
goto PTM_DoIt;
}
}
}
RIPERR0(ERROR_INVALID_THREAD_ID, RIP_VERBOSE, "");
MSGERROR(0);
}
PTM_DoIt:
/*
* Should be OK if any of the following are true
* threads are running on the same desktop
* request is on behalf of a system process
* this process owns the desktop the thread is running in
* the LUIDs match
*/
ptiCurrent = PtiCurrent();
if ( !(ptiCurrent->rpdesk == pti->rpdesk) &&
!(ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) &&
!(GetDesktopView(ptiCurrent->ppi, pti->rpdesk))) {
LUID luidCurrent, luidTo;
if (!NT_SUCCESS(GetProcessLuid(ptiCurrent->pEThread, &luidCurrent)) ||
!NT_SUCCESS(GetProcessLuid(pti->pEThread, &luidTo)) ||
!RtlEqualLuid(&luidCurrent, &luidTo)) {
RIPERR3(ERROR_INVALID_THREAD_ID,
RIP_WARNING,
"NtUserPostThreadMessage failed LUID check: msg(%lx), t1(%#p) -> t2(%#p)",
msg, ptiCurrent, pti);
MSGERROR(0);
}
}
retval = _PostThreadMessage(
pti,
msg,
wParam,
lParam);
TRACE("NtUserPostThreadMessage");
ENDRECV();
}
BOOL NtUserRegisterTasklist(
IN HWND hwnd)
{
BEGINRECV_HWND(DWORD, 0, hwnd);
retval = _RegisterTasklist(
pwnd);
TRACE("NtUserRegisterTasklist");
ENDRECV_HWND();
}
BOOL NtUserCloseClipboard(
VOID)
{
BEGINRECV(BOOL, FALSE);
retval = xxxCloseClipboard(NULL);
TRACE("NtUserCloseClipboard");
ENDRECV();
}
BOOL NtUserEmptyClipboard(
VOID)
{
BEGINRECV(BOOL, FALSE);
retval = xxxEmptyClipboard(NULL);
TRACE("NtUserEmptyClipboard");
ENDRECV();
}
BOOL NtUserSetClipboardData( // API SetClipboardData
IN UINT fmt,
IN HANDLE hData,
IN PSETCLIPBDATA pscd)
{
SETCLIPBDATA scd;
BEGINRECV(BOOL, FALSE);
/*
* Check for jobs with JOB_OBJECT_UILIMIT_WRITECLIPBOARD
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_WRITECLIPBOARD)) {
RIPMSG0(RIP_WARNING, "NtUserSetClipboardData failed for restricted thread");
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
scd = ProbeAndReadSetClipBData(pscd);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _SetClipboardData(
fmt,
hData,
scd.fGlobalHandle,
scd.fIncSerialNumber);
TRACE("NtUserSetClipboardData");
ENDRECV();
}
HANDLE NtUserConvertMemHandle( // worker routine, lpData not from API
IN LPBYTE lpData,
IN UINT cbData)
{
BEGINRECV(HANDLE, NULL);
/*
* Probe arguments
*/
try {
ProbeForRead(lpData, cbData, sizeof(BYTE));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* lpData is client-side.
*/
retval = _ConvertMemHandle(lpData, cbData);
TRACE("NtUserConvertMemHandle");
ENDRECV();
}
NTSTATUS NtUserCreateLocalMemHandle( // helper routine
IN HANDLE hMem,
OUT LPBYTE lpData OPTIONAL,
IN UINT cbData,
OUT PUINT lpcbNeeded OPTIONAL)
{
PCLIPDATA pClipData;
BEGINRECV(NTSTATUS, STATUS_INVALID_HANDLE);
pClipData = HMValidateHandle(hMem, TYPE_CLIPDATA);
if (pClipData == NULL)
MSGERROR(0);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(lpData)) {
ProbeForWrite(lpData, cbData, sizeof(BYTE));
}
if (ARGUMENT_PRESENT(lpcbNeeded)) {
ProbeAndWriteUlong(lpcbNeeded, pClipData->cbData);
}
if (!ARGUMENT_PRESENT(lpData) || cbData < pClipData->cbData) {
retval = STATUS_BUFFER_TOO_SMALL;
} else {
RtlCopyMemory(lpData, &pClipData->abData, pClipData->cbData);
retval = STATUS_SUCCESS;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserCreateLocalMemHandle");
ENDRECV();
}
HHOOK NtUserSetWindowsHookEx(
IN HANDLE hmod,
IN PUNICODE_STRING pstrLib OPTIONAL,
IN DWORD idThread,
IN int nFilterType,
IN PROC pfnFilterProc,
IN DWORD dwFlags)
{
PTHREADINFO ptiThread;
BEGINRECV(HHOOK, NULL);
if (idThread != 0) {
ptiThread = PtiFromThreadId(idThread);
if (ptiThread == NULL) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
MSGERROR(0);
}
} else {
ptiThread = NULL;
}
/*
* Probe pstrLib in GetHmodTableIndex().
*/
retval = (HHOOK)zzzSetWindowsHookEx(
hmod,
pstrLib,
ptiThread,
nFilterType,
pfnFilterProc,
dwFlags);
retval = PtoH((PVOID)retval);
TRACE("NtUserSetWindowsHookEx");
ENDRECV();
}
HWINEVENTHOOK NtUserSetWinEventHook(
IN DWORD eventMin,
IN DWORD eventMax,
IN HMODULE hmodWinEventProc,
IN PUNICODE_STRING pstrLib OPTIONAL,
IN WINEVENTPROC pfnWinEventProc,
IN DWORD idEventProcess,
IN DWORD idEventThread,
IN DWORD dwFlags)
{
BEGINRECV(HWINEVENTHOOK, NULL);
TESTFLAGS(dwFlags, WINEVENT_VALID);
/*
* Probe pstrLib in GetHmodTableIndex().
*/
retval = (HWINEVENTHOOK)_SetWinEventHook(
eventMin,
eventMax,
hmodWinEventProc,
pstrLib,
pfnWinEventProc,
LongToHandle(idEventProcess),
idEventThread,
dwFlags);
retval = PtoH((PVOID)retval);
TRACE("NtUserSetWinEventHook");
ENDRECV();
}
BOOL NtUserUnhookWinEvent(
IN HWINEVENTHOOK hWinEventUnhook)
{
PEVENTHOOK peh;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWINEVENTHOOK(peh, hWinEventUnhook);
retval = _UnhookWinEvent(peh);
TRACE("NtUserUnhookWinEvent");
ENDATOMICRECV();
}
VOID NtUserNotifyWinEvent(
IN DWORD event,
IN HWND hwnd,
IN LONG idObject,
IN LONG idChild)
{
BEGINRECV_HWNDLOCK_VOID(hwnd);
xxxWindowEvent(event, pwnd, idObject, idChild, WEF_USEPWNDTHREAD);
TRACEVOID("NtUserNotifyWinEvent");
ENDRECV_HWNDLOCK_VOID();
}
BOOL NtUserRegisterUserApiHook(
IN PUNICODE_STRING pstrLib,
IN ULONG_PTR offPfnInitUserApiHook)
{
BEGINATOMICRECV(BOOL, FALSE);
/*
* Probe pstrLib in GetHmodTableIndex().
*/
retval = _RegisterUserApiHook(
pstrLib,
offPfnInitUserApiHook);
TRACE("NtUserRegisterUserApiHook");
ENDATOMICRECV();
}
BOOL NtUserUnregisterUserApiHook(VOID)
{
BEGINATOMICRECV(BOOL, FALSE);
retval = _UnregisterUserApiHook();
TRACE("NtUserUnregisterUserApiHook");
ENDATOMICRECV();
}
BOOL NtUserGetGUIThreadInfo( // API GetGUIThreadInfo
IN DWORD idThread,
IN OUT PGUITHREADINFO pgui)
{
PTHREADINFO ptiThread;
GUITHREADINFO gui;
BEGINRECV_SHARED(BOOL, FALSE);
if (idThread) {
ptiThread = PtiFromThreadId(idThread);
if (ptiThread == NULL) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "Bad thread id");
MSGERROR(0);
}
} else {
ptiThread = NULL;
}
/*
* Probe arguments and copy results
* C2: test pti & current thread on same desktop within _GetGUIThreadInfo
*/
try {
ProbeForWrite(pgui, sizeof(*pgui), DATAALIGN);
gui.cbSize = pgui->cbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _GetGUIThreadInfo(ptiThread, &gui);
if (retval) {
try {
*pgui = gui;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetGUIThreadInfo");
ENDRECV_SHARED();
}
/*****************************************************************************\
* GetTitleBarInfo
*
* Gets information about the title bar
\*****************************************************************************/
BOOL NtUserGetTitleBarInfo(IN HWND hwnd, IN OUT PTITLEBARINFO ptbi)
{
TITLEBARINFO tbi;
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
/*
* Probe arguments and copy out results
*/
try {
ProbeForWrite(ptbi, sizeof(*ptbi), DATAALIGN);
tbi.cbSize = ptbi->cbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Get the titlebar info
*/
retval = xxxGetTitleBarInfo(pwnd, &tbi);
if (retval) {
try {
*ptbi = tbi;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetTitleBarInfo");
ENDRECV_HWNDLOCK();
}
/*****************************************************************************\
* NtUserGetComboBoxInfo
*
* Gets information about the combo box
\*****************************************************************************/
BOOL NtUserGetComboBoxInfo(IN HWND hwnd, IN OUT PCOMBOBOXINFO pcbi)
{
COMBOBOXINFO cbi;
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
/*
* Probe arguments and copy out results
*/
try {
ProbeForWrite(pcbi, sizeof(*pcbi), DATAALIGN);
cbi.cbSize = pcbi->cbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Get the combobox info
*/
retval = xxxGetComboBoxInfo(pwnd, &cbi);
if (retval) {
try {
*pcbi = cbi;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetComboBoxInfo");
ENDRECV_HWNDLOCK();
}
/*****************************************************************************\
* NtUserGetListBoxInfo
*
* Gets information about the list box
\*****************************************************************************/
DWORD NtUserGetListBoxInfo(IN HWND hwnd)
{
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
/*
* Get the listbox info
*/
retval = xxxGetListBoxInfo(pwnd);
TRACE("NtUserGetListBoxInfo");
ENDRECV_HWNDLOCK();
}
/*****************************************************************************\
* GetCursorInfo
*
* Gets information about the global cursor
\*****************************************************************************/
BOOL NtUserGetCursorInfo(IN OUT PCURSORINFO pci)
{
CURSORINFO ci = {0};
BEGINRECV_SHARED(BOOL, FALSE);
ci.ptScreenPos = gpsi->ptCursor;
ci.flags = 0;
if (gpcurPhysCurrent)
ci.flags |= CURSOR_SHOWING;
/*
* Get the current LOGICAL cursor (the one apps actually see from LoadCursor())
*/
ci.hCursor = (HCURSOR)PtoH(gpcurLogCurrent);
retval = TRUE;
/*
* Probe arguments and copy out result
*/
try {
ProbeForWrite(pci, sizeof(*pci), DATAALIGN);
if (pci->cbSize != sizeof(CURSORINFO)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "CURSORINFO.cbSize %d is wrong", pci->cbSize);
retval = FALSE;
} else {
*pci = ci;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetCursorInfo");
ENDRECV_SHARED();
}
/*****************************************************************************\
* GetScrollBarInfo
*
* Gets information about the scroll bar
\*****************************************************************************/
BOOL NtUserGetScrollBarInfo(IN HWND hwnd, IN LONG idObject, IN OUT PSCROLLBARINFO psbi)
{
SCROLLBARINFO sbi;
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
/*
* Probe arguments and copy out results
*/
try {
ProbeForWrite(psbi, sizeof(*psbi), DATAALIGN);
sbi.cbSize = psbi->cbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Get the scrollbar info
*/
retval = xxxGetScrollBarInfo(pwnd, idObject, &sbi);
if (retval) {
try {
*psbi = sbi;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetScrollBarInfo");
ENDRECV_HWNDLOCK();
}
HWND NtUserGetAncestor(IN HWND hwndChild, IN UINT gaFlags)
{
BEGINRECV_HWND_SHARED(HWND, NULL, hwndChild);
if ((gaFlags < GA_MIN) || (gaFlags > GA_MAX)) {
RIPERR3(ERROR_INVALID_PARAMETER, RIP_WARNING,
"NtUserGetAncestor: Invalid gaFlags parameter %d, not %d - %d",
gaFlags, GA_MIN, GA_MAX);
MSGERROR(0);
}
retval = (HWND)_GetAncestor(pwnd, gaFlags);
retval = PtoH((PVOID)retval);
TRACE("NtUserGetAncestor");
ENDRECV_HWND_SHARED();
}
HWND NtUserRealChildWindowFromPoint(IN HWND hwndParent, IN POINT pt)
{
BEGINRECV_HWND_SHARED(HWND, NULL, hwndParent);
retval = (HWND)_RealChildWindowFromPoint(pwnd, pt);
retval = PtoH((PVOID)retval);
TRACE("NtUserRealChildWindowFromPoint");
ENDRECV_HWND_SHARED();
}
BOOL NtUserGetAltTabInfo(
IN HWND hwnd,
IN int iItem,
IN OUT PALTTABINFO pati,
OUT LPWSTR lpszItemText,
IN UINT cchItemText OPTIONAL,
BOOL bAnsi)
{
ALTTABINFO ati;
BEGINRECV_HWNDOPT_SHARED(BOOL, FALSE, hwnd);
/*
* If the specified window is not a switch window, then fail the call.
* It's a dumb API we got from Windows 95, I am hereby allowing NULL hwnd.
*/
if (pwnd && (pwnd != gspwndAltTab)) {
MSGERROR(ERROR_INVALID_WINDOW_HANDLE);
}
/*
* Probe arguments
*/
try {
ProbeForWrite(pati, sizeof(*pati), DATAALIGN);
if (bAnsi) {
ProbeForWriteBuffer((LPSTR)lpszItemText, cchItemText, CHARALIGN);
} else {
ProbeForWriteBuffer(lpszItemText, cchItemText, CHARALIGN);
}
/*
* Validate AltTabInfo structure
*/
if (pati->cbSize != sizeof(ALTTABINFO)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "ALTTABINFO.cbSize %d is wrong", pati->cbSize);
MSGERROR(0);
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Get the alt tab info
*/
ati.cbSize = sizeof(ALTTABINFO);
retval = _GetAltTabInfo(iItem, &ati, lpszItemText, cchItemText, bAnsi);
if (retval) {
try {
*pati = ati;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetAltTabInfo");
ENDRECV_HWNDOPT_SHARED();
}
BOOL NtUserGetMenuBarInfo(
IN HWND hwnd,
IN long idObject,
IN long idItem,
IN OUT PMENUBARINFO pmbi)
{
MENUBARINFO mbi;
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
try {
#if defined(_X86_)
ProbeForWrite(pmbi, sizeof(*pmbi), sizeof(BYTE));
#else
ProbeForWrite(pmbi, sizeof(*pmbi), sizeof(DWORD));
#endif
mbi.cbSize = pmbi->cbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Get the menubar info
*/
retval = xxxGetMenuBarInfo(pwnd, idObject, idItem, &mbi);
if (retval) {
try {
*pmbi = mbi;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetMenuBarInfo");
ENDRECV_HWNDLOCK();
}
BOOL NtUserSetInternalWindowPos( // private SetInternalWindowPos
IN HWND hwnd,
IN UINT cmdShow,
IN CONST RECT *lpRect,
IN CONST POINT *lpPoint)
{
RECT rc;
POINT pt;
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
try {
rc = ProbeAndReadRect(lpRect);
pt = ProbeAndReadPoint(lpPoint);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxSetInternalWindowPos(
pwndND,
cmdShow,
&rc,
&pt);
TRACE("NtUserSetInternalWindowPos");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserChangeClipboardChain(
IN HWND hwndRemove,
IN HWND hwndNewNext)
{
PWND pwndNewNext;
TL tlpwndNewNext;
BEGINRECV_HWNDLOCK(DWORD, 0, hwndRemove);
ValidateHWNDOPT(pwndNewNext, hwndNewNext);
ThreadLockWithPti(ptiCurrent, pwndNewNext, &tlpwndNewNext);
retval = xxxChangeClipboardChain(
pwnd,
pwndNewNext);
ThreadUnlock(&tlpwndNewNext);
TRACE("NtUserChangeClipboardChain");
ENDRECV_HWNDLOCK();
}
DWORD NtUserCheckMenuItem(
IN HMENU hmenu,
IN UINT wIDCheckItem,
IN UINT wCheck)
{
PMENU pmenu;
BEGINATOMICRECV(DWORD, (DWORD)-1);
TESTFLAGS(wCheck, MF_VALID);
ValidateHMENUMODIFY(pmenu, hmenu);
retval = _CheckMenuItem(
pmenu,
wIDCheckItem,
wCheck);
TRACE("NtUserCheckMenuItem");
ENDATOMICRECV();
}
HWND NtUserChildWindowFromPointEx(
IN HWND hwndParent,
IN POINT point,
IN UINT flags)
{
BEGINRECV_HWND(HWND, NULL, hwndParent);
retval = (HWND)_ChildWindowFromPointEx(pwnd, point, flags);
retval = PtoH((PVOID)retval);
TRACE("NtUserChildWindowFromPointEx");
ENDRECV_HWND();
}
BOOL NtUserClipCursor( // API ClipCursor
IN CONST RECT *lpRect OPTIONAL)
{
RECT rc;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lpRect)) {
try {
rc = ProbeAndReadRect(lpRect);
lpRect = &rc;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
retval = zzzClipCursor(lpRect);
TRACE("NtUserClipCursor");
ENDRECV();
}
HACCEL NtUserCreateAcceleratorTable( // API CreateAcceleratorTableA/W
IN LPACCEL paccel,
IN INT cAccel)
{
BEGINRECV(HACCEL, NULL);
if (cAccel <= 0) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
ProbeForReadBuffer(paccel, cAccel, DATAALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = (HACCEL)_CreateAcceleratorTable(
paccel,
cAccel * sizeof(ACCEL));
retval = PtoH((PVOID)retval);
TRACE("NtUserCreateAcceleratorTable");
ENDRECV();
}
BOOL NtUserDeleteMenu(
IN HMENU hmenu,
IN UINT nPosition,
IN UINT dwFlags)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV(BOOL, FALSE);
TESTFLAGS(dwFlags, MF_VALID);
ValidateHMENUMODIFYCHECKLOCK(pmenu, hmenu);
ThreadLock(pmenu, &tlpMenu);
retval = xxxDeleteMenu(
pmenu,
nPosition,
dwFlags);
ThreadUnlock(&tlpMenu);
TRACE("NtUserDeleteMenu");
ENDRECV();
}
BOOL NtUserDestroyAcceleratorTable(
IN HACCEL hAccel)
{
LPACCELTABLE pat;
BEGINRECV(BOOL, FALSE);
ValidateHACCEL(pat, hAccel);
/*
* Mark the object for destruction - if it says it's ok to free,
* then free it.
*/
if (HMMarkObjectDestroy(pat)) {
HMFreeObject(pat);
}
retval = TRUE;
TRACE("NtUserDestroyAcceleratorTable");
ENDRECV();
}
BOOL NtUserDestroyCursor(
IN HCURSOR hcurs,
IN DWORD cmd)
{
PCURSOR pcurs;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHCURSOR(pcurs, hcurs);
retval = _DestroyCursor(pcurs, cmd);
TRACE("NtUserDestroyCursor");
ENDATOMICRECV();
}
HANDLE NtUserGetClipboardData( // API GetClipboardData
IN UINT fmt,
OUT PGETCLIPBDATA pgcd)
{
PTHREADINFO ptiCurrent;
TL tlpwinsta;
PWINDOWSTATION pwinsta;
GETCLIPBDATA gcd;
BEGINRECV(HANDLE, NULL);
ptiCurrent = PtiCurrent();
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
/*
* Check for jobs with JOB_OBJECT_UILIMIT_READCLIPBOARD
*/
if (IS_THREAD_RESTRICTED(ptiCurrent, JOB_OBJECT_UILIMIT_READCLIPBOARD)) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "NtUserGetClipboardData failed for restricted thread");
MSGERROR(0);
}
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
/*
* Start out assuming the format requested
* will be the format returned.
*/
gcd.uFmtRet = fmt;
retval = xxxGetClipboardData(pwinsta, fmt, &gcd);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure(pgcd, gcd, GETCLIPBDATA);
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
CLEANUPRECV();
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
TRACE("NtUserGetClipboardData");
ENDRECV();
}
BOOL NtUserDestroyMenu(
IN HMENU hmenu)
{
PMENU pmenu;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHMENUMODIFY(pmenu, hmenu);
retval = _DestroyMenu(pmenu);
TRACE("NtUserDestroyMenu");
ENDATOMICRECV();
}
BOOL NtUserDestroyWindow(
IN HWND hwnd)
{
BEGINRECV_HWND(DWORD, 0, hwnd);
retval = xxxDestroyWindow(pwnd);
TRACE("NtUserDestroyWindow");
ENDRECV_HWND();
}
LRESULT NtUserDispatchMessage( // API DispatchMessageA/W
IN CONST MSG *pmsg)
{
MSG msg;
BEGINRECV(LRESULT, 0);
/*
* Probe arguments
*/
try {
msg = ProbeAndReadMessage(pmsg);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxDispatchMessage(&msg);
TRACE("NtUserDispatchMessage");
ENDRECV();
}
BOOL NtUserEnableMenuItem(
IN HMENU hMenu,
IN UINT wIDEnableItem,
IN UINT wEnable)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV(BOOL, -1);
TESTFLAGS(wEnable, MF_VALID);
ValidateHMENUMODIFY(pmenu, hMenu);
ThreadLockAlways(pmenu, &tlpMenu);
retval = xxxEnableMenuItem(
pmenu,
wIDEnableItem,
wEnable);
ThreadUnlock(&tlpMenu);
TRACE("NtUserEnableMenuItem");
ENDRECV();
}
BOOL NtUserAttachThreadInput(
IN DWORD idAttach,
IN DWORD idAttachTo,
IN BOOL fAttach)
{
PTHREADINFO ptiAttach;
PTHREADINFO ptiAttachTo;
BEGINRECV(BOOL, FALSE);
/*
* Always must attach or detach from a real thread id.
*/
if ((ptiAttach = PtiFromThreadId(idAttach)) == NULL) {
MSGERROR(0);
}
if ((ptiAttachTo = PtiFromThreadId(idAttachTo)) == NULL) {
MSGERROR(0);
}
retval = zzzAttachThreadInput(
ptiAttach,
ptiAttachTo,
fAttach);
TRACE("NtUserAttachThreadInput");
ENDRECV();
}
BOOL NtUserGetWindowPlacement( // API GetWindowPlacement
IN HWND hwnd,
OUT PWINDOWPLACEMENT pwp)
{
WINDOWPLACEMENT wp;
BEGINRECV_HWND(DWORD, 0, hwnd);
/*
* Probe arguments
*/
try {
ProbeForWriteWindowPlacement(pwp);
wp.length = pwp->length;
#ifdef LATER
if (pwp->length != sizeof(WINDOWPLACEMENT)) {
if (TestWF(pwnd, WFWIN40COMPAT)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "GetWindowPlacement: invalid length %lX", pwp->length);
MSGERROR(0);
} else {
RIPMSG1(RIP_WARNING, "GetWindowPlacement: invalid length %lX", pwp->length);
pwp->length = sizeof(WINDOWPLACEMENT);
}
}
#endif
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _GetWindowPlacement(pwnd, &wp);
try {
RtlCopyMemory(pwp, &wp, sizeof(WINDOWPLACEMENT));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetWindowPlacement");
ENDRECV_HWND();
}
BOOL NtUserSetWindowPlacement( // API SetWindowPlacement
IN HWND hwnd,
IN CONST WINDOWPLACEMENT *pwp)
{
WINDOWPLACEMENT wp;
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
try {
wp = ProbeAndReadWindowPlacement(pwp);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (wp.length != sizeof(WINDOWPLACEMENT)) {
if (Is400Compat(ptiCurrent->dwExpWinVer)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "SetWindowPlacement: invalid length %lX", pwp->length);
MSGERROR(0);
} else {
RIPMSG1(RIP_WARNING, "SetWindowPlacement: invalid length %lX", pwp->length);
}
}
retval = xxxSetWindowPlacement(pwndND, &wp);
TRACE("NtUserSetWindowPlacement");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserLockWindowUpdate( // API LockWindowUpdate
IN HWND hwnd)
{
PWND pwnd;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
retval = LockWindowUpdate2(pwnd, FALSE);
TRACE("NtUserLockWindowUpdate");
ENDATOMICRECV();
}
BOOL NtUserGetClipCursor( // API GetClipCursor
OUT LPRECT lpRect)
{
/*
* Check if the caller has the proper access rights: if not, this will
* SetLastError to ERROR_ACCESS_DENIED and return FALSE. Do this *before*
* BEGINRECV_SHARED, else we must use MSGERROR to release the critsect!
*/
RETURN_IF_ACCESS_DENIED(PpiCurrent()->amwinsta,
WINSTA_READATTRIBUTES,
FALSE);
{
BEGINRECV_SHARED(BOOL, FALSE);
/*
* Probe arguments
*/
try {
ProbeForWriteRect(lpRect);
*lpRect = grcCursorClip;
retval = TRUE;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetClipCursor");
ENDRECV_SHARED();
}
}
BOOL NtUserEnableScrollBar(
IN HWND hwnd,
IN UINT wSBflags,
IN UINT wArrows)
{
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
LIMITVALUE(wSBflags, SB_MAX, "EnableScrollBar");
retval = xxxEnableScrollBar(
pwndND,
wSBflags,
wArrows);
TRACE("NtUserEnableScrollBar");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserDdeSetQualityOfService( // API DdeSetQualityOfService
IN HWND hwndClient,
IN CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev OPTIONAL)
{
SECURITY_QUALITY_OF_SERVICE qosNew, qosPrev;
BEGINRECV_HWND(BOOL, FALSE, hwndClient);
if (GETPTI(pwnd) != PtiCurrent()) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
qosNew = ProbeAndReadStructure(pqosNew, SECURITY_QUALITY_OF_SERVICE);
if (ARGUMENT_PRESENT(pqosPrev))
ProbeForWrite(pqosPrev, sizeof(*pqosPrev), sizeof(DWORD));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _DdeSetQualityOfService(
pwnd,
&qosNew,
&qosPrev);
try {
if (ARGUMENT_PRESENT(pqosPrev))
*pqosPrev = qosPrev;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserDdeSetQualityOfService");
ENDRECV_HWND();
}
BOOL NtUserDdeGetQualityOfService( // private DdeGetQualityOfService
IN HWND hwndClient,
IN HWND hwndServer,
OUT PSECURITY_QUALITY_OF_SERVICE pqos)
{
PWND pwndServer;
PTHREADINFO ptiCurrent;
SECURITY_QUALITY_OF_SERVICE qos;
BEGINATOMICRECV_HWND(BOOL, FALSE, hwndClient);
ValidateHWNDOPT(pwndServer, hwndServer);
ptiCurrent = PtiCurrent();
if (GETPTI(pwnd) != ptiCurrent && pwndServer != NULL &&
GETPTI(pwndServer) != ptiCurrent) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
ProbeForWrite(pqos, sizeof(*pqos), DATAALIGN);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = _DdeGetQualityOfService(
pwnd,
pwndServer,
&qos);
try {
RtlCopyMemory(pqos, &qos, sizeof (SECURITY_QUALITY_OF_SERVICE));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserDdeGetQualityOfService");
ENDATOMICRECV_HWND();
}
DWORD NtUserGetMenuIndex(
IN HMENU hMenu,
IN HMENU hSubMenu)
{
PMENU pmenu;
PMENU psubmenu;
DWORD idx;
BEGINRECV_SHARED(DWORD, 0);
ValidateHMENU(pmenu, hMenu);
ValidateHMENU(psubmenu, hSubMenu);
retval = (DWORD)-1;
if (pmenu && psubmenu) {
for (idx=0; idx<pmenu->cItems; idx++)
if ((pmenu->rgItems[idx].spSubMenu == psubmenu)) {
retval = idx;
break;
}
}
TRACE("NtUserGetMenuIndex");
ENDRECV_SHARED();
}
#if DBG
VOID NtUserSetRipFlags(
DWORD dwRipFlags)
{
BEGINRECV_VOID();
SetRipFlags(dwRipFlags);
TRACEVOID("NtUserSetRipFlags");
ENDRECV_VOID();
}
VOID NtUserSetDbgTag(
int tag,
DWORD dwBitFlags)
{
BEGINRECV_VOID();
SetDbgTag(tag, dwBitFlags);
TRACEVOID("NtUserSetDbgTag");
ENDRECV_VOID();
}
VOID NtUserSetDbgTagCount(
DWORD dwTagCount)
{
BEGINRECV_VOID();
SetDbgTagCount(dwTagCount);
TRACEVOID("NtUserSetDbgTagCount");
ENDRECV_VOID();
}
#endif
ULONG_PTR NtUserCallNoParam(
IN DWORD xpfnProc)
{
BEGINRECV(ULONG_PTR, 0);
/*
* C4296: (...) : expression is always true/false
* The first comparison in ISXPFNPROCINRANGE is always true for
* SFI_BEGINTRANSLATENOPARAMXXX, so we explicitly disable the warning.
*/
#pragma warning(disable:4296)
VALIDATEXPFNPROC(NOPARAM);
retval = (apfnSimpleCall[xpfnProc]());
if (ISXPFNPROCINRANGE(NOPARAMANDRETURNHANDLE)) {
retval = (ULONG_PTR)PtoH((PVOID)retval);
}
#pragma warning(default:4296)
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV();
}
ULONG_PTR NtUserCallOneParam(
IN ULONG_PTR dwParam,
IN DWORD xpfnProc)
{
BEGINRECV(ULONG_PTR, 0);
VALIDATEXPFNPROC(ONEPARAM);
retval = (apfnSimpleCall[xpfnProc](dwParam));
if (ISXPFNPROCINRANGE(ONEPARAMANDRETURNHANDLE)) {
retval = (ULONG_PTR)PtoH((PVOID)retval);
}
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV();
}
ULONG_PTR NtUserCallHwnd(
IN HWND hwnd,
IN DWORD xpfnProc)
{
BEGINRECV_HWNDLOCK(ULONG_PTR, 0, hwnd);
VALIDATEXPFNPROC(HWND);
retval = (apfnSimpleCall[xpfnProc](pwnd));
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV_HWNDLOCK();
}
ULONG_PTR NtUserCallHwndLock(
IN HWND hwnd,
IN DWORD xpfnProc)
{
BEGINRECV_HWNDLOCK_COND_ND(ULONG_PTR, 0, hwnd, xpfnProc);
VALIDATEXPFNPROC(HWNDLOCK);
retval = apfnSimpleCall[xpfnProc](pwndCondND);
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV_HWNDLOCK_COND_ND();
}
ULONG_PTR NtUserCallHwndOpt(
IN HWND hwnd,
IN DWORD xpfnProc)
{
PWND pwnd;
BEGINATOMICRECV(ULONG_PTR, 0);
ValidateHWNDOPT(pwnd, hwnd);
VALIDATEXPFNPROC(HWNDOPT);
retval = (apfnSimpleCall[xpfnProc](pwnd));
TRACE(apszSimpleCallNames[xpfnProc]);
ENDATOMICRECV();
}
ULONG_PTR NtUserCallHwndParam(
IN HWND hwnd,
IN ULONG_PTR dwParam,
IN DWORD xpfnProc)
{
BEGINRECV_HWNDLOCK(ULONG_PTR, 0, hwnd);
VALIDATEXPFNPROC(HWNDPARAM);
retval = (apfnSimpleCall[xpfnProc](pwnd, dwParam));
if (ISXPFNPROCINRANGE(HWNDPARAMANDRETURNHANDLE)) {
retval = (ULONG_PTR)PtoH((PVOID)retval);
}
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV_HWNDLOCK();
}
ULONG_PTR NtUserCallHwndParamLock(
IN HWND hwnd,
IN ULONG_PTR dwParam,
IN DWORD xpfnProc)
{
BEGINRECV_HWNDLOCK_COND_ND(ULONG_PTR, 0, hwnd, xpfnProc);
VALIDATEXPFNPROC(HWNDPARAMLOCK);
retval = apfnSimpleCall[xpfnProc](pwndCondND, dwParam);
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV_HWNDLOCK_COND_ND();
}
ULONG_PTR NtUserCallTwoParam(
ULONG_PTR dwParam1,
ULONG_PTR dwParam2,
IN DWORD xpfnProc)
{
BEGINRECV(ULONG_PTR, 0);
VALIDATEXPFNPROC(TWOPARAM);
retval = (apfnSimpleCall[xpfnProc](dwParam1, dwParam2));
TRACE(apszSimpleCallNames[xpfnProc]);
ENDRECV();
}
BOOL NtUserThunkedMenuItemInfo( // worker for various menu APIs
IN HMENU hMenu,
IN UINT nPosition,
IN BOOL fByPosition,
IN BOOL fInsert,
IN LPMENUITEMINFOW lpmii,
IN PUNICODE_STRING pstrItem OPTIONAL)
{
PMENU pmenu;
MENUITEMINFO mii;
UNICODE_STRING strItem;
TL tlpMenu;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
* No need to SetLastError because lpmii is always the address of
* a local stack structure in USER code, not an application address.
*/
try {
mii = ProbeAndReadMenuItem(lpmii);
if (ARGUMENT_PRESENT(pstrItem)) {
strItem = ProbeAndReadUnicodeString(pstrItem);
ProbeForReadUnicodeStringBuffer(strItem);
} else {
RtlInitUnicodeString(&strItem, NULL);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
if (fInsert) {
ValidateHMENUMODIFYCHECKLOCK(pmenu, hMenu);
} else {
ValidateHMENUMODIFY(pmenu, hMenu);
}
ThreadLock(pmenu, &tlpMenu);
/*
* These routines only use the buffer in a try/except (actually in
* xxxSetLPITEMInfo).
*/
if (fInsert) {
retval = xxxInsertMenuItem(
pmenu,
nPosition,
fByPosition,
&mii,
&strItem);
} else {
retval = xxxSetMenuItemInfo(
pmenu,
nPosition,
fByPosition,
&mii,
&strItem);
}
ThreadUnlock(&tlpMenu);
TRACE("NtUserThunkedMenuItemInfo");
ENDRECV();
}
/***************************************************************************\
* NtUserThunkedMenuInfo
*
* History:
* 07-23-96 GerardoB - Added header & fixed up for 5.0
\***************************************************************************/
BOOL NtUserThunkedMenuInfo( // API SetMenuInfo
IN HMENU hMenu,
IN LPCMENUINFO lpmi)
{
PMENU pmenu;
MENUINFO mi;
TL tlpMenu;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
mi = ProbeAndReadMenuInfo(lpmi);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ValidateHMENUMODIFY(pmenu, hMenu);
ThreadLock(pmenu, &tlpMenu);
retval = xxxSetMenuInfo(pmenu, &mi);
ThreadUnlock(&tlpMenu);
TRACE("NtUserThunkedMenuInfo");
ENDRECV();
}
BOOL NtUserSetMenuDefaultItem(
IN HMENU hMenu,
IN UINT wID,
IN UINT fByPosition)
{
PMENU pmenu;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHMENUMODIFY(pmenu, hMenu);
retval = _SetMenuDefaultItem(
pmenu,
wID,
fByPosition);
TRACE("NtUserSetMenuDefaultItem");
ENDATOMICRECV();
}
BOOL NtUserSetMenuContextHelpId(
IN HMENU hMenu,
IN DWORD dwContextHelpId)
{
PMENU pmenu;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHMENUMODIFY(pmenu, hMenu);
retval = _SetMenuContextHelpId(
pmenu,
dwContextHelpId);
TRACE("NtUserSetMenuContextHelpId");
ENDATOMICRECV();
}
BOOL NtUserSetMenuFlagRtoL(
IN HMENU hMenu)
{
PMENU pmenu;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHMENU(pmenu, hMenu);
retval = _SetMenuFlagRtoL(pmenu);
TRACE("NtUserSetMenuFlagRtoL");
ENDATOMICRECV();
}
BOOL NtUserDrawAnimatedRects( // API DrawAnimatedRects
IN HWND hwnd,
IN int idAni,
IN CONST RECT *lprcFrom,
IN CONST RECT *lprcTo)
{
PWND pwnd;
TL tlpwnd;
RECT rcFrom;
RECT rcTo;
BEGINRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
/*
* Probe arguments
*/
try {
rcFrom = ProbeAndReadRect(lprcFrom);
rcTo = ProbeAndReadRect(lprcTo);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ThreadLock(pwnd, &tlpwnd);
retval = xxxDrawAnimatedRects(
pwnd,
idAni,
&rcFrom,
&rcTo);
ThreadUnlock(&tlpwnd);
TRACE("NtUserDrawAnimatedRects");
ENDRECV();
}
BOOL NtUserDrawCaption( // API DrawCaption
IN HWND hwnd,
IN HDC hdc,
IN CONST RECT *lprc,
IN UINT flags)
{
RECT rc;
BEGINRECV_HWNDLOCK(DWORD, FALSE, hwnd);
/*
* Probe arguments
*/
try {
rc = ProbeAndReadRect(lprc);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxDrawCaptionTemp(pwnd, hdc, &rc, NULL, NULL, NULL, flags);
TRACE("NtUserDrawCaption");
ENDRECV_HWNDLOCK();
}
BOOL NtUserPaintDesktop(
IN HDC hdc)
{
PTHREADINFO ptiCurrent;
PWND pwndDesk;
TL tlpwndDesk;
BEGINRECV(BOOL, FALSE);
ptiCurrent = PtiCurrent();
if (ptiCurrent->rpdesk != NULL) {
pwndDesk = ptiCurrent->rpdesk->pDeskInfo->spwnd;
ThreadLockWithPti(ptiCurrent, pwndDesk, &tlpwndDesk);
retval = xxxInternalPaintDesktop(pwndDesk, hdc, TRUE);
ThreadUnlock(&tlpwndDesk);
} else {
MSGERROR(0);
}
TRACE("NtUserPaintDesktop");
ENDRECV();
}
SHORT NtUserGetAsyncKeyState(
IN int vKey)
{
PTHREADINFO ptiCurrent;
BEGINRECV_SHARED(SHORT, 0);
ptiCurrent = PtiCurrentShared();
UserAssert(ptiCurrent);
/*
* Don't allow other processes to spy on other deskops or a process
* to spy on the foreground if the desktop does not allow input spying
*/
if ((ptiCurrent->rpdesk != grpdeskRitInput) ||
( ((gptiForeground == NULL) || (PpiCurrent() != gptiForeground->ppi)) &&
!RtlAreAnyAccessesGranted(ptiCurrent->amdesk, (DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD)))) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "GetAysncKeyState: not"
" foreground desktop or no desktop hooking (input spying)");
MSGERROR(0);
}
UserAssert(!(ptiCurrent->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO));
retval = _GetAsyncKeyState(vKey);
/*
* Update the client side key state cache.
*/
try {
ptiCurrent->pClientInfo->dwAsyncKeyCache = gpsi->dwAsyncKeyCache;
RtlCopyMemory(ptiCurrent->pClientInfo->afAsyncKeyState,
gafAsyncKeyState,
CBASYNCKEYCACHE);
RtlCopyMemory(ptiCurrent->pClientInfo->afAsyncKeyStateRecentDown,
gafAsyncKeyStateRecentDown,
CBASYNCKEYCACHE);
} except (StubExceptionHandler(TRUE)) {
retval = 0;
}
TRACE("NtUserGetAsyncKeyState");
ENDRECV_SHARED();
}
HBRUSH NtUserGetControlBrush(
IN HWND hwnd,
IN HDC hdc,
IN UINT msg)
{
BEGINRECV_HWNDLOCK(HBRUSH, NULL, hwnd);
if (hdc == NULL || !InMsgRange(msg, WM_CTLCOLORFIRST, WM_CTLCOLORLAST)) {
MSGERROR(0);
}
retval = xxxGetControlBrush(
pwnd,
hdc,
msg);
TRACE("NtUserGetControlBrush");
ENDRECV_HWNDLOCK();
}
HBRUSH NtUserGetControlColor(
IN HWND hwndParent,
IN HWND hwndCtl,
IN HDC hdc,
IN UINT msg)
{
PWND pwndCtl;
TL tlpwndCtl;
BEGINRECV_HWNDLOCK(HBRUSH, NULL, hwndParent);
ValidateHWND(pwndCtl, hwndCtl);
if (hdc == NULL || !InMsgRange(msg, WM_CTLCOLORFIRST, WM_CTLCOLORLAST)) {
MSGERROR(0);
}
ThreadLockAlwaysWithPti(ptiCurrent, pwndCtl, &tlpwndCtl);
retval = xxxGetControlColor(
pwnd,
pwndCtl,
hdc,
msg);
ThreadUnlock(&tlpwndCtl);
TRACE("NtUserGetControlColor");
ENDRECV_HWNDLOCK();
}
BOOL NtUserEndMenu(VOID)
{
PTHREADINFO ptiCurrent;
PWND pwnd;
BEGINRECV(BOOL, FALSE);
ptiCurrent = PtiCurrent();
/*
* The menu might be in the middle of some callback, so calling xxxEndMenu
* directly might mess things up. So we post it a message to signal it to
* go away at a good moment
*/
if (ptiCurrent->pMenuState != NULL) {
pwnd = GetMenuStateWindow(ptiCurrent->pMenuState);
if (pwnd != NULL) {
_PostMessage(pwnd, MN_ENDMENU, 0, 0);
} else {
/*
* Is this menu messed up?
*/
UserAssert(pwnd != NULL);
ptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
}
}
retval = TRUE;
TRACEVOID("NtUserEndMenu");
ENDRECV();
}
int NtUserCountClipboardFormats(
VOID)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(int, 0);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = pwinsta->cNumClipFormats;
TRACE("NtUserCountClipboardFormats");
ENDRECV_SHARED();
}
DWORD NtUserGetClipboardSequenceNumber(
VOID)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(DWORD, 0);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = pwinsta->iClipSequenceNumber;
TRACE("NtUserGetClipboardSequenceNumber");
ENDRECV_SHARED();
}
UINT NtUserGetCaretBlinkTime(VOID)
{
BEGINRECV_SHARED(UINT, 0);
/*
* Blow it off if the caller doesn't have the proper access rights. However,
* allow CSRSS to use this value internally to the server. Note that if the
* client tries to retrieve this value itself, the access check will
* function normally.
*/
if ((PpiCurrent()->Process != gpepCSRSS) &&
(!CheckGrantedAccess(PpiCurrent()->amwinsta, WINSTA_READATTRIBUTES))) {
MSGERROR(0);
}
retval = gpsi->dtCaretBlink;
TRACE("NtUserGetCaretBlinkTime");
ENDRECV_SHARED();
}
HWND NtUserGetClipboardOwner(
VOID)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(HWND, NULL);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = PtoH(pwinsta->spwndClipOwner);
TRACE("NtUserGetClipboardOwner");
ENDRECV_SHARED();
}
HWND NtUserGetClipboardViewer(
VOID)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(HWND, NULL);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = PtoH(pwinsta->spwndClipViewer);
TRACE("NtUserGetClipboardViewer");
ENDRECV_SHARED();
}
UINT NtUserGetDoubleClickTime(
VOID)
{
BEGINRECV_SHARED(UINT, 0);
/*
* Blow it off if the caller doesn't have the proper access rights. However,
* allow CSRSS to use this value internally to the server. Note that if the
* client tries to retrieve this value itself, the access check will
* function normally.
*/
if ((PpiCurrent()->Process != gpepCSRSS) &&
(!CheckGrantedAccess(PpiCurrent()->amwinsta, WINSTA_READATTRIBUTES))) {
MSGERROR(0);
}
retval = gdtDblClk;
TRACE("NtUserGetDoubleClickTime");
ENDRECV_SHARED();
}
HWND NtUserGetForegroundWindow(
VOID)
{
BEGINRECV_SHARED(HWND, NULL);
/*
* Only return a window if there is a foreground queue and the
* caller has access to the current desktop.
*/
if (gpqForeground == NULL || gpqForeground->spwndActive == NULL ||
PtiCurrentShared()->rpdesk != gpqForeground->spwndActive->head.rpdesk) {
MSGERROR(0);
}
retval = PtoHq(gpqForeground->spwndActive);
TRACE("NtUserGetForegroundWindow");
ENDRECV_SHARED();
}
HWND NtUserGetOpenClipboardWindow(
VOID)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(HWND, NULL);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = PtoH(pwinsta->spwndClipOpen);
TRACE("NtUserGetOpenClipboardWindow");
ENDRECV_SHARED();
}
int NtUserGetPriorityClipboardFormat( // API GetPriorityClipboardFormat
IN UINT *paFormatPriorityList,
IN int cFormats)
{
BEGINRECV_SHARED(int, 0);
/*
* Probe arguments
*/
try {
ProbeForReadBuffer(paFormatPriorityList, cFormats, DATAALIGN);
retval = _GetPriorityClipboardFormat(
paFormatPriorityList,
cFormats);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetPriorityClipboardFormat");
ENDRECV_SHARED();
}
HMENU NtUserGetSystemMenu(
IN HWND hwnd,
IN BOOL bRevert)
{
BEGINRECV_HWNDLOCK(HMENU, NULL, hwnd);
retval = (HMENU)xxxGetSystemMenu(pwnd, bRevert);
retval = PtoH((PVOID)retval);
TRACE("NtUserGetSystemMenu");
ENDRECV_HWNDLOCK();
}
BOOL NtUserGetUpdateRect( // API GetUpdateRect
IN HWND hwnd,
IN LPRECT prect OPTIONAL,
IN BOOL bErase)
{
RECT rect2;
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
retval = xxxGetUpdateRect(
pwnd,
prect? &rect2:NULL,
bErase);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(prect)) {
try {
ProbeAndWriteStructure(prect, rect2, RECT);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetUpdateRect");
ENDRECV_HWNDLOCK();
}
BOOL NtUserHideCaret(
IN HWND hwnd)
{
PWND pwnd;
BEGINRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
retval = zzzHideCaret(pwnd);
TRACE("NtUserHideCaret");
ENDRECV();
}
BOOL NtUserHiliteMenuItem(
IN HWND hwnd,
IN HMENU hMenu,
IN UINT uIDHiliteItem,
IN UINT uHilite)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
TESTFLAGS(uHilite, MF_VALID);
ValidateHMENUMODIFY(pmenu, hMenu);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
retval = xxxHiliteMenuItem(
pwnd,
pmenu,
uIDHiliteItem,
uHilite);
ThreadUnlock(&tlpMenu);
TRACE("NtUserHiliteMenuItem");
ENDRECV_HWNDLOCK();
}
BOOL NtUserInvalidateRect( // API InvalidateRect
IN HWND hwnd,
IN CONST RECT *prect OPTIONAL,
IN BOOL bErase)
{
PWND pwnd;
TL tlpwnd;
RECT rc;
BEGINRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(prect)) {
try {
rc = ProbeAndReadRect(prect);
prect = &rc;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
ThreadLock(pwnd, &tlpwnd);
retval = xxxInvalidateRect(
pwnd,
(PRECT)prect,
bErase);
ThreadUnlock(&tlpwnd);
TRACE("NtUserInvalidateRect");
ENDRECV();
}
BOOL NtUserIsClipboardFormatAvailable(
IN UINT nFormat)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(BOOL, FALSE);
/*
* Blow it off if the caller doesn't have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
MSGERROR(0);
}
retval = (FindClipFormat(pwinsta, nFormat) != NULL);
TRACE("NtUserIsClipboardFormatAvailable");
ENDRECV_SHARED();
}
BOOL NtUserKillTimer(
IN HWND hwnd,
IN UINT_PTR nIDEvent)
{
PWND pwnd;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
retval = _KillTimer(
pwnd,
nIDEvent);
TRACE("NtUserKillTimer");
ENDATOMICRECV();
}
HWND NtUserMinMaximize(
IN HWND hwnd,
IN UINT nCmdShow,
IN BOOL fKeepHidden)
{
BEGINRECV_HWNDLOCK_ND(HWND, NULL, hwnd);
retval = (HWND)xxxMinMaximize(
pwndND,
nCmdShow,
((fKeepHidden) ? MINMAX_KEEPHIDDEN : 0) | TEST_PUDF(PUDF_ANIMATE));
retval = PtoH((PVOID)retval);
TRACE("NtUserMinMaximize");
ENDRECV_HWNDLOCK_ND();
}
/**************************************************************************\
* NtUserMNDragOver
*
* Called from the IDropTarget interface to let menus update the selection
* given the mouse position. It also returns the handle of the menu the
* the index of the item the point is on.
*
* 10/28/96 GerardoB Created
\**************************************************************************/
BOOL NtUserMNDragOver( // worker for menu drag & drop
IN POINT * ppt,
OUT PMNDRAGOVERINFO pmndoi)
{
POINT pt;
MNDRAGOVERINFO mndoi;
BEGINRECV(BOOL, FALSE);
/*
* No need to SetLastError since ppt and pmndoi are always addresses of
* local stack variables in USER, not addresses from an application
*/
try {
pt = ProbeAndReadPoint(ppt);
} except (StubExceptionHandler(FALSE)) {
RIPMSG1(RIP_WARNING, "NtUserMNDragOver: Exception:%#lx", GetExceptionCode());
MSGERROR(0);
}
retval = xxxMNDragOver(&pt, &mndoi);
if (retval) {
try {
ProbeAndWriteStructure(pmndoi, mndoi, MNDRAGOVERINFO);
} except (StubExceptionHandler(FALSE)) {
RIPMSG1(RIP_WARNING, "NtUserMNDragOver: Exception:%#lx", GetExceptionCode());
MSGERROR(0);
}
}
TRACE("NtUserMNDragOver");
ENDRECV();
}
/**************************************************************************\
* NtUserMNDragLeave
*
* Called from the IDropTarget interface to let the menu clean up
*
* 10/28/96 GerardoB Created
\**************************************************************************/
BOOL NtUserMNDragLeave(VOID)
{
BEGINRECV(BOOL, FALSE);
retval = xxxMNDragLeave();
TRACE("NtUserMNDragLeave");
ENDRECV();
}
BOOL NtUserOpenClipboard( // API OpenClipboard
IN HWND hwnd,
OUT PBOOL pfEmptyClient)
{
PWND pwnd;
TL tlpwnd;
BOOL fEmptyClient;
BEGINRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = _OpenClipboard(pwnd, &fEmptyClient);
ThreadUnlock(&tlpwnd);
/*
* Probe arguments
* No need to SetLastError since pfEmptyClient is the address of a local
* variable in USER client code, not an application address.
*/
try {
ProbeAndWriteUlong(pfEmptyClient, fEmptyClient);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserOpenClipboard");
ENDRECV();
}
BOOL NtUserPeekMessage(
OUT LPMSG pmsg,
IN HWND hwnd,
IN UINT wMsgFilterMin,
IN UINT wMsgFilterMax,
IN UINT wRemoveMsg)
{
MSG msg;
BEGINRECV(BOOL, FALSE);
TESTFLAGS(wRemoveMsg, PM_VALID);
retval = xxxPeekMessage(
&msg,
hwnd,
wMsgFilterMin,
wMsgFilterMax,
wRemoveMsg);
/*
* Probe and write arguments only if PeekMessage suceeds otherwise
* we want to leave MSG undisturbed (bug 16224) to be compatible.
*/
if (retval) {
try {
ProbeAndWriteStructure(pmsg, msg, MSG);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserPeekMessage");
ENDRECV();
}
BOOL NtUserPostMessage(
IN HWND hwnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PWND pwnd;
BEGINRECV(BOOL, FALSE);
/*
* Prevent apps from setting hi 16 bits so we can use them internally.
*/
if (msg & MSGFLAG_MASK) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid message");
MSGERROR(0);
}
switch ((ULONG_PTR)hwnd) {
case -1:
case 0x0000FFFF:
pwnd = PWND_BROADCAST;
break;
case 0:
pwnd = NULL;
break;
default:
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
/*
* We fake terminates to dead windows! (SAS)
*/
errret = (msg == WM_DDE_TERMINATE);
MSGERROR(0);
}
break;
}
retval = _PostMessage(
pwnd,
msg,
wParam,
lParam);
TRACE("NtUserPostMessage");
ENDRECV();
}
BOOL NtUserRegisterHotKey(
IN HWND hwnd,
IN int id,
IN UINT fsModifiers,
IN UINT vk)
{
PWND pwnd;
BEGINATOMICRECV(BOOL, FALSE);
TESTFLAGS(fsModifiers, MOD_VALID);
ValidateHWNDOPT(pwnd, hwnd);
retval = _RegisterHotKey(pwnd, id, fsModifiers, vk);
TRACE("NtUserRegisterHotKey");
ENDATOMICRECV();
}
BOOL NtUserRemoveMenu(
IN HMENU hmenu,
IN UINT nPosition,
IN UINT dwFlags)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV(BOOL, FALSE);
TESTFLAGS(dwFlags, MF_VALID);
ValidateHMENUMODIFYCHECKLOCK(pmenu, hmenu);
ThreadLock(pmenu, &tlpMenu);
retval = xxxRemoveMenu(pmenu, nPosition, dwFlags);
ThreadUnlock(&tlpMenu);
TRACE("NtUserRemoveMenu");
ENDRECV();
}
BOOL NtUserScrollWindowEx( // API ScrollWindowEx
IN HWND hwnd,
IN int dx,
IN int dy,
IN CONST RECT *prcScroll OPTIONAL,
IN CONST RECT *prcClip OPTIONAL,
IN HRGN hrgnUpdate,
OUT LPRECT prcUpdate OPTIONAL,
IN UINT flags)
{
RECT rcScroll;
RECT rcClip;
RECT rcUpdate;
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(prcScroll)) {
rcScroll = ProbeAndReadRect(prcScroll);
prcScroll = &rcScroll;
}
if (ARGUMENT_PRESENT(prcClip)) {
rcClip = ProbeAndReadRect(prcClip);
prcClip = &rcClip;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxScrollWindowEx(
pwnd,
dx,
dy,
(PRECT)prcScroll,
(PRECT)prcClip,
hrgnUpdate,
prcUpdate ? &rcUpdate : NULL,
flags);
if (ARGUMENT_PRESENT(prcUpdate)) {
try {
ProbeAndWriteStructure(prcUpdate, rcUpdate, RECT);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserScrollWindow");
ENDRECV_HWNDLOCK();
}
HWND NtUserSetActiveWindow(
IN HWND hwnd)
{
PWND pwnd;
TL tlpwnd;
BEGINRECV(HWND, NULL);
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = (HWND)xxxSetActiveWindow(pwnd);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwnd);
TRACE("NtUserSetActiveWindow");
ENDRECV();
}
HWND NtUserSetCapture(
IN HWND hwnd)
{
PWND pwnd;
TL tlpwnd;
BEGINRECV(HWND, NULL);
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = (HWND)xxxSetCapture(pwnd);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwnd);
TRACE("NtUserSetCapture");
ENDRECV();
}
WORD NtUserSetClassWord(
IN HWND hwnd,
IN int nIndex,
IN WORD wNewWord)
{
BEGINRECV_HWND(WORD, 0, hwnd);
retval = _SetClassWord(
pwnd,
nIndex,
wNewWord);
TRACE("NtUserSetClassWord");
ENDRECV_HWND();
}
HWND NtUserSetClipboardViewer(
IN HWND hwnd)
{
PWND pwnd;
TL tlpwnd;
BEGINRECV(HWND, NULL);
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = (HWND)xxxSetClipboardViewer(pwnd);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwnd);
TRACE("NtUserSetClipboardViewer");
ENDRECV();
}
HCURSOR NtUserSetCursor(
IN HCURSOR hCursor)
{
PCURSOR pCursor;
BEGINRECV(HCURSOR, NULL);
ValidateHCURSOROPT(pCursor, hCursor);
retval = (HCURSOR)zzzSetCursor(pCursor);
retval = PtoH((PVOID)retval);
TRACE("NtUserSetCursor");
ENDRECV();
}
HWND NtUserSetFocus(
IN HWND hwnd)
{
PWND pwnd;
TL tlpwnd;
BEGINRECV(HWND, NULL);
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = (HWND)xxxSetFocus(pwnd);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwnd);
TRACE("NtUserSetFocus");
ENDRECV();
}
BOOL NtUserSetMenu(
IN HWND hwnd,
IN HMENU hmenu,
IN BOOL fRedraw)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV_HWNDLOCK_ND(DWORD, 0, hwnd);
ValidateHMENUOPT(pmenu, hmenu);
ThreadLockWithPti(ptiCurrent, pmenu, &tlpMenu);
retval = xxxSetMenu(pwndND, pmenu, fRedraw);
ThreadUnlock(&tlpMenu);
TRACE("NtUserSetMenu");
ENDRECV_HWNDLOCK_ND();
}
HWND NtUserSetParent(
IN HWND hwndChild,
IN HWND hwndNewParent)
{
PWND pwndNewParent;
TL tlpwndNewParent;
BEGINRECV_HWNDLOCK_ND(HWND, NULL, hwndChild);
if (hwndNewParent == NULL) {
pwndNewParent = _GetDesktopWindow();
} else if (hwndNewParent == HWND_MESSAGE) {
pwndNewParent = _GetMessageWindow();
} else {
ValidateHWND(pwndNewParent, hwndNewParent);
}
ThreadLockWithPti(ptiCurrent, pwndNewParent, &tlpwndNewParent);
retval = (HWND)xxxSetParent(
pwndND,
pwndNewParent);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwndNewParent);
TRACE("NtUserSetParent");
ENDRECV_HWNDLOCK_ND();
}
int NtUserSetScrollInfo( // API SetScrollInfo
IN HWND hwnd,
IN int nBar,
IN LPCSCROLLINFO pInfo,
IN BOOL fRedraw)
{
SCROLLINFO si;
BEGINRECV_HWNDLOCK_ND(DWORD, 0, hwnd);
LIMITVALUE(nBar, SB_MAX, "SetScrollInfo");
/*
* Probe arguments
*/
try {
si = ProbeAndReadScrollInfo(pInfo);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxSetScrollBar(pwndND, nBar, &si, fRedraw);
TRACE("NtUserSetScrollInfo");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserSetSysColors( // API SetSysColors
IN int nCount,
IN CONST INT *pSysColor,
IN CONST COLORREF *pColorValues,
IN UINT uOptions)
{
LPINT lpSysColors = NULL;
LPDWORD lpSysColorValues = NULL;
TL tlName, tlSysColors, tlSysColorValues;
PUNICODE_STRING pProfileUserName = NULL;
PTHREADINFO ptiCurrent;
BEGINRECV(BOOL, FALSE);
ptiCurrent = PtiCurrent();
/*
* Prevent restricted threads from changing global stuff
*/
if (IS_THREAD_RESTRICTED(ptiCurrent, JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS)) {
MSGERROR(0);
}
/*
* Probe arguments
*/
if (nCount) {
try {
ProbeForReadBuffer(pSysColor, nCount, DATAALIGN);
ProbeForReadBuffer(pColorValues, nCount, DATAALIGN);
lpSysColors = UserAllocPoolWithQuota(nCount * sizeof(*pSysColor), TAG_COLORS);
if (lpSysColors == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
RtlCopyMemory(lpSysColors, pSysColor, nCount * sizeof(*pSysColor));
lpSysColorValues = UserAllocPoolWithQuota(nCount * sizeof(*pColorValues), TAG_COLORVALUES);
if (lpSysColorValues == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
RtlCopyMemory(lpSysColorValues, pColorValues, nCount * sizeof(*pColorValues));
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
}
ThreadLockPool(ptiCurrent, lpSysColors, &tlSysColors);
ThreadLockPool(ptiCurrent, lpSysColorValues, &tlSysColorValues);
pProfileUserName = CreateProfileUserName(&tlName);
retval = xxxSetSysColors(pProfileUserName,
nCount,
lpSysColors,
lpSysColorValues,
uOptions);
FreeProfileUserName(pProfileUserName, &tlName);
ThreadUnlockPool(ptiCurrent, &tlSysColorValues);
ThreadUnlockPool(ptiCurrent, &tlSysColors);
CLEANUPRECV();
if (lpSysColors) {
UserFreePool(lpSysColors);
}
if (lpSysColorValues) {
UserFreePool(lpSysColorValues);
}
TRACE("NtUserSetSysColors");
ENDRECV();
}
UINT_PTR NtUserSetTimer(
IN HWND hwnd,
IN UINT_PTR nIDEvent,
IN UINT wElapse,
IN TIMERPROC pTimerFunc)
{
PWND pwnd;
BEGINATOMICRECV(UINT_PTR, 0);
ValidateHWNDOPT(pwnd, hwnd);
/*
* We have code on the client side that assumes no CSRSS code creates
* a timer with a timer proc, so assert that that's the case.
*/
UserAssert(PsGetCurrentProcess() != gpepCSRSS || pTimerFunc == NULL);
/*
* If we let apps set a timer granularity less then 10 the app
* spends too long processing timer messages. Some WOW apps like
* Paradox in WinStone use zero to effectively get the minimal
* timer value which was ~55ms in Win 3.1. We also step this
* value up for 32 bit apps because the NT timer resolution
* can very depending if the multimedia timers have turned up
* the resolution. If they have NT apps that specify a low value
* will not work properly because they will eat the CPU processing
* WM_TIMER messages.
*/
if (wElapse < 10) {
wElapse = 10;
}
retval = _SetTimer(
pwnd,
nIDEvent,
wElapse,
(TIMERPROC_PWND)pTimerFunc);
TRACE("NtUserSetTimer");
ENDATOMICRECV();
}
LONG_PTR NtUserSetWindowLongPtr(
IN HWND hwnd,
IN int nIndex,
IN LONG_PTR dwNewLong,
IN BOOL bAnsi)
{
BEGINRECV_HWNDLOCK(ULONG_PTR, 0, hwnd);
retval = xxxSetWindowLongPtr(pwnd, nIndex, dwNewLong, bAnsi);
TRACE("NtUserSetWindowLongPtr");
ENDRECV_HWNDLOCK();
}
#ifdef _WIN64
LONG NtUserSetWindowLong(
IN HWND hwnd,
IN int nIndex,
IN LONG dwNewLong,
IN BOOL bAnsi)
{
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
retval = xxxSetWindowLong(pwnd, nIndex, dwNewLong, bAnsi);
TRACE("NtUserSetWindowLong");
ENDRECV_HWNDLOCK();
}
#endif
WORD NtUserSetWindowWord(
IN HWND hwnd,
IN int nIndex,
IN WORD wNewWord)
{
BEGINRECV_HWND(WORD, 0, hwnd);
retval = _SetWindowWord(pwnd, nIndex, wNewWord);
TRACE("NtUserSetWindowWord");
ENDRECV_HWND();
}
HHOOK NtUserSetWindowsHookAW(
IN int nFilterType,
IN HOOKPROC pfnFilterProc,
IN DWORD dwFlags)
{
BEGINRECV(HHOOK, NULL);
retval = (HHOOK)zzzSetWindowsHookAW(nFilterType, (PROC)pfnFilterProc, dwFlags);
TRACE("NtUserSetWindowsHookAW");
ENDRECV();
}
BOOL NtUserShowCaret(
IN HWND hwnd)
{
PWND pwnd;
BEGINRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
retval = zzzShowCaret(pwnd);
TRACE("NtUserShowCaret");
ENDRECV();
}
BOOL NtUserShowScrollBar(
IN HWND hwnd,
IN int iBar,
IN BOOL fShow)
{
BEGINRECV_HWNDLOCK_ND(DWORD, 0, hwnd);
LIMITVALUE(iBar, SB_MAX, "ShowScrollBar");
retval = xxxShowScrollBar(pwndND, iBar, fShow);
TRACE("NtUserShowScrollBar");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserShowWindowAsync(
IN HWND hwnd,
IN int nCmdShow)
{
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
LIMITVALUE(nCmdShow, SW_MAX, "ShowWindowAsync");
retval = _ShowWindowAsync(pwndND, nCmdShow, 0);
TRACE("NtUserShowWindowAsync");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserShowWindow(
IN HWND hwnd,
IN int nCmdShow)
{
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
LIMITVALUE(nCmdShow, SW_MAX, "ShowWindow");
/*
* Let's not allow the window to be shown/hidden once we
* started the destruction of the window.
*/
if (TestWF(pwndND, WFINDESTROY)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"ShowWindow: Window is being destroyed (%#p)",
pwndND);
MSGERROR(0);
}
retval = xxxShowWindow(pwndND, nCmdShow | TEST_PUDF(PUDF_ANIMATE));
TRACE("NtUserShowWindow");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserTrackMouseEvent( // API TrackMouseEvent
IN OUT LPTRACKMOUSEEVENT lpTME)
{
TRACKMOUSEEVENT tme;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
tme = ProbeAndReadTrackMouseEvent(lpTME);
if (tme.cbSize != sizeof(tme)) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "TrackMouseEvent: invalid size %lX", tme.cbSize);
MSGERROR(0);
}
TESTFLAGS(tme.dwFlags, TME_VALID);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (tme.dwFlags & TME_QUERY) {
retval = QueryTrackMouseEvent(&tme);
try {
RtlCopyMemory(lpTME, &tme, sizeof(tme));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
} else {
retval = TrackMouseEvent(&tme);
}
TRACE("NtUserTrackMouseEvent");
ENDRECV();
}
BOOL NtUserTrackPopupMenuEx( // API TrackPopupMenuEx
IN HMENU hMenu,
IN UINT uFlags,
IN int x,
IN int y,
IN HWND hwnd,
IN CONST TPMPARAMS *pparamst OPTIONAL)
{
PWND pwnd;
PMENU pmenu;
TL tlpwnd;
TL tlpMenu;
PTHREADINFO ptiCurrent;
TPMPARAMS paramst;
BEGINRECV(BOOL, FALSE);
TESTFLAGS(uFlags, TPM_VALID);
ValidateHMENU(pmenu, hMenu);
ValidateHWND(pwnd, hwnd);
ptiCurrent = PtiCurrent();
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(pparamst)) {
paramst = ProbeAndReadPopupParams(pparamst);
pparamst = &paramst;
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = xxxTrackPopupMenuEx(
pmenu,
uFlags,
x,
y,
pwnd,
pparamst);
CLEANUPRECV();
ThreadUnlock(&tlpMenu);
ThreadUnlock(&tlpwnd);
TRACE("NtUserTrackPopupMenuEx");
ENDRECV();
}
UINT NtUserPaintMenuBar(
IN HWND hwnd,
IN HDC hdc,
IN int iLeftOffset,
IN int iRightOffset,
IN int iTopOffset,
IN DWORD dwFlags)
{
BEGINRECV_HWNDLOCK(UINT, 0, hwnd);
/*
* This routine should only be called for top-level windows.
*/
if (TestwndChild(pwnd)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
TESTFLAGS(dwFlags, PMB_VALID);
if (iLeftOffset < 0 || iRightOffset < 0 || iTopOffset < 0) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
retval = xxxPaintMenuBar(pwnd, hdc, iLeftOffset, iRightOffset, iTopOffset, dwFlags);
TRACE("NtUserPaintMenuBar");
ENDRECV_HWNDLOCK();
}
UINT NtUserCalcMenuBar(
IN HWND hwnd,
IN int iLeftOffset,
IN int iRightOffset,
IN int iTopOffset,
IN LPCRECT prcWnd)
{
RECT rcWnd;
BEGINRECV_HWNDLOCK(UINT, 0, hwnd);
if (iLeftOffset < 0 || iRightOffset < 0 || iTopOffset < 0) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
try {
if (ARGUMENT_PRESENT(prcWnd)) {
rcWnd = ProbeAndReadRect(prcWnd);
} else {
CopyRect(&rcWnd, &pwnd->rcWindow);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCalcMenuBar(pwnd, iLeftOffset, iRightOffset, iTopOffset, &rcWnd);
TRACE("NtUserCalcMenuBar");
ENDRECV_HWNDLOCK();
}
BOOL NtUserTranslateMessage( // API TranslateMessage
IN CONST MSG *lpMsg,
IN UINT flags)
{
MSG msg;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
msg = ProbeAndReadMessage(lpMsg);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (ValidateHwnd(msg.hwnd) == NULL) {
MSGERROR(0);
}
retval = xxxTranslateMessage(
&msg,
flags);
TRACE("NtUserTranslateMessage");
ENDRECV();
}
BOOL NtUserUnhookWindowsHookEx(
IN HHOOK hhk)
{
PHOOK phk;
BEGINRECV(BOOL, FALSE);
ValidateHHOOK(phk, hhk);
retval = zzzUnhookWindowsHookEx(
phk);
TRACE("NtUserUnhookWindowsHookEx");
ENDRECV();
}
BOOL NtUserUnregisterHotKey(
IN HWND hwnd,
IN int id)
{
PWND pwnd;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWNDOPT(pwnd, hwnd);
retval = _UnregisterHotKey(
pwnd,
id);
TRACE("NtUserUnregisterHotKey");
ENDATOMICRECV();
}
BOOL NtUserValidateRect( // API ValidateRect
IN HWND hwnd,
IN CONST RECT *lpRect OPTIONAL)
{
PWND pwnd;
TL tlpwnd;
RECT rc;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lpRect)) {
try {
rc = ProbeAndReadRect(lpRect);
lpRect = &rc;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
ValidateHWNDOPT(pwnd, hwnd);
ThreadLock(pwnd, &tlpwnd);
retval = xxxValidateRect(pwnd, (PRECT)lpRect);
ThreadUnlock(&tlpwnd);
TRACE("NtUserValidateRect");
ENDRECV();
}
DWORD NtUserWaitForInputIdle(
IN ULONG_PTR idProcess,
IN DWORD dwMilliseconds,
IN BOOL fSharedWow)
{
BEGINRECV(DWORD, (DWORD)-1);
retval = xxxWaitForInputIdle(
idProcess,
dwMilliseconds,
fSharedWow);
TRACE("NtUserWaitForInputIdle");
ENDRECV();
}
HWND NtUserWindowFromPoint(
IN POINT Point)
{
BEGINRECV(HWND, NULL);
retval = (HWND)xxxWindowFromPoint(
Point);
retval = PtoH((PVOID)retval);
TRACE("NtUserWindowFromPoint");
ENDRECV();
}
HDC NtUserBeginPaint( // API BeginPaint
IN HWND hwnd,
OUT LPPAINTSTRUCT lpPaint)
{
PAINTSTRUCT ps;
BEGINRECV_HWNDLOCK(HDC, NULL, hwnd);
retval = xxxBeginPaint(pwnd, &ps);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure(lpPaint, ps, PAINTSTRUCT);
} except (StubExceptionHandler(TRUE)) {
xxxEndPaint(pwnd, &ps);
MSGERROR(0);
}
TRACE("NtUserBeginPaint");
ENDRECV_HWNDLOCK();
}
BOOL NtUserCreateCaret(
IN HWND hwnd,
IN HBITMAP hBitmap,
IN int nWidth,
IN int nHeight)
{
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
retval = xxxCreateCaret(pwnd, hBitmap, nWidth, nHeight);
TRACE("NtUserCreateCaret");
ENDRECV_HWNDLOCK();
}
BOOL NtUserEndPaint( // API EndPaint
IN HWND hwnd,
IN CONST PAINTSTRUCT *lpPaint)
{
PAINTSTRUCT ps;
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
try {
ps = ProbeAndReadPaintStruct(lpPaint);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxEndPaint(pwnd, &ps);
TRACE("NtUserEndPaint");
ENDRECV_HWNDLOCK();
}
int NtUserExcludeUpdateRgn(
IN HDC hdc,
IN HWND hwnd)
{
BEGINRECV_HWND(int, ERROR, hwnd);
if (hdc == NULL)
MSGERROR(0);
retval = _ExcludeUpdateRgn(hdc, pwnd);
TRACE("NtUserExcludeUpdateRgn");
ENDRECV_HWND();
}
HDC NtUserGetDC(
IN HWND hwnd)
{
PWND pwnd;
BOOL bValid = TRUE;
BEGINATOMICRECV(HDC, NULL);
ValidateHWNDOPT(pwnd, hwnd);
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_HANDLES) && pwnd == NULL) {
PDESKTOP pdesk = PtiCurrent()->rpdesk;
/*
* Make sure it has access to the desktop window.
*/
if (!ValidateHwnd(PtoH(pdesk->pDeskInfo->spwnd))) {
bValid = FALSE;
}
}
retval = _GetDC(pwnd);
if (!bValid) {
HRGN hrgn = CreateEmptyRgn();
/*
* Select a NULL visible region on this DC so that restricted
* processes don't mess with GetDC(NULL).
*/
GreSelectVisRgn(retval, hrgn, SVR_DELETEOLD);
}
TRACE("NtUserGetDC");
ENDATOMICRECV();
}
HDC NtUserGetDCEx(
IN HWND hwnd,
IN HRGN hrgnClip,
IN DWORD flags)
{
PWND pwnd;
BEGINATOMICRECV(HDC, NULL);
if ((hrgnClip && !GreIsValidRegion(hrgnClip)) || flags & ~DCX_MASK) {
RIPMSG0(RIP_ERROR, "NtUserGetDCEx passed invalid parameter");
MSGERROR(ERROR_INVALID_PARAMETER);
}
ValidateHWNDOPT(pwnd, hwnd);
if (pwnd == NULL) {
pwnd = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_HANDLES)) {
/*
* Make sure it has access to the desktop window.
*/
if (!ValidateHwnd(PtoH(pwnd))) {
RIPMSG0(RIP_WARNING,
"NtUserGetDCEx fails desktop window validation");
MSGERROR(0);
}
}
}
retval = _GetDCEx(pwnd, hrgnClip, flags);
TRACE("NtUserGetDCEx");
ENDATOMICRECV();
}
HDC NtUserGetWindowDC(
IN HWND hwnd)
{
PWND pwnd;
BEGINATOMICRECV(HDC, NULL);
ValidateHWNDOPT(pwnd, hwnd);
retval = _GetWindowDC(pwnd);
TRACE("NtUserGetWindowDC");
ENDATOMICRECV();
}
int NtUserGetUpdateRgn(
IN HWND hwnd,
IN HRGN hrgn,
IN BOOL bErase)
{
BEGINRECV_HWNDLOCK(int, ERROR, hwnd);
retval = xxxGetUpdateRgn(
pwnd,
hrgn,
bErase);
TRACE("NtUserGetUpdateRgn");
ENDRECV_HWNDLOCK();
}
BOOL NtUserRedrawWindow( // API RedrawWindow
IN HWND hwnd,
IN CONST RECT *lprcUpdate OPTIONAL,
IN HRGN hrgnUpdate,
IN UINT flags)
{
RECT rc;
BEGINRECV_HWNDLOCK_OPT(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lprcUpdate)) {
try {
rc = ProbeAndReadRect(lprcUpdate);
lprcUpdate = &rc;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TESTFLAGS(flags, RDW_VALIDMASK);
retval = xxxRedrawWindow(
pwnd,
(PRECT)lprcUpdate,
hrgnUpdate,
flags);
TRACE("NtUserRedrawWindow");
ENDRECV_HWNDLOCK_OPT();
}
BOOL NtUserInvalidateRgn(
IN HWND hwnd,
IN HRGN hrgn,
IN BOOL bErase)
{
BEGINRECV_HWNDLOCK(BOOL, FALSE, hwnd);
retval = xxxInvalidateRgn(
pwnd,
hrgn,
bErase);
TRACE("NtUserInvalidateRgn");
ENDRECV_HWNDLOCK();
}
int NtUserSetWindowRgn(
IN HWND hwnd,
IN HRGN hrgn,
IN BOOL bRedraw)
{
BEGINRECV_HWNDLOCK_ND(int, 0, hwnd);
retval = xxxSetWindowRgn(
pwndND,
hrgn,
bRedraw);
TRACE("NtUserSetWindowRgn");
ENDRECV_HWNDLOCK_ND();
}
BOOL NtUserScrollDC( // API ScrollDC
IN HDC hdc,
IN int dx,
IN int dy,
IN CONST RECT *prcScroll OPTIONAL,
IN CONST RECT *prcClip OPTIONAL,
IN HRGN hrgnUpdate,
OUT LPRECT prcUpdate OPTIONAL)
{
RECT rcScroll;
RECT rcClip;
RECT rcUpdate;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(prcScroll)) {
rcScroll = ProbeAndReadRect(prcScroll);
prcScroll = &rcScroll;
}
if (ARGUMENT_PRESENT(prcClip)) {
rcClip = ProbeAndReadRect(prcClip);
prcClip = &rcClip;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _ScrollDC(
hdc,
dx,
dy,
(PRECT)prcScroll,
(PRECT)prcClip,
hrgnUpdate,
prcUpdate ? &rcUpdate : NULL);
if (ARGUMENT_PRESENT(prcUpdate)) {
try {
ProbeAndWriteStructure(prcUpdate, rcUpdate, RECT);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
ENDRECV();
}
int NtUserInternalGetWindowText( // private InternalGetWindowText
IN HWND hwnd,
OUT LPWSTR lpString,
IN int nMaxCount)
{
BEGINRECV_HWND_SHARED(DWORD, 0, hwnd);
if (nMaxCount) {
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(lpString, nMaxCount, CHARALIGN);
/*
* Initialize string empty.
*/
*lpString = TEXT('\0');
if (pwnd->strName.Length) {
retval = TextCopy(&pwnd->strName, lpString, nMaxCount);
} else {
retval = 0;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0); // private API, don't SetLastError
}
} else {
MSGERROR(0);
}
TRACE("NtUserInternalGetWindowText");
ENDRECV_HWND_SHARED();
}
int NtUserGetMouseMovePointsEx( // API GetMouseMovePointsEx
IN UINT cbSize,
IN CONST MOUSEMOVEPOINT *lppt,
OUT MOUSEMOVEPOINT *lpptBuf,
IN UINT nBufPoints,
IN DWORD resolution)
{
MOUSEMOVEPOINT mmp;
BEGINRECV(int, -1);
if (cbSize != sizeof(MOUSEMOVEPOINT) || nBufPoints > MAX_MOUSEPOINTS) {
RIPERR2(ERROR_INVALID_PARAMETER, RIP_VERBOSE,
"GetMouseMovePointsEx: invalid cbSize %d or nBufPoints %d",
cbSize, nBufPoints);
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
mmp = ProbeAndReadStructure(lppt, MOUSEMOVEPOINT);
ProbeForWriteBuffer(lpptBuf, nBufPoints, DATAALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* GetMouseMovePointsEx protects itself with a try block.
* No it doesn't!
*/
retval = _GetMouseMovePointsEx(&mmp, lpptBuf, nBufPoints, resolution);
TRACE("NtUserGetMouseMovePointsEx");
ENDRECV();
}
int NtUserToUnicodeEx( // API ToUnicode/ToUnicodeEx/ToAscii/ToAsciiEx
IN UINT wVirtKey,
IN UINT wScanCode,
IN CONST BYTE *lpKeyState,
OUT LPWSTR pwszBuff,
IN int cchBuff,
IN UINT wFlags,
IN HKL hKeyboardLayout)
{
BYTE KeyState[256];
WCHAR wcBuff[4];
LPWSTR pwszBuffK;
BOOL bAlloc = FALSE;
PTHREADINFO ptiCurrent;
TL tlInput;
BEGINRECV(int, 0);
if (cchBuff <= 0) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
/*
* Probe arguments
*/
try {
ProbeForRead(lpKeyState, 256, sizeof(BYTE));
RtlCopyMemory(KeyState, lpKeyState, 256);
ProbeForWriteBuffer(pwszBuff, cchBuff, CHARALIGN);
if (cchBuff < 4) {
pwszBuffK = wcBuff;
}else {
pwszBuffK = UserAllocPoolWithQuota(cchBuff * sizeof(WCHAR), TAG_UNICODEBUFFER);
if (pwszBuffK == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
bAlloc = TRUE;
ptiCurrent = PtiCurrent();
ThreadLockPool(ptiCurrent, pwszBuffK, &tlInput);
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = xxxToUnicodeEx(
wVirtKey,
wScanCode,
KeyState,
pwszBuffK,
cchBuff,
wFlags,
hKeyboardLayout);
try {
RtlCopyMemory(pwszBuff, pwszBuffK, cchBuff*sizeof(WCHAR));
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
CLEANUPRECV();
if (bAlloc) {
ThreadUnlockAndFreePool(ptiCurrent, &tlInput);
}
TRACE("NtUserToUnicodeEx");
ENDRECV();
}
BOOL NtUserYieldTask(
VOID)
{
PTHREADINFO ptiCurrent;
BOOL bBackground;
BEGINRECV(BOOL, FALSE);
/*
* Make sure this process is running in the background if it is just
* spinning.
*/
ptiCurrent = PtiCurrent();
try {
ptiCurrent->pClientInfo->cSpins++;
bBackground = ptiCurrent->pClientInfo->cSpins >= CSPINBACKGROUND;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* CheckProcessBackground see input.c for comments
*/
if (bBackground) {
try {
ptiCurrent->pClientInfo->cSpins = 0;
ptiCurrent->pClientInfo->dwTIFlags |= TIF_SPINNING;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ptiCurrent->TIF_flags |= TIF_SPINNING;
if (!(ptiCurrent->ppi->W32PF_Flags & W32PF_FORCEBACKGROUNDPRIORITY)) {
ptiCurrent->ppi->W32PF_Flags |= W32PF_FORCEBACKGROUNDPRIORITY;
if (ptiCurrent->ppi == gppiWantForegroundPriority) {
SetForegroundPriority(ptiCurrent, FALSE);
}
}
}
retval = xxxUserYield(ptiCurrent);
TRACE("NtUserYieldTask");
ENDRECV();
}
BOOL NtUserWaitMessage(
VOID)
{
BEGINRECV(BOOL, FALSE);
retval = xxxWaitMessage();
TRACE("NtUserWaitMessage");
ENDRECV();
}
#ifdef MESSAGE_PUMP_HOOK
BOOL NtUserRealWaitMessageEx(
IN UINT fsWakeMask,
IN DWORD Timeout)
{
BEGINRECV(BOOL, FALSE);
TESTFLAGS(fsWakeMask, QS_VALID);
if (!IsInsideMPH()) {
RIPMSG0(RIP_WARNING, "NtUserRealWaitMessageEx: Calling MPH function on non-initialized thread");
}
retval = xxxRealWaitMessageEx(fsWakeMask, Timeout);
TRACE("NtUserRealWaitMessage");
ENDRECV();
}
#endif // MESSAGE_PUMP_HOOK
UINT NtUserLockWindowStation(
IN HWINSTA hwinsta)
{
PWINDOWSTATION pwinsta;
NTSTATUS Status;
BEGINRECV(UINT, 0);
Status = ValidateHwinsta(hwinsta, UserMode, 0, &pwinsta);
if (!NT_SUCCESS(Status))
MSGERROR(0);
retval = _LockWindowStation(pwinsta);
ObDereferenceObject(pwinsta);
TRACE("NtUserLockWindowStation");
ENDRECV();
}
BOOL NtUserUnlockWindowStation(
IN HWINSTA hwinsta)
{
PWINDOWSTATION pwinsta;
NTSTATUS Status;
BEGINRECV(BOOL, FALSE);
Status = ValidateHwinsta(hwinsta, UserMode, 0, &pwinsta);
if (!NT_SUCCESS(Status))
MSGERROR(0);
retval = _UnlockWindowStation(pwinsta);
ObDereferenceObject(pwinsta);
TRACE("NtUserUnlockWindowStation");
ENDRECV();
}
UINT NtUserSetWindowStationUser( // private SetWindowStationUser
IN HWINSTA hwinsta,
IN PLUID pLuidUser,
IN PSID pSidUser OPTIONAL,
IN DWORD cbSidUser)
{
PWINDOWSTATION pwinsta;
NTSTATUS Status;
LUID luid;
BEGINATOMICRECV(UINT, FALSE);
Status = ValidateHwinsta(hwinsta, UserMode, 0, &pwinsta);
if (!NT_SUCCESS(Status))
MSGERROR(0);
try {
ProbeForRead(pLuidUser, sizeof(*pLuidUser), sizeof(DWORD));
luid = *pLuidUser;
if (ARGUMENT_PRESENT(pSidUser)) {
ProbeForRead(pSidUser, cbSidUser, sizeof(DWORD));
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0); // don't SetLastError for private API
}
/*
* SetWindowStationUser uses pSidUser in a try block.
*/
retval = _SetWindowStationUser(pwinsta, &luid, pSidUser, cbSidUser);
CLEANUPRECV();
ObDereferenceObject(pwinsta);
TRACE("NtUserSetWindowStationUser");
ENDATOMICRECV();
}
BOOL NtUserSetLogonNotifyWindow(
IN HWND hwnd)
{
BEGINRECV_HWND(BOOL, FALSE, hwnd);
retval = _SetLogonNotifyWindow(pwnd);
TRACE("NtUserSetLogonNotifyWindow");
ENDRECV_HWND();
}
BOOL NtUserSetSystemCursor(
IN HCURSOR hcur,
IN DWORD id)
{
PCURSOR pcur;
BEGINRECV(BOOL, FALSE);
ValidateHCURSOR(pcur, hcur);
retval = zzzSetSystemCursor(pcur, id);
TRACE("NtUserSetSystemCursor");
ENDRECV();
}
HCURSOR NtUserGetCursorFrameInfo( // private GetCursorFrameInfo (Obsolete? - IanJa)
IN HCURSOR hcur,
IN int iFrame,
OUT LPDWORD pjifRate,
OUT LPINT pccur)
{
PCURSOR pcur, pcurRet;
DWORD jifRate;
INT ccur;
BEGINRECV_SHARED(HCURSOR, NULL);
ValidateHCURSOR(pcur, hcur);
/*
* Probe arguments
*/
try {
ProbeForWriteUlong(pjifRate);
ProbeForWriteLong(pccur);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0); // don't SetLastError for private API
}
pcurRet = _GetCursorFrameInfo(
pcur,
iFrame,
&jifRate,
&ccur);
if (pcurRet != NULL) {
retval = PtoH(pcurRet);
try {
*pjifRate = jifRate;
*pccur = ccur;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0); // don't SetLastError for private API
}
} else {
retval = NULL;
}
TRACE("NtUserGetCursorFrameInfo");
ENDRECV_SHARED();
}
BOOL NtUserSetCursorContents(
IN HCURSOR hCursor,
IN HCURSOR hCursorNew)
{
PCURSOR pCursor;
PCURSOR pCursorNew;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHCURSOR(pCursor, hCursor);
ValidateHCURSOR(pCursorNew, hCursorNew);
retval = _SetCursorContents(pCursor, pCursorNew);
TRACE("NtUserSetCursorContents");
ENDATOMICRECV();
}
HCURSOR NtUserFindExistingCursorIcon( // Various Icon/Cursor APIs
IN PUNICODE_STRING pstrModName,
IN PUNICODE_STRING pstrResName,
IN PCURSORFIND pcfSearch)
{
ATOM atomModName;
UNICODE_STRING strModName;
UNICODE_STRING strResName;
PCURSOR pcurSrc;
CURSORFIND cfSearch;
BEGINRECV_SHARED(HCURSOR, NULL);
/*
* Probe arguments
*/
try {
cfSearch = ProbeAndReadCursorFind(pcfSearch);
ValidateHCURSOROPT(pcurSrc, cfSearch.hcur);
strModName = ProbeAndReadUnicodeString(pstrModName);
ProbeForReadUnicodeStringBuffer(strModName);
strResName = ProbeAndReadUnicodeString(pstrResName);
ProbeForReadUnicodeStringBufferOrId(strResName);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* The ModName buffer is client-side, but UserFindAtom protects
* access.
*/
atomModName = UserFindAtom(strModName.Buffer);
if (atomModName) {
/*
* The ResName buffer is client-side. FindExistincCursorIcon
* protects access.
*/
retval = (HCURSOR)_FindExistingCursorIcon(atomModName,
&strResName,
pcurSrc,
&cfSearch);
retval = (HCURSOR)PtoH((PCURSOR)retval);
} else {
retval = 0;
}
TRACE("NtUserFindExistingCursorIcon");
ENDRECV_SHARED();
}
BOOL NtUserSetCursorIconData( // worker called by CreateIcon, CreateCursor etc.
IN HCURSOR hCursor,
IN PUNICODE_STRING pstrModName,
IN PUNICODE_STRING pstrResName,
IN PCURSORDATA pData)
{
UNICODE_STRING strModName;
UNICODE_STRING strResName;
PCURSOR pCursor;
CURSORDATA curData;
DWORD cbData;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHCURSOR(pCursor, hCursor);
/*
* Probe arguments
*/
try {
strModName = ProbeAndReadUnicodeString(pstrModName);
strResName = ProbeAndReadUnicodeString(pstrResName);
ProbeForReadUnicodeStringBuffer(strModName);
ProbeForReadUnicodeStringBufferOrId(strResName);
curData = ProbeAndReadCursorData(pData);
if (curData.CURSORF_flags & CURSORF_ACON) {
/*
* Avoid overflow here, or we might end up probing less.
* MCostea #199188
*/
if (HIWORD(curData.cpcur) | HIWORD(curData.cicur)) {
MSGERROR(0);
}
/*
* The code assumes that the memory was allocated in one chunk
* as in CreateAniIcon(). To prevent evil apps, do this check.
*/
if ((INT_PTR)curData.ajifRate != curData.cpcur * (INT_PTR) sizeof(HCURSOR) ||
(INT_PTR)curData.aicur != (INT_PTR)curData.ajifRate + curData.cicur * (INT_PTR) sizeof(JIF)) {
MSGERROR(0);
}
cbData = (curData.cpcur * sizeof(HCURSOR)) +
(curData.cicur * sizeof(JIF)) +
(curData.cicur * sizeof(DWORD));
} else {
cbData = 0;
}
ProbeForRead(curData.aspcur, cbData, sizeof(DWORD));
} except (StubExceptionHandler(FALSE)) {
/*
* Probed parameters are USER stack variables, not supplied by the
* application itself, so don't bother to SetLastError.
*/
MSGERROR(0);
}
/*
* SetCursorIconData guards use of the buffer addresses with try clauses.
*/
retval = _SetCursorIconData(pCursor,
&strModName,
&strResName,
&curData,
cbData);
TRACE("NtUserSetCursorIconData");
ENDATOMICRECV();
}
BOOL NtUserGetMenuItemRect( // API GetMenuItemRect
IN HWND hwnd,
IN HMENU hMenu,
IN UINT uItem,
OUT LPRECT lprcItem)
{
PMENU pmenu;
TL tlpMenu;
RECT rcItem;
BEGINRECV_HWNDLOCK_OPT(DWORD, 0, hwnd);
ValidateHMENU(pmenu, hMenu);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
retval = xxxGetMenuItemRect(
pwnd,
pmenu,
uItem,
&rcItem);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure(lprcItem, rcItem, RECT);
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
CLEANUPRECV();
ThreadUnlock(&tlpMenu);
TRACE("NtUserGetMenuItemRect");
ENDRECV_HWNDLOCK_OPT();
}
int NtUserMenuItemFromPoint( // API MenuItemFromPoint
IN HWND hwnd,
IN HMENU hMenu,
IN POINT ptScreen)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV_HWNDLOCK_OPT(DWORD, -1, hwnd);
ValidateHMENU(pmenu, hMenu);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
retval = xxxMenuItemFromPoint(
pwnd,
pmenu,
ptScreen);
ThreadUnlock(&tlpMenu);
TRACE("NtUserMenuItemFromPoint");
ENDRECV_HWNDLOCK_OPT();
}
BOOL NtUserGetCaretPos( // API GetCaretPos
OUT LPPOINT lpPoint)
{
PTHREADINFO pti;
PQ pq;
BEGINRECV_SHARED(BOOL, FALSE);
/*
* Probe arguments
*/
try {
ProbeForWritePoint(lpPoint);
pti = PtiCurrentShared();
pq = pti->pq;
lpPoint->x = pq->caret.x;
lpPoint->y = pq->caret.y;
retval = TRUE;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetCaretPos");
ENDRECV_SHARED();
}
BOOL NtUserDefSetText(
IN HWND hwnd,
IN PLARGE_STRING pstrText OPTIONAL)
{
LARGE_STRING strText;
BEGINRECV_HWND(DWORD, 0, hwnd);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(pstrText)) {
try {
strText = ProbeAndReadLargeString(pstrText);
#if defined(_X86_)
ProbeForRead(strText.Buffer, strText.Length, sizeof(BYTE));
#else
ProbeForRead(strText.Buffer, strText.Length,
strText.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
pstrText = &strText;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0); // WM_SETTEXT lParam
}
}
/*
* pstrText buffer is client side. DefSetText protects uses of the buffer.
*/
retval = DefSetText(
pwnd,
pstrText);
TRACE("NtUserDefSetText");
ENDRECV_HWND();
}
NTSTATUS NtUserQueryInformationThread(
IN HANDLE hThread,
IN USERTHREADINFOCLASS ThreadInfoClass,
IN OUT PVOID ThreadInformation,
IN ULONG ThreadInformationLength,
IN OUT PULONG ReturnLength OPTIONAL)
{
ULONG uReturnLength;
TL tlBuffer;
PTHREADINFO ptiCurrent;
union {
USERTHREAD_SHUTDOWN_INFORMATION ThreadShutdownInformation;
DWORD dwThreadInfo;
WCHAR szThreadTaskName[32];
USERTHREAD_WOW_INFORMATION UserThreadWowInformation;
} ThreadInformationUnion;
PVOID pThreadInformation = NULL;
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
ptiCurrent = PtiCurrent();
/*
* Probe all arguments. Try block necessary even with CSRSS as
* the calling process because it can incurr an in-page exception.
*/
try {
if (ARGUMENT_PRESENT(ThreadInformation)) {
ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(WCHAR));
if (ThreadInformationLength > sizeof(ThreadInformationUnion)) {
pThreadInformation = UserAllocPoolWithQuota(ThreadInformationLength, TAG_SYSTEM);
if (pThreadInformation) {
ThreadLockPool(ptiCurrent, pThreadInformation, &tlBuffer);
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} else {
pThreadInformation = &ThreadInformationUnion;
}
RtlCopyMemory(pThreadInformation, ThreadInformation, ThreadInformationLength);
} else {
pThreadInformation = NULL;
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = xxxQueryInformationThread(
hThread,
ThreadInfoClass,
pThreadInformation,
ThreadInformationLength,
(ARGUMENT_PRESENT(ReturnLength))? &uReturnLength: NULL);
try {
if (ARGUMENT_PRESENT(ThreadInformation)) {
ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(WCHAR));
RtlCopyMemory(ThreadInformation, pThreadInformation, ThreadInformationLength);
}
if (ARGUMENT_PRESENT(ReturnLength)) {
ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
RtlCopyMemory(ReturnLength, &uReturnLength, sizeof(ULONG));
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
CLEANUPRECV();
if ((pThreadInformation != &ThreadInformationUnion) && pThreadInformation) {
ASSERT(ThreadInformationLength > sizeof(ThreadInformationUnion));
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
}
TRACE("NtUserQueryInformationThread");
ENDRECVCSRSS();
}
NTSTATUS NtUserSetInformationThread(
IN HANDLE hThread,
IN USERTHREADINFOCLASS ThreadInfoClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength)
{
union {
USERTHREAD_FLAGS UserThread_Flags;
DWORD dwThreadInfo;
NTSTATUS Status;
USERTHREAD_USEDESKTOPINFO UserThreadDesktopInfo;
HANDLE handle;
} ThreadInformationUnion;
PVOID pThreadInformation = &ThreadInformationUnion;
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
if (ThreadInformationLength > sizeof(ThreadInformationUnion)) {
FRE_RIPMSG2(
RIP_ERROR,
"ThreadInformationLength: %x is greater than union size: %x.",
ThreadInformationLength,
sizeof(ThreadInformationUnion));
}
/*
* Probe read arguments. Try block necessary even with CSRSS as
* the calling process because it can incurr an in-page exception.
*/
try {
if (ARGUMENT_PRESENT(ThreadInformation)) {
ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(DWORD));
RtlCopyMemory(pThreadInformation, ThreadInformation, ThreadInformationLength);
} else {
pThreadInformation = NULL;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxSetInformationThread(
hThread,
ThreadInfoClass,
pThreadInformation,
ThreadInformationLength);
try {
if (ARGUMENT_PRESENT(ThreadInformation)) {
ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(DWORD));
RtlCopyMemory(ThreadInformation, pThreadInformation, ThreadInformationLength);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserSetInformationThread");
ENDRECVCSRSS();
}
NTSTATUS NtUserSetInformationProcess(
IN HANDLE hProcess,
IN USERPROCESSINFOCLASS ProcessInfoClass,
IN PVOID pProcessInformation,
IN ULONG ProcessInformationLength)
{
USERTHREAD_FLAGS ProcessInformation;
BEGINRECVCSRSS(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* Probe read arguments. Try block necessary even with CSRSS as
* the calling process because it can incurr an in-page exception.
*/
try {
if (ARGUMENT_PRESENT(pProcessInformation)) {
ProbeForRead(pProcessInformation, ProcessInformationLength, sizeof(DWORD));
RtlCopyMemory(&ProcessInformation, pProcessInformation, ProcessInformationLength);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = SetInformationProcess(
hProcess,
ProcessInfoClass,
ARGUMENT_PRESENT(pProcessInformation) ? &ProcessInformation : NULL,
ProcessInformationLength);
TRACE("NtUserSetInformationProcess");
ENDRECVCSRSS();
}
BOOL NtUserNotifyProcessCreate(
IN DWORD dwProcessId,
IN DWORD dwParentThreadId,
IN ULONG_PTR dwData,
IN DWORD dwFlags)
{
extern BOOL xxxUserNotifyProcessCreate(
DWORD idProcess,
DWORD idParentThread,
ULONG_PTR dwData,
DWORD dwFlags);
BEGINRECVCSRSS(BOOL, FALSE);
retval = xxxUserNotifyProcessCreate(
dwProcessId,
dwParentThreadId,
dwData, // Static value not a ptr. No probing needed.
dwFlags);
TRACE("NtUserNotifyProcessCreate");
ENDRECVCSRSS();
}
NTSTATUS NtUserSoundSentry(VOID)
{
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
retval = (_UserSoundSentryWorker() ?
STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
TRACE("NtUserSoundSentry");
ENDRECV();
}
NTSTATUS NtUserTestForInteractiveUser( // private _UserTestTokenForInteractive
IN PLUID pluidCaller)
{
LUID luidCaller;
BEGINRECV_SHARED(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* Probe arguments
*/
try {
luidCaller = ProbeAndReadStructure(pluidCaller, LUID);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = TestForInteractiveUser(&luidCaller);
TRACE("NtUserTestForInteractiveUser");
ENDRECV_SHARED();
}
BOOL NtUserSetConsoleReserveKeys(
IN HWND hwnd,
IN DWORD fsReserveKeys)
{
BOOL _SetConsoleReserveKeys(PWND, DWORD);
BEGINRECV_HWND(BOOL, FALSE, hwnd);
retval = _SetConsoleReserveKeys(pwnd, fsReserveKeys);
TRACE("NtUserSetConsoleReserveKeys");
ENDRECV_HWND();
}
VOID NtUserModifyUserStartupInfoFlags(
IN DWORD dwMask,
IN DWORD dwFlags)
{
BEGINRECV_VOID();
PpiCurrent()->usi.dwFlags = (PpiCurrent()->usi.dwFlags & ~dwMask) | (dwFlags & dwMask);
TRACEVOID("NtUserModifyUserStartupInfoFlags");
ENDRECV_VOID();
}
BOOL NtUserSetWindowFNID(
IN HWND hwnd,
IN WORD fnid)
{
BEGINRECV_HWND(BOOL, FALSE, hwnd);
/*
* Don't let apps mess with windows on other processes.
*/
if (GETPTI(pwnd)->ppi != PpiCurrent()) {
MSGERROR(0);
}
/*
* Make sure the fnid is in the correct range.
*/
if (fnid != FNID_CLEANEDUP_BIT) {
if ((fnid < FNID_CONTROLSTART) || (fnid > FNID_CONTROLEND) || (GETFNID(pwnd) != 0)) {
MSGERROR(0);
}
}
/*
* Remember what window class this window belongs to. Can't use
* the real class because any app can call CallWindowProc()
* directly no matter what the class is!
*/
pwnd->fnid |= fnid;
retval = TRUE;
TRACE("NtUserSetWindowFNID");
ENDRECV_HWND();
}
#define AWS_MASK (BS_TYPEMASK | BS_RIGHT | BS_RIGHTBUTTON | \
WS_HSCROLL | WS_VSCROLL | SS_TYPEMASK)
VOID NtUserAlterWindowStyle(
IN HWND hwnd,
IN DWORD mask,
IN DWORD flags)
{
BEGINRECV_HWND_VOID(hwnd);
if (GETPTI(pwnd)->ppi == PpiCurrent()) {
if (mask & ~AWS_MASK) {
RIPMSGF1(RIP_WARNING, "Bad mask 0x%x", mask);
}
mask &= AWS_MASK;
pwnd->style = (pwnd->style & (~mask)) | (flags & mask);
} else {
RIPMSGF1(RIP_WARNING, "Current ppi doesn't own pwnd 0x%p", pwnd);
}
TRACEVOID("NtUserAlterWindowStyle");
ENDRECV_HWND_VOID();
}
VOID NtUserSetThreadState(
IN DWORD dwFlags,
IN DWORD dwMask)
{
PTHREADINFO ptiCurrent;
DWORD dwOldFlags;
if (dwFlags & ~(QF_DIALOGACTIVE)) {
return;
}
BEGINRECV_VOID();
ptiCurrent = PtiCurrent();
dwOldFlags = ptiCurrent->pq->QF_flags;
ptiCurrent->pq->QF_flags ^= ((dwOldFlags ^ dwFlags) & dwMask);
TRACEVOID("NtUserSetThreadState");
ENDRECV_VOID();
}
ULONG_PTR NtUserGetThreadState(
IN USERTHREADSTATECLASS ThreadState)
{
PTHREADINFO ptiCurrent = PtiCurrentShared();
BEGINRECV_SHARED(ULONG_PTR, 0);
switch (ThreadState) {
case UserThreadStateFocusWindow:
retval = (ULONG_PTR)HW(ptiCurrent->pq->spwndFocus);
break;
case UserThreadStateActiveWindow:
retval = (ULONG_PTR)HW(ptiCurrent->pq->spwndActive);
break;
case UserThreadStateCaptureWindow:
retval = (ULONG_PTR)HW(ptiCurrent->pq->spwndCapture);
break;
case UserThreadStateDefaultImeWindow:
retval = (ULONG_PTR)HW(ptiCurrent->spwndDefaultIme);
break;
case UserThreadStateDefaultInputContext:
retval = (ULONG_PTR)PtoH(ptiCurrent->spDefaultImc);
break;
case UserThreadStateImeCompatFlags:
UserAssert(ptiCurrent->ppi != NULL);
retval = (DWORD)(ptiCurrent->ppi->dwImeCompatFlags);
break;
case UserThreadStatePreviousKeyboardLayout:
retval = (ULONG_PTR)(ptiCurrent->hklPrev);
break;
#ifdef OBSOLETE
case UserThreadStateIsWinlogonThread:
/*
* This is no longer supported, for the securty breach bug.
* The enum value is kept for the Wow16 compatibility.
*/
#endif
case UserThreadStateNeedsSecurity:
/*
* Client IMM checks if the process is winlogon to prevent switching
* dictionaries, etc. Also, we need to check the secure desktop, for
* some accessibility applications run on the secure desktop.
*/
retval = (PsGetCurrentProcessId() == gpidLogon) || (ptiCurrent->rpdesk == grpdeskLogon);
if (ptiCurrent->rpdesk == grpdeskLogon) {
RIPMSG2(RIP_WARNING,
"Thread 0x%p is running on the secure desktop %p",
ptiCurrent,
grpdeskLogon);
}
break;
case UserThreadStateIsConImeThread:
UserAssert(ptiCurrent->rpdesk != NULL);
retval = (DWORD)(PtiFromThreadId(ptiCurrent->rpdesk->dwConsoleIMEThreadId) == ptiCurrent);
break;
case UserThreadStateInputState:
retval = (DWORD)_GetInputState();
break;
case UserThreadStateCursor:
retval = (ULONG_PTR)PtoH(ptiCurrent->pq->spcurCurrent);
break;
case UserThreadStateChangeBits:
retval = ptiCurrent->pcti->fsChangeBits;
break;
case UserThreadStatePeekMessage:
/*
* Update the last read time so that hung app painting won't occur.
*/
SET_TIME_LAST_READ(ptiCurrent);
retval = (DWORD)FALSE;
break;
case UserThreadStateExtraInfo:
retval = ptiCurrent->pq->ExtraInfo;
break;
case UserThreadStateInSendMessage:
if (ptiCurrent->psmsCurrent != NULL) {
if (ptiCurrent->psmsCurrent->ptiSender != NULL) {
retval = ISMEX_SEND;
} else if (ptiCurrent->psmsCurrent->flags & (SMF_CB_REQUEST | SMF_CB_REPLY)) {
retval = ISMEX_CALLBACK;
} else {
retval = ISMEX_NOTIFY;
}
if (ptiCurrent->psmsCurrent->flags & SMF_REPLY) {
retval |= ISMEX_REPLIED;
}
} else {
retval = ISMEX_NOSEND;
}
break;
case UserThreadStateMessageTime:
retval = ptiCurrent->timeLast;
break;
case UserThreadStateIsForeground:
retval = (ptiCurrent->pq == gpqForeground);
break;
case UserThreadConnect:
retval = TRUE;
break;
default:
RIPMSG1(RIP_WARNING, "NtUserGetThreadState invalid ThreadState:%#x", ThreadState);
MSGERROR(0);
}
ENDRECV_SHARED();
}
BOOL NtUserValidateHandleSecure(
IN HANDLE h)
{
BEGINRECV(BOOL, FALSE);
retval = ValidateHandleSecure(h);
TRACE("NtUserValidateHandleSecure");
ENDRECV();
}
BOOL NtUserUserHandleGrantAccess( // API UserHandleGrantAccess
IN HANDLE hUserHandle,
IN HANDLE hJob,
IN BOOL bGrant)
{
NTSTATUS Status;
PEJOB Job;
PW32JOB pW32Job;
DWORD dw;
PHE phe;
PULONG_PTR pgh;
BOOL retval;
BOOL errret = FALSE;
Status = ObReferenceObjectByHandle(
hJob,
JOB_OBJECT_SET_ATTRIBUTES,
*PsJobType,
UserMode,
(PVOID*)&Job,
NULL);
if (!NT_SUCCESS(Status)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"UserHandleGrantAccess: Invalid job handle 0x%p",
hJob);
return FALSE;
}
/*
* Acquire the job's lock and enter the user critical section.
*/
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(PsGetJobLock(Job), TRUE);
EnterCrit();
/*
* Bail out if it doesn't have UI restrictions.
*/
if (PsGetJobUIRestrictionsClass(Job) == 0) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"UserHandleGrantAccess: job 0x%p doesn't have UI restrictions",
hJob);
MSGERRORCLEANUP(0);
}
/*
* see if we have a W32JOB structure created for this job
*/
pW32Job = gpJobsList;
while (pW32Job) {
if (pW32Job->Job == Job) {
break;
}
pW32Job = pW32Job->pNext;
}
UserAssert(pW32Job != NULL);
try {
/*
* Now, validate the 'unsecure' handle.
*/
if (HMValidateHandle(hUserHandle, TYPE_GENERIC) == NULL) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"UserHandleGrantAccess: invalid handle 0x%p",
hUserHandle);
MSGERRORCLEANUP(0);
}
dw = HMIndexFromHandle(hUserHandle);
phe = &gSharedInfo.aheList[dw];
phe->bFlags |= HANDLEF_GRANTED;
pgh = pW32Job->pgh;
if (bGrant) {
/*
* Add the handle to the process' list
*/
if (pW32Job->ughCrt == pW32Job->ughMax) {
if (pW32Job->ughCrt == 0) {
pgh = UserAllocPool(GH_SIZE * sizeof(*pgh), TAG_GRANTEDHANDLES);
} else {
/*
* we need to grow the array
*/
DWORD uBytes = (pW32Job->ughMax) * sizeof(*pgh);
pgh = UserReAllocPool(pgh,
uBytes,
uBytes + GH_SIZE * sizeof(*pgh),
TAG_GRANTEDHANDLES);
}
if (pgh == NULL) {
MSGERRORCLEANUP(ERROR_NOT_ENOUGH_MEMORY);
}
pW32Job->pgh = pgh;
pW32Job->ughMax += GH_SIZE;
}
UserAssert(pW32Job->ughCrt < pW32Job->ughMax);
/*
* see if the handle is not already granted to this process
*/
for (dw = 0; dw < pW32Job->ughCrt; dw++) {
if (*(pgh + dw) == (ULONG_PTR)hUserHandle) {
break;
}
}
if (dw >= pW32Job->ughCrt) {
/*
* add the handle to the granted handles table
*/
*(pgh + pW32Job->ughCrt) = (ULONG_PTR)hUserHandle;
(pW32Job->ughCrt)++;
}
} else {
/*
* Remove the handle from the granted list
*/
/*
* search for the handle in the array.
*/
for (dw = 0; dw < pW32Job->ughCrt; dw++) {
if (*(pgh + dw) == (ULONG_PTR)hUserHandle) {
/*
* found the handle granted to this process
*/
RtlMoveMemory(pgh + dw,
pgh + dw + 1,
(pW32Job->ughCrt - dw - 1) * sizeof(*pgh));
(pW32Job->ughCrt)--;
break;
}
}
#if DBG
if (dw >= pW32Job->ughCrt) {
RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING,
"UserHandleGrantAccess(FALSE): handle not found %#p",
hUserHandle);
}
#endif // DBG
}
retval = TRUE;
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
CLEANUPRECV();
LeaveCrit();
ExReleaseResourceLite(PsGetJobLock(Job));
KeLeaveCriticalRegion();
ObDereferenceObject(Job);
TRACE("NtUserUserHandleGrantAccess");
return retval;
}
HWND NtUserCreateWindowEx(
IN DWORD dwExStyle,
IN PLARGE_STRING pstrNVClassName,
IN PLARGE_STRING pstrClassName,
IN PLARGE_STRING pstrWindowName OPTIONAL,
IN DWORD dwStyle,
IN int x,
IN int y,
IN int nWidth,
IN int nHeight,
IN HWND hwndParent,
IN HMENU hmenu,
IN HANDLE hModule,
IN LPVOID pParam,
IN DWORD dwFlags,
IN PACTIVATION_CONTEXT pActCtx)
{
LARGE_STRING strNVClassName;
LARGE_STRING strClassName;
LARGE_STRING strWindowName;
PWND pwndParent;
PMENU pmenu;
TL tlpwndParent;
TL tlpMenu;
BOOL fLockMenu = FALSE;
PTHREADINFO ptiCurrent;
BEGINRECV(HWND, NULL);
if (hwndParent != HWND_MESSAGE) {
ValidateHWNDOPT(pwndParent, hwndParent);
} else {
pwndParent = _GetMessageWindow();
}
/*
* Win3.1 only checks for WS_CHILD before treating pmenu as an id. This
* is a bug, because throughout the code, the real check is TestwndChild(),
* which checks (style & (WS_CHILD | WS_POPUP)) == WS_CHILD. This is
* because old style "iconic popup" is WS_CHILD | WS_POPUP. So... if on
* win3.1 an app used ws_iconicpopup, menu validation would not occur
* (could crash if hmenu != NULL). On Win32, check for the real thing -
* but allow NULL!
*/
ptiCurrent = PtiCurrent();
if (((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) &&
(hmenu != NULL)) {
ValidateHMENU(pmenu, hmenu);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
fLockMenu = TRUE;
} else {
pmenu = (PMENU)hmenu;
}
/*
* Mask out the new 5.0 extended style bits for apps
* that would try to use them and we'll fail in xxxCreateWindowEx
*/
if (GetAppCompatFlags2(VER40) & GACF2_NO50EXSTYLEBITSCW) {
#if DBG
if (dwExStyle & ~(WS_EX_VALID40 | WS_EX_INTERNAL)) {
RIPMSG0(RIP_WARNING, "CreateWindowEx: appcompat removed 5.0 EX bits");
}
#endif
dwExStyle &= (WS_EX_VALID40 | WS_EX_INTERNAL);
}
if ((dwExStyle & (WS_EX_ALLVALID | WS_EX_INTERNAL)) != dwExStyle) {
RIPMSG0(RIP_WARNING, "CreateWindowEx: enforced not using private bits");
/*
* NOTE: Because WS_EX_ANSICREATOR is a reused bit, we actually need to
* check for valid | internal instead of turning off the private bits.
*
* It is very important for us to do this because we need to ensure that
* certain bits are not set, such as WS_EXP_COMPOSITING or
* WS_EXP_REDIRECTED because we can fault if this bits were set without
* properly setting up their accompanying data.
*/
dwExStyle &= WS_EX_ALLVALID | WS_EX_INTERNAL;
}
/*
* Probe arguments
*/
try {
#if defined(_X86_)
if (IS_PTR(pstrNVClassName)) {
strNVClassName = ProbeAndReadLargeString(pstrNVClassName);
ProbeForRead(strNVClassName.Buffer, strNVClassName.Length,
sizeof(BYTE));
pstrNVClassName = &strNVClassName;
}
if (IS_PTR(pstrClassName)) {
strClassName = ProbeAndReadLargeString(pstrClassName);
ProbeForRead(strClassName.Buffer, strClassName.Length,
sizeof(BYTE));
pstrClassName = &strClassName;
}
if (ARGUMENT_PRESENT(pstrWindowName)) {
strWindowName = ProbeAndReadLargeString(pstrWindowName);
ProbeForRead(strWindowName.Buffer, strWindowName.Length,
sizeof(BYTE));
pstrWindowName = &strWindowName;
}
#else
if (IS_PTR(pstrNVClassName)) {
strNVClassName = ProbeAndReadLargeString(pstrNVClassName);
ProbeForRead(strNVClassName.Buffer, strNVClassName.Length,
sizeof(WORD));
pstrNVClassName = &strNVClassName;
}
if (IS_PTR(pstrClassName)) {
strClassName = ProbeAndReadLargeString(pstrClassName);
ProbeForRead(strClassName.Buffer, strClassName.Length,
sizeof(WORD));
pstrClassName = &strClassName;
}
if (ARGUMENT_PRESENT(pstrWindowName)) {
strWindowName = ProbeAndReadLargeString(pstrWindowName);
ProbeForRead(strWindowName.Buffer, strWindowName.Length,
(strWindowName.bAnsi ? sizeof(BYTE) : sizeof(WORD)));
pstrWindowName = &strWindowName;
}
#endif
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
ThreadLockWithPti(ptiCurrent, pwndParent, &tlpwndParent);
/*
* The buffers for ClassName and WindowName are still in client space.
*/
retval = (HWND)xxxCreateWindowEx(
dwExStyle,
pstrNVClassName,
pstrClassName,
pstrWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
pwndParent,
pmenu,
hModule,
pParam,
dwFlags,
pActCtx);
retval = PtoH((PVOID)retval);
ThreadUnlock(&tlpwndParent);
CLEANUPRECV();
if (fLockMenu)
ThreadUnlock(&tlpMenu);
TRACE("NtUserCreateWindowEx");
ENDRECV();
}
NTSTATUS NtUserBuildHwndList( // worker for EnumWindows, EnumThreadWindows etc.
IN HDESK hdesk,
IN HWND hwndNext,
IN BOOL fEnumChildren,
IN DWORD idThread,
IN UINT cHwndMax,
OUT HWND *phwndFirst,
OUT PUINT pcHwndNeeded)
{
PWND pwndNext;
PDESKTOP pdesk;
PBWL pbwl;
PTHREADINFO pti;
UINT cHwndNeeded;
UINT wFlags = BWL_ENUMLIST;
WIN32_OPENMETHOD_PARAMETERS OpenParams;
BEGINATOMICRECV(NTSTATUS, STATUS_INVALID_HANDLE);
if (IS_IME_ENABLED()) {
// special treatment of IME Window
wFlags |= BWL_ENUMIMELAST;
}
/*
* Validate prior to referencing the desktop
*/
ValidateHWNDOPT(pwndNext, hwndNext);
if (idThread) {
pti = PtiFromThreadId(idThread);
if (pti == NULL || pti->rpdesk == NULL) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
pwndNext = pti->rpdesk->pDeskInfo->spwnd->spwndChild;
} else {
pti = NULL;
}
if (hdesk) {
retval = ValidateHdesk(hdesk, UserMode, DESKTOP_READOBJECTS, &pdesk);
if (!NT_SUCCESS(retval)) {
MSGERROR(ERROR_INVALID_HANDLE);
}
OpenParams.GrantedAccess = 0;
OpenParams.HandleCount = 0;
OpenParams.Object = pdesk;
OpenParams.OpenReason = ObOpenHandle;
OpenParams.Process = PsGetCurrentProcess();
retval = MapDesktop(&OpenParams);
if (!NT_SUCCESS(retval)) {
errret = retval;
MSGERROR(ERROR_INVALID_HANDLE);
}
pwndNext = pdesk->pDeskInfo->spwnd->spwndChild;
} else {
pdesk = NULL;
}
if (pwndNext == NULL) {
/*
* Windows NT Bug #262004.
* If we have a valid desk (just no windows on it), then we need to
* fall through. Otherwise, we'll just grab the current desktop and
* enum its windows!
*/
if (pdesk == NULL) {
if (pti != NULL) {
pwndNext = pti->rpdesk->pDeskInfo->spwnd->spwndChild;
} else {
pwndNext = _GetDesktopWindow()->spwndChild;
}
}
} else {
if (fEnumChildren) {
wFlags |= BWL_ENUMCHILDREN;
pwndNext = pwndNext->spwndChild;
}
}
if ((pbwl = BuildHwndList(pwndNext, wFlags, pti)) == NULL) {
MSGERRORCLEANUP(ERROR_NOT_ENOUGH_MEMORY);
}
cHwndNeeded = (UINT)(pbwl->phwndNext - pbwl->rghwnd) + 1;
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(phwndFirst, cHwndMax, sizeof(DWORD));
ProbeForWriteUlong(pcHwndNeeded);
/*
* If we have enough space, copy out list of hwnds to user mode buffer.
*/
if (cHwndNeeded <= cHwndMax) {
RtlCopyMemory(phwndFirst, pbwl->rghwnd, cHwndNeeded * sizeof(HWND));
retval = STATUS_SUCCESS;
} else {
retval = STATUS_BUFFER_TOO_SMALL;
}
*pcHwndNeeded = cHwndNeeded;
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0); // phwndFirst/pcHwndNeeded are USER's, not app's
}
CLEANUPRECV();
if (pbwl != NULL) {
FreeHwndList(pbwl);
}
if (pdesk != NULL) {
LogDesktop(pdesk, LD_DEREF_VALIDATE_HDESK4, FALSE, (ULONG_PTR)PtiCurrent());
ObDereferenceObject(pdesk);
}
TRACE("NtUserBuildHwndList");
ENDATOMICRECV();
}
NTSTATUS NtUserBuildPropList( // worker for EnumProps etc.
IN HWND hwnd,
IN UINT cPropMax,
OUT PPROPSET pPropSet,
OUT PUINT pcPropNeeded)
{
BEGINRECV_HWNDLOCK(NTSTATUS, STATUS_INVALID_HANDLE, hwnd);
if (cPropMax == 0) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(pPropSet, cPropMax, sizeof(DWORD));
ProbeForWriteUlong(pcPropNeeded);
retval = _BuildPropList(
pwnd,
pPropSet,
cPropMax,
pcPropNeeded);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0); // pPropSet/pcPropNeed are USER's, not app's
}
TRACE("NtUserBuildPropList");
ENDRECV_HWNDLOCK();
}
NTSTATUS NtUserBuildNameList( // worker for EnumWindowStations/EnumDesktops
IN HWINSTA hwinsta,
IN UINT cbNameList,
OUT PNAMELIST ccxpNameList,
OUT PUINT pcbNeeded)
{
UINT cbNeeded;
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(NTSTATUS, STATUS_INVALID_HANDLE);
if (cbNameList < sizeof(NAMELIST)) {
MSGERROR(0);
}
try {
ProbeForWriteUlong(pcbNeeded);
ProbeForWrite(ccxpNameList, cbNameList, sizeof(DWORD));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
if (hwinsta != NULL) {
retval = ValidateHwinsta(hwinsta, UserMode, WINSTA_ENUMDESKTOPS, &pwinsta);
} else {
retval = STATUS_SUCCESS;
pwinsta = NULL;
}
if (!NT_SUCCESS(retval)) {
try {
*ccxpNameList->awchNames = 0;
ccxpNameList->cb = 1;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
} else {
retval = _BuildNameList(pwinsta, ccxpNameList, cbNameList, &cbNeeded);
try {
*pcbNeeded = cbNeeded;
} except (StubExceptionHandler(FALSE)) {
retval = STATUS_ACCESS_VIOLATION;
}
if (pwinsta != NULL) {
ObDereferenceObject(pwinsta);
}
}
TRACE("NtUserBuildNameList");
ENDRECV_SHARED();
}
HKL NtUserActivateKeyboardLayout(
IN HKL hkl,
IN UINT Flags)
{
BEGINRECV(HKL, NULL);
/*
* Prevent restricted threads from setting the keyboard layout
* for the entire system.
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_HANDLES)) {
MSGERROR(0);
}
retval = xxxActivateKeyboardLayout(_GetProcessWindowStation(NULL),
hkl,
Flags,
NULL);
TRACE("NtUserActivateKeyboardLayout");
ENDRECV();
}
NTSTATUS GetSymbolicLink(
OUT PUNICODE_STRING pLinkTarget,
IN PCWSTR pSymbolicLink)
{
NTSTATUS Status;
HANDLE hLinkHandle;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING RootString;
UNICODE_STRING RootValue;
PVOID pRootValueBuffer = UserAllocPool(MAX_PATH * sizeof(WCHAR), TAG_KBDLAYOUT);
if (pRootValueBuffer == NULL) {
return STATUS_NO_MEMORY;
}
RtlInitUnicodeString(&RootString,
pSymbolicLink);
InitializeObjectAttributes(&oa,
&RootString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenSymbolicLinkObject(&hLinkHandle,
GENERIC_READ,
&oa);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING,
"GetSymbolicLink: Failed to open symbolic link. Got status=%x.",
Status);
goto exit;
}
RootValue.Buffer = pRootValueBuffer;
RootValue.Length = 0;
RootValue.MaximumLength = (USHORT)MAX_PATH * sizeof(WCHAR);
Status = ZwQuerySymbolicLinkObject(hLinkHandle, &RootValue, NULL);
ZwClose(hLinkHandle);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING,
"GetSymbolicLink: Failed to query symbolic link. Got status=%x.",
Status);
goto exit;
}
RtlCopyUnicodeString(pLinkTarget, &RootValue);
exit:
if (pRootValueBuffer) {
UserFreePool(pRootValueBuffer);
}
return Status;
}
NTSTATUS GetWindowsDirectoryDevicePath(
OUT PUNICODE_STRING pWindir)
{
NTSTATUS Status;
PWCHAR pSlash = NULL, pFixUp;
UNICODE_STRING RootValue;
UNICODE_STRING PathValue;
PVOID pRootValueBuffer = UserAllocPool(MAX_PATH * sizeof(WCHAR), TAG_KBDLAYOUT);
PVOID pPathValueBuffer = UserAllocPool(MAX_PATH * sizeof(WCHAR), TAG_KBDLAYOUT);
if ((pRootValueBuffer == NULL) || (pPathValueBuffer == NULL)) {
Status = STATUS_NO_MEMORY;
RIPMSGF1(RIP_WARNING,
"Failed to allocate memory. Got status=%x.",
Status);
goto exit;
}
RootValue.Buffer = pRootValueBuffer;
RootValue.Length = 0;
RootValue.MaximumLength = (USHORT)MAX_PATH * sizeof(WCHAR);
/*
* \SystemRoot is a SymbolicLink that will get us the name of the
* windows install directory. Much like %systemroot%\%windir% does.
*/
Status = GetSymbolicLink(&RootValue, L"\\SystemRoot");
if (!NT_SUCCESS(Status)) {
RIPMSGF1(RIP_WARNING,
"Failed to query \\SystemRoot. Got status=%x.",
Status);
goto exit;
}
/*
* \SystemRoot returns in the form "\Device\Harddisk1\Partition1\WINDOWS".
* We need to convert to \Device\HarddiskVolume3\WINDOWS form by converting
* the "\Device\Harddisk1\Partition1" SymbolicLink to the needed form so we
* can do our comparisons.
* We will walk the string backwards masking out a slash at a time as it is
* possible the windows directory is \WINDOWS\foo\xyz or anything the user
* has decided to make it. It is not always 1 level deep.
*/
PathValue.Buffer = pPathValueBuffer;
PathValue.Length = 0;
PathValue.MaximumLength = (USHORT)MAX_PATH * sizeof(WCHAR);
do {
pFixUp = pSlash;
pSlash = wcsrchr(RootValue.Buffer, L'\\');
if (pFixUp != NULL) {
pFixUp[0] = L'\\';
}
if (pSlash) {
pSlash[0] = L'\0';
Status = GetSymbolicLink(&PathValue, RootValue.Buffer);
if (NT_SUCCESS(Status)) {
pSlash[0] = L'\\';
RtlAppendUnicodeToString(&PathValue, pSlash);
RtlCopyUnicodeString(pWindir, &PathValue);
goto exit;
}
}
} while (pSlash != NULL);
exit:
if (pRootValueBuffer) {
UserFreePool(pRootValueBuffer);
}
if (pPathValueBuffer) {
UserFreePool(pPathValueBuffer);
}
return Status;
}
HANDLE ConvertHandleAndVerifyLoc(
HANDLE hFile)
{
HANDLE hSafeFile = NULL;
NTSTATUS Status;
PFILE_OBJECT pFileObject = NULL;
ULONG ulRetNameLength;
BYTE bNameBuffer[(MAX_PATH * sizeof(WCHAR)) + sizeof(OBJECT_NAME_INFORMATION)];
POBJECT_NAME_INFORMATION pFileNameInfo = (POBJECT_NAME_INFORMATION)bNameBuffer;
PUNICODE_STRING pNameBuffer = (PUNICODE_STRING)&bNameBuffer;
UNICODE_STRING LinkValue;
PVOID pLinkValueBuffer = UserAllocPool(MAX_PATH * sizeof(WCHAR), TAG_KBDLAYOUT);
if (pLinkValueBuffer == NULL) {
Status = STATUS_NO_MEMORY;
goto exit;
}
if (hFile) {
/*
* This will get a pointer to the object, Verify that the user has
* read access and that the object is a file handle.
*/
Status = ObReferenceObjectByHandle(hFile,
FILE_READ_DATA,
*IoFileObjectType,
UserMode,
&pFileObject,
NULL);
if (!NT_SUCCESS(Status)) {
RIPMSGF2(RIP_WARNING,
"Failed to convert handle %x. Got status=%x.",
hFile,
Status);
goto exit;
}
/*
* Lets get the name of the file. The value returned is of the form
* "\Device\HarddiskVolume3\WINDOWS\system32\kbdus.dll"
*/
Status = ObQueryNameString(pFileObject,
pFileNameInfo,
sizeof(bNameBuffer),
&ulRetNameLength);
if (!NT_SUCCESS(Status)) {
RIPMSGF2(RIP_WARNING,
"Failed to query info for %p. Got status=%x.",
pFileObject,
Status);
goto exit;
}
LinkValue.Buffer = pLinkValueBuffer;
LinkValue.Length = 0;
LinkValue.MaximumLength = (USHORT)MAX_PATH * sizeof(WCHAR);
/*
* Now lets get the windows directory path so we can match this
* with pFileNameInfo's value and make sure we are in the windows
* directory.
*/
Status = GetWindowsDirectoryDevicePath(&LinkValue);
if (!NT_SUCCESS(Status)) {
RIPMSGF1(RIP_WARNING,
"Failed to query \\SystemRoot. Got status=%x.",
Status);
goto exit;
}
#if defined(_WIN64)
if (PtiCurrent()->TIF_flags & TIF_WOW64) {
RtlAppendUnicodeToString(&LinkValue, L"\\SysWOW64");
} else
#endif
{
RtlAppendUnicodeToString(&LinkValue, L"\\system32");
}
if (_wcsnicmp(pFileNameInfo->Name.Buffer, LinkValue.Buffer, LinkValue.Length / sizeof(WCHAR))) {
RIPMSGF1(RIP_WARNING,
"Specifed hFile %S is not in a secure location.",
pFileNameInfo->Name.Buffer);
Status = STATUS_INVALID_PARAMETER_1;
goto exit;
}
/*
* We have passed the location check so lets go ahead and open a
* kernel handle that we can use later to map the view.
*/
Status = ObOpenObjectByPointer(pFileObject,
OBJ_KERNEL_HANDLE,
NULL,
FILE_READ_DATA,
*IoFileObjectType,
KernelMode,
&hSafeFile);
if (!NT_SUCCESS(Status)) {
RIPMSGF2(RIP_WARNING,
"Failed to get handle for %p. Got status=%x.",
pFileObject,
Status);
goto exit;
}
}
goto exit;
exit:
if (pLinkValueBuffer != NULL) {
UserFreePool(pLinkValueBuffer);
}
if (pFileObject) {
ObDereferenceObject(pFileObject);
}
return hSafeFile;
}
HKL NtUserLoadKeyboardLayoutEx(
IN HANDLE hFile,
IN DWORD offTable,
IN PKBDTABLE_MULTI_INTERNAL pKbdTableMulti,
IN HKL hkl,
IN PUNICODE_STRING pstrKLID,
IN UINT KbdInputLocale,
IN UINT Flags)
{
UNICODE_STRING strKLID;
PWINDOWSTATION pwinsta;
WCHAR awchKF[KL_NAMELENGTH];
UINT chMax;
KBDTABLE_MULTI_INTERNAL kbdTableMulti;
HANDLE hSafeFile = NULL;
UINT i;
BEGINRECV(HKL, NULL);
TESTFLAGS(Flags, KLF_VALID);
RtlZeroMemory(&kbdTableMulti, sizeof(KBDTABLE_MULTI_INTERNAL));
pwinsta = _GetProcessWindowStation(NULL);
/*
* Probe arguments
*/
try {
strKLID = ProbeAndReadUnicodeString(pstrKLID);
ProbeForRead(strKLID.Buffer, strKLID.Length, CHARALIGN);
chMax = min(sizeof(awchKF) - sizeof(WCHAR), strKLID.Length) / sizeof(WCHAR);
wcsncpy(awchKF, strKLID.Buffer, chMax);
awchKF[chMax] = 0;
if (pKbdTableMulti) {
kbdTableMulti = ProbeAndReadStructure(pKbdTableMulti, KBDTABLE_MULTI_INTERNAL);
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
hSafeFile = ConvertHandleAndVerifyLoc(hFile);
if (pKbdTableMulti && hSafeFile != NULL) {
if (kbdTableMulti.multi.nTables >= KBDTABLE_MULTI_MAX) {
RIPMSGF1(RIP_WARNING,
"pKbdTableMulti.multi.nTables too large: %x",
kbdTableMulti.multi.nTables);
kbdTableMulti.multi.nTables = 0;
MSGERRORCLEANUP(ERROR_INVALID_PARAMETER);
} else if (kbdTableMulti.multi.nTables > 0) {
for (i = 0; i < kbdTableMulti.multi.nTables; i++) {
kbdTableMulti.files[i].hFile = ConvertHandleAndVerifyLoc(kbdTableMulti.files[i].hFile);
if (kbdTableMulti.files[i].hFile == NULL) {
RIPMSGF2(RIP_WARNING,
"Failed to Convert KbdTableMulti[%x].hFile and nTables is %x.",
i,
kbdTableMulti.multi.nTables);
break;
}
}
kbdTableMulti.multi.nTables = i;
}
}
pKbdTableMulti = &kbdTableMulti;
retval = xxxLoadKeyboardLayoutEx(pwinsta,
hSafeFile,
hkl,
offTable,
pKbdTableMulti,
awchKF,
KbdInputLocale,
Flags);
CLEANUPRECV();
if (hSafeFile != NULL) {
ZwClose(hSafeFile);
for (i = 0; i < kbdTableMulti.multi.nTables; i++) {
if (kbdTableMulti.files[i].hFile != NULL) {
ZwClose(kbdTableMulti.files[i].hFile);
}
}
}
TRACE("NtUserLoadKeyboardLayoutEx");
ENDRECV();
}
BOOL NtUserUnloadKeyboardLayout(
IN HKL hkl)
{
BEGINRECV(BOOL, FALSE);
retval = xxxUnloadKeyboardLayout(
_GetProcessWindowStation(NULL),
hkl);
TRACE("NtUserUnloadKeyboardLayout");
ENDRECV();
}
BOOL NtUserSetSystemMenu(
IN HWND hwnd,
IN HMENU hmenu)
{
PMENU pmenu;
TL tlpMenu;
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
ValidateHMENU(pmenu, hmenu);
ThreadLockAlwaysWithPti(ptiCurrent, pmenu, &tlpMenu);
retval = xxxSetSystemMenu(pwnd, pmenu);
ThreadUnlock(&tlpMenu);
TRACE("NtUserSetSystemMenu");
ENDRECV_HWNDLOCK();
}
BOOL NtUserDragDetect(
IN HWND hwnd,
IN POINT pt)
{
BEGINRECV_HWNDLOCK(DWORD, 0, hwnd);
retval = xxxDragDetect(pwnd, pt);
TRACE("NtUserDragDetect");
ENDRECV_HWNDLOCK();
}
UINT_PTR NtUserSetSystemTimer(
IN HWND hwnd,
IN UINT_PTR nIDEvent,
IN DWORD dwElapse,
IN WNDPROC pTimerFunc)
{
BEGINRECV_HWND(UINT_PTR, 0, hwnd);
UNREFERENCED_PARAMETER(pTimerFunc);
retval = _SetSystemTimer(pwnd,
nIDEvent,
dwElapse,
NULL);
TRACE("NtUserSetSystemTimer");
ENDRECV_HWND();
}
BOOL NtUserQuerySendMessage( // private QuerySendMessage
OUT PMSG pmsg OPTIONAL)
{
PSMS psms;
BEGINRECV_SHARED(BOOL, FALSE);
if ((psms = PtiCurrentShared()->psmsCurrent) == NULL) {
MSGERROR(0);
}
retval = TRUE;
if (ARGUMENT_PRESENT(pmsg)) {
try {
ProbeForWriteMessage(pmsg);
pmsg->hwnd = HW(psms->spwnd);
pmsg->message = psms->message;
pmsg->wParam = psms->wParam;
pmsg->lParam = psms->lParam;
pmsg->time = psms->tSent;
pmsg->pt.x = 0;
pmsg->pt.y = 0;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("NtUserQuerySendMessage");
ENDRECV_SHARED();
}
UINT NtUserSendInput(
IN UINT cInputs,
IN CONST INPUT *pInputs,
IN int cbSize)
{
LPINPUT pInput2 = NULL;
PTHREADINFO ptiCurrent;
TL tlInput;
BEGINRECV(UINT, 0);
if (sizeof(INPUT) != cbSize || cInputs == 0) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
ptiCurrent = PtiCurrent();
/*
* Probe arguments
*/
try {
ProbeForReadBuffer(pInputs, cInputs, DATAALIGN);
pInput2 = UserAllocPoolWithQuota(cInputs * sizeof(*pInputs), TAG_SENDINPUT);
if (pInput2 == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
RtlCopyMemory(pInput2, pInputs, cInputs * sizeof(*pInputs));
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
ThreadLockPool(ptiCurrent, pInput2, &tlInput);
retval = xxxSendInput(cInputs, pInput2);
ThreadUnlockPool(ptiCurrent, &tlInput);
CLEANUPRECV();
if (pInput2) {
UserFreePool(pInput2);
}
TRACE("NtUserSendInput");
ENDRECV();
}
UINT NtUserBlockInput(
IN BOOL fBlockIt)
{
BEGINATOMICRECV(BOOL, FALSE);
retval = _BlockInput(fBlockIt);
TRACE("NtUserBlockInput");
ENDATOMICRECV();
}
BOOL NtUserImpersonateDdeClientWindow(
IN HWND hwndClient,
IN HWND hwndServer)
{
PWND pwndServer;
BEGINATOMICRECV_HWND(BOOL, FALSE, hwndClient);
ValidateHWND(pwndServer, hwndServer);
if (GETPTI(pwndServer) != PtiCurrent()) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
MSGERROR(0);
}
if (GETPWNDPPI(pwnd) == GETPWNDPPI(pwndServer)) {
retval = TRUE; // impersonating self is a NOOP
} else {
retval = _ImpersonateDdeClientWindow(pwnd, pwndServer);
}
TRACE("NtUserImpersonateDdeClientWindow");
ENDATOMICRECV_HWND();
}
ULONG_PTR NtUserGetCPD(
IN HWND hwnd,
IN DWORD options,
IN ULONG_PTR dwData)
{
BEGINRECV_HWND(ULONG_PTR, 0, hwnd);
switch (options & ~CPD_TRANSITION_TYPES) {
case CPD_WND:
case CPD_DIALOG:
case CPD_WNDTOCLS:
break;
default:
RIPMSG1(RIP_WARNING, "GetCPD: Invalid options %x", options);
MSGERROR(0);
}
retval = GetCPD(pwnd, options, dwData);
TRACE("NtUserGetCPD");
ENDRECV_HWND();
}
int NtUserCopyAcceleratorTable( // API CopyAcceleratorTableA/W
IN HACCEL hAccelSrc,
IN OUT LPACCEL lpAccelDst OPTIONAL,
IN int cAccel)
{
LPACCELTABLE pat;
int i;
BEGINATOMICRECV(int, 0);
ValidateHACCEL(pat, hAccelSrc);
if (lpAccelDst == NULL) {
retval = pat->cAccel;
} else {
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(lpAccelDst, cAccel, DATAALIGN);
if (cAccel > (int)pat->cAccel)
cAccel = pat->cAccel;
retval = cAccel;
for (i = 0; i < cAccel; i++) {
RtlCopyMemory(&lpAccelDst[i], &pat->accel[i], sizeof(ACCEL));
lpAccelDst[i].fVirt &= ~FLASTKEY;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserCopyAcceleratorTable");
ENDATOMICRECV();
}
HWND NtUserFindWindowEx( // API FindWindowA/W, FindWindowExA/W
IN HWND hwndParent,
IN HWND hwndChild,
IN PUNICODE_STRING pstrClassName,
IN PUNICODE_STRING pstrWindowName,
DWORD dwType)
{
UNICODE_STRING strClassName;
UNICODE_STRING strWindowName;
PWND pwndParent, pwndChild;
BEGINATOMICRECV(HWND, NULL);
if (hwndParent != HWND_MESSAGE) {
ValidateHWNDOPT(pwndParent, hwndParent);
} else {
pwndParent = _GetMessageWindow();
}
ValidateHWNDOPT(pwndChild, hwndChild);
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pstrClassName);
strWindowName = ProbeAndReadUnicodeString(pstrWindowName);
ProbeForReadUnicodeStringBufferOrId(strClassName);
ProbeForReadUnicodeStringBuffer(strWindowName);
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
/*
* Use of both buffers is protected by try/except clauses in the code.
*/
retval = (HWND)_FindWindowEx(
pwndParent,
pwndChild,
strClassName.Buffer,
strWindowName.Buffer,
dwType);
retval = PtoH((PVOID)retval);
CLEANUPRECV();
TRACE("NtUserFindWindowEx");
ENDATOMICRECV();
}
BOOL NtUserGetClassInfoEx( // API GetClassInfoA/W
IN HINSTANCE hInstance OPTIONAL,
IN PUNICODE_STRING pstrClassName,
IN OUT LPWNDCLASSEXW lpWndClass,
OUT LPWSTR *ppszMenuName,
IN BOOL bAnsi)
{
UNICODE_STRING strClassName;
LPWSTR pszMenuName;
WNDCLASSEXW wc;
BEGINRECV(BOOL, FALSE);
#ifdef LAZY_CLASS_INIT
if ((PtiCurrent()->ppi->W32PF_Flags & W32PF_CLASSESREGISTERED) == 0) {
if (!LW_RegisterWindows()) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
}
#endif
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pstrClassName);
/*
* The class name may either be a string or an atom. Only
* probe strings.
*/
ProbeForReadUnicodeStringBufferOrId(strClassName);
ProbeForWrite(lpWndClass, sizeof(*lpWndClass), DATAALIGN);
ProbeForWriteUlong((PULONG)ppszMenuName);
RtlCopyMemory(&wc, lpWndClass, sizeof(WNDCLASSEXW));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* The class name buffer is client-side.
*/
retval = _GetClassInfoEx(hInstance,
(LPTSTR)strClassName.Buffer,
&wc,
&pszMenuName,
bAnsi);
if (retval) {
try {
RtlCopyMemory(lpWndClass, &wc, sizeof(WNDCLASSEXW));
*ppszMenuName = pszMenuName;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetClassInfo");
ENDRECV();
}
/*
* gaFNIDtoICLS is used only in NtUserGetClassName and should be in sync with
* the values from user.h
* ICLS_MAX is an unused value
*/
CONST BYTE gaFNIDtoICLS[] = {
// FNID-START
ICLS_SCROLLBAR, // FNID_SCROLLBAR
ICLS_ICONTITLE, // FNID_ICONTITLE
ICLS_MENU, // FNID_MENU
ICLS_DESKTOP, // FNID_DESKTOP
ICLS_MAX, // FNID_DEFWINDOWPROC
ICLS_MAX, // FNID_MESSAGE
ICLS_SWITCH, // FNID_SWITCH
ICLS_BUTTON, // FNID_BUTTON
ICLS_COMBOBOX, // FNID_COMBOBOX
ICLS_COMBOLISTBOX, // FNID_COMBOLISTBOX
ICLS_DIALOG, // FNID_DIALOG
ICLS_EDIT, // FNID_EDIT
ICLS_LISTBOX, // FNID_LISTBOX
ICLS_MDICLIENT, // FNID_MDICLIENT
ICLS_STATIC, // FNID_STATIC
ICLS_IME, // FNID_IME
ICLS_MAX, // FNID_HKINLPCWPEXSTRUCT
ICLS_MAX, // FNID_HKINLPCWPRETEXSTRUCT
ICLS_MAX, // FNID_DEFFRAMEPROC
ICLS_MAX, // FNID_DEFMDICHILDPROC
ICLS_MAX, // FNID_MB_DLGPROC
ICLS_MAX, // FNID_MDIACTIVATEDLGPROC
ICLS_MAX, // FNID_SENDMESSAGE
ICLS_MAX, // FNID_SENDMESSAGEFF
ICLS_MAX, // FNID_SENDMESSAGEEX
ICLS_MAX, // FNID_CALLWINDOWPROC
ICLS_MAX, // FNID_SENDMESSAGEBSM
ICLS_TOOLTIP, // FNID_TOOLTIP
ICLS_GHOST, // FNID_GHOST
ICLS_MAX, // FNID_SENDNOTIFYMESSAGE
ICLS_MAX // FNID_SENDMESSAGECALLBACK
}; // FNID_END
int NtUserGetClassName( // API GetClassNameA/W
IN HWND hwnd,
IN BOOL bReal,
IN OUT PUNICODE_STRING pstrClassName)
{
UNICODE_STRING strClassName;
ATOM atom;
BEGINRECV_HWND_SHARED(DWORD, 0, hwnd);
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pstrClassName);
#if defined(_X86_)
ProbeForWrite(strClassName.Buffer, strClassName.MaximumLength,
sizeof(BYTE));
#else
ProbeForWrite(strClassName.Buffer, strClassName.MaximumLength,
sizeof(WCHAR));
#endif
atom = pwnd->pcls->atomNVClassName;
UserAssert(ARRAY_SIZE(gaFNIDtoICLS) == FNID_END - FNID_START + 1);
if (bReal) {
DWORD dwFnid;
DWORD dwClass;
dwFnid = GETFNID(pwnd);
if (dwFnid) {
dwFnid -= FNID_START;
if (dwFnid < ARRAY_SIZE(gaFNIDtoICLS)) {
dwClass = gaFNIDtoICLS[dwFnid];
if (dwClass != ICLS_MAX) {
atom = gpsi->atomSysClass[dwClass];
}
}
}
}
retval = UserGetAtomName(
atom,
strClassName.Buffer,
strClassName.MaximumLength / sizeof(WCHAR));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetClassName");
ENDRECV_HWND_SHARED();
}
UINT NtUserGetAtomName(
IN ATOM atom,
IN OUT PUNICODE_STRING pstrAtomName)
{
UNICODE_STRING strAtomName;
BEGINRECV_SHARED(UINT, 0);
/*
* Probe arguments
*/
try {
strAtomName = ProbeAndReadUnicodeString(pstrAtomName);
#if defined(_X86_)
ProbeForWrite(strAtomName.Buffer, strAtomName.MaximumLength,
sizeof(BYTE));
#else
ProbeForWrite(strAtomName.Buffer, strAtomName.MaximumLength,
sizeof(WCHAR));
#endif
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = UserGetAtomName(
atom,
strAtomName.Buffer,
strAtomName.MaximumLength / sizeof(WCHAR));
TRACE("NtUserGetAtomName");
ENDRECV_SHARED();
}
int NtUserGetClipboardFormatName( // API GetclipboardFormatNameA/W
IN UINT format,
OUT LPWSTR lpszFormatName,
IN UINT chMax)
{
BEGINRECV_NOCRIT(int, 0);
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(lpszFormatName, chMax, CHARALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if ((ATOM)format < MAXINTATOM) {
MSGERROR(ERROR_INVALID_PARAMETER);
} else {
/*
* UserGetAtomName (actually RtlQueryAtomInAtomTable) protects access
* within a try block, and sets last error appropriately.
*/
retval = UserGetAtomName((ATOM)format, lpszFormatName, chMax);
}
TRACE("NtUserGetClipboardFormatName");
ENDRECV_NOCRIT();
}
int NtUserGetKeyNameText(
IN LONG lParam,
OUT LPWSTR lpszKeyName,
IN UINT chMax)
{
BEGINRECV_SHARED(int, 0);
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(lpszKeyName, chMax, CHARALIGN);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Note -- lpszKeyName is a client-side address. GetKeyNameText
* protects uses with try blocks, and sets last error accordingly.
*/
retval = _GetKeyNameText(
lParam,
lpszKeyName,
chMax);
TRACE("NtUserGetKeyNameText");
ENDRECV_SHARED();
}
BOOL NtUserGetKeyboardLayoutName(
IN OUT PUNICODE_STRING pstrKLID)
{
PTHREADINFO ptiCurrent;
PKL pklActive;
UNICODE_STRING strKLID;
BEGINRECV_SHARED(BOOL, FALSE);
ptiCurrent = PtiCurrentShared();
pklActive = ptiCurrent->spklActive;
if (pklActive == NULL) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
strKLID = ProbeAndReadUnicodeString(pstrKLID);
ProbeForWrite(strKLID.Buffer, strKLID.MaximumLength, CHARALIGN);
if (IS_IME_KBDLAYOUT(pklActive->hkl)) {
/*
* IME KL may have different KL name for the same layout file.
* Their KL name are really equivalent to HKL.
*/
RtlIntegerToUnicodeString(DOWNCAST(ULONG, pklActive->hkl), 0x10, &strKLID);
} else {
#if (KL_NAMELENGTH != 8 + 1)
#error unexpected KL_NAMELENGTH
#endif
if (strKLID.MaximumLength < KL_NAMELENGTH * sizeof(WCHAR) ||
!NT_SUCCESS(RtlIntegerToUnicode(pklActive->dwKLID, 0x10, -(KL_NAMELENGTH - 1), strKLID.Buffer))) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
strKLID.Length = (KL_NAMELENGTH - 1) * sizeof(WCHAR);
/*
* Make it NULL terminated.
*/
strKLID.Buffer[KL_NAMELENGTH - 1] = L'\0';
}
retval = TRUE;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserGetKeyboardLayoutName");
ENDRECV_SHARED();
}
UINT NtUserGetKeyboardLayoutList(
IN UINT nItems,
OUT HKL *lpBuff)
{
PWINDOWSTATION pwinsta;
BEGINRECV_SHARED(UINT, 0);
/*
* Probe arguments
*/
try {
if (!lpBuff) {
nItems = 0;
}
ProbeForWriteBuffer(lpBuff, nItems, DATAALIGN);
pwinsta = _GetProcessWindowStation(NULL);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* Access to the client-side buffer lpBuff is protected by try/except
* inside _GetKeyboardLayoutList()
*/
retval = (DWORD)_GetKeyboardLayoutList(pwinsta, nItems, lpBuff);
TRACE("NtUserGetKeyboardLayoutList");
ENDRECV_SHARED();
}
UINT NtUserMapVirtualKeyEx(
IN UINT uCode,
IN UINT uMapType,
IN ULONG_PTR dwHKLorPKL,
IN BOOL bHKL)
{
PKL pkl;
BEGINRECV_SHARED(UINT, 0);
/*
* See if we need to convert an HKL to a PKL. MapVirtualKey passes a PKL and
* MapVirtualKeyEx passes an HKL. The conversion must be done in the kernel.
*/
if (bHKL) {
pkl = HKLtoPKL(PtiCurrentShared(), (HKL)dwHKLorPKL);
} else {
pkl = PtiCurrentShared()->spklActive;
}
if (pkl == NULL) {
retval = 0;
} else {
retval = InternalMapVirtualKeyEx(uCode, uMapType, pkl->spkf->pKbdTbl);
}
TRACE("NtUserMapVirtualKeyEx");
ENDRECV_SHARED();
}
ATOM NtUserRegisterClassExWOW(
IN WNDCLASSEX *lpWndClass,
IN PUNICODE_STRING pstrClassName,
IN PUNICODE_STRING pstrClassNameVer,
IN PCLSMENUNAME pcmn,
IN WORD fnid,
IN DWORD dwFlags,
IN LPDWORD pdwWOWstuff OPTIONAL)
{
UNICODE_STRING strClassName;
UNICODE_STRING strClassNameVer;
UNICODE_STRING strMenuName;
WNDCLASSVEREX WndClass;
WC WowCls;
CLSMENUNAME cmn;
BEGINRECV(ATOM, 0);
TESTFLAGS(dwFlags, CSF_VALID);
#ifdef LAZY_CLASS_INIT
if ((PtiCurrent()->ppi->W32PF_Flags & W32PF_CLASSESREGISTERED) == 0) {
if (!LW_RegisterWindows()) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
}
#endif
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pstrClassName);
strClassNameVer = ProbeAndReadUnicodeString(pstrClassNameVer);
cmn = ProbeAndReadStructure(pcmn, CLSMENUNAME);
strMenuName = ProbeAndReadUnicodeString(cmn.pusMenuName);
*((LPWNDCLASSEX)(&WndClass)) = ProbeAndReadStructure(lpWndClass, WNDCLASSEX);
ProbeForReadUnicodeStringBufferOrId(strClassName);
ProbeForReadUnicodeStringBufferOrId(strClassNameVer);
ProbeForReadUnicodeStringBufferOrId(strMenuName);
if (ARGUMENT_PRESENT(pdwWOWstuff)) {
ProbeForRead(pdwWOWstuff, sizeof(WC), sizeof(BYTE));
RtlCopyMemory(&WowCls, pdwWOWstuff, sizeof(WC));
pdwWOWstuff = (PDWORD)&WowCls;
}
WndClass.lpszClassName = strClassName.Buffer;
WndClass.lpszClassNameVer = strClassNameVer.Buffer;
WndClass.lpszMenuName = strMenuName.Buffer;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (WndClass.cbClsExtra < 0 || WndClass.cbWndExtra < 0 || WndClass.cbSize != sizeof(WNDCLASSEX)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
/*
* ClassName and MenuName in WndClass are client-side pointers.
*/
retval = _RegisterClassEx(&WndClass,
&cmn,
fnid,
dwFlags,
pdwWOWstuff);
TRACE("NtUserRegisterClassExWOW");
ENDRECV();
}
UINT NtUserRegisterWindowMessage(
IN PUNICODE_STRING pstrMessage)
{
UNICODE_STRING strMessage;
BEGINRECV_NOCRIT(UINT, 0);
/*
* Probe arguments
*/
try {
strMessage = ProbeAndReadUnicodeString(pstrMessage);
ProbeForReadUnicodeStringBuffer(strMessage);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* The buffer is in client-side memory.
* Rtl atom routines protect accesses to strings with their
* own try/except blocks, UserAddAtom sets last error accordingly.
*/
retval = UserAddAtom(
strMessage.Buffer, FALSE);
TRACE("NtUserRegisterWindowMessage");
ENDRECV_NOCRIT();
}
HANDLE NtUserRemoveProp(
IN HWND hwnd,
IN DWORD dwProp)
{
BEGINRECV_HWND(HANDLE, NULL, hwnd);
retval = InternalRemoveProp(pwnd, (LPWSTR)LOWORD(dwProp), FALSE);
TRACE("NtUserRemoveProp");
ENDRECV_HWND();
}
BOOL NtUserSetProp(
IN HWND hwnd,
IN DWORD dwProp,
IN HANDLE hData)
{
BEGINRECV_HWND(DWORD, 0, hwnd);
retval = InternalSetProp(pwnd,
(LPTSTR)LOWORD(dwProp),
hData,
HIWORD(dwProp) ? PROPF_STRING : 0);
TRACE("NtUserSetProp");
ENDRECV_HWND();
}
BOOL NtUserUnregisterClass( // API UnregisterClass
IN PUNICODE_STRING pstrClassName,
IN HINSTANCE hInstance,
OUT PCLSMENUNAME pcmn)
{
UNICODE_STRING strClassName;
CLSMENUNAME cmn;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
strClassName = ProbeAndReadUnicodeString(pstrClassName);
ProbeForReadUnicodeStringBufferOrId(strClassName);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
/*
* The buffer is in client-side memory.
*/
retval = _UnregisterClass(
strClassName.Buffer,
hInstance,
&cmn);
try {
ProbeAndWriteStructure(pcmn, cmn, CLSMENUNAME);
} except (StubExceptionHandler(FALSE)) {
// no SetLastError, since pcmn is a USER address, not the application's
}
TRACE("NtUserUnregisterClass");
ENDRECV();
}
SHORT NtUserVkKeyScanEx(
IN WCHAR cChar,
IN ULONG_PTR dwHKLorPKL,
IN BOOL bHKL)
{
PKL pkl;
BEGINRECV_SHARED(SHORT, -1);
/*
* See if we need to convert an HKL to a PKL. VkKeyScan passes a PKL and
* VkKeyScanEx passes an HKL. The conversion must be done on the server side.
*/
if (bHKL) {
pkl = HKLtoPKL(PtiCurrentShared(), (HKL)dwHKLorPKL);
} else {
pkl = PtiCurrentShared()->spklActive;
}
if (pkl == NULL) {
retval = (SHORT)-1;
} else {
retval = InternalVkKeyScanEx(cChar, pkl->spkf->pKbdTbl);
}
TRACE("NtUserVkKeyScanEx");
ENDRECV_SHARED();
}
NTSTATUS
NtUserEnumDisplayDevices(
IN PUNICODE_STRING pstrDeviceName,
IN DWORD iDevNum,
IN OUT LPDISPLAY_DEVICEW lpDisplayDevice,
IN DWORD dwFlags)
{
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* We need to syncrhonize with session switching from local to remote or
* remote to local while enumerating display settings. Use
* UserSessionSwitchEnterCrit() to ensure mutual exclusion with session
* switch code, but first leave the User critical section as
* UserSessionSwitchEnterCrit() does not expect to be held by the caller.
* On return from UserSessionSwitchEnterCrit() the critical section will be
* held.
*/
LeaveCrit();
retval = UserSessionSwitchEnterCrit();
if (retval != STATUS_SUCCESS) {
goto exit_api;
}
/*
* Update the list of devices. Do this only if connected to local console.
* If the function returns FALSE (retry update), then we must
* disable the current hdev, call back, and reanable the hdev.
*/
if (!IsRemoteConnection()) {
if (DrvUpdateGraphicsDeviceList(FALSE, FALSE, TRUE) == FALSE) {
if (SafeDisableMDEV()) {
DrvUpdateGraphicsDeviceList(TRUE, FALSE, TRUE);
SafeEnableMDEV();
/*
* Repaint the screen
*/
xxxUserResetDisplayDevice();
/*
* xxxUserResetDisplayDevice may have released and reaquiered the user critical section.
* We need to make sure again that no session switch has started during that window.
*/
LeaveCrit();
retval = UserSessionSwitchEnterCrit();
if (retval != STATUS_SUCCESS) {
goto exit_api;
}
}
}
}
/*
* Address checking, etc., occurs in GRE.
*/
retval = DrvEnumDisplayDevices(pstrDeviceName,
gpDispInfo->pMonitorPrimary->hDev,
iDevNum,
lpDisplayDevice,
dwFlags,
UserMode);
UserSessionSwitchLeaveCrit();
exit_api:
EnterCrit();
TRACE("NtUserEnumDisplayDevices");
ENDRECV();
}
NTSTATUS
NtUserEnumDisplaySettings(
IN PUNICODE_STRING pstrDeviceName,
IN DWORD iModeNum,
OUT LPDEVMODEW lpDevMode,
IN DWORD dwFlags)
{
BEGINRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
/*
* We need to synchronize with session switching from local to remote or
* remote to local while enumerating display settings. Use
* UserSessionSwitchEnterCrit() to ensure mutual exclusion with session
* switch code, but first leave the User critical section as
* UserSessionSwitchEnterCrit() does not expect to be held by the caller.
* On return from UserSessionSwitchEnterCrit() the critical section will be
* held.
*
* Address checking, etc., occurs in GRE.
*/
LeaveCrit();
retval = UserSessionSwitchEnterCrit();
if (retval != STATUS_SUCCESS) {
goto exit_api;
}
retval = DrvEnumDisplaySettings(pstrDeviceName,
gpDispInfo->pMonitorPrimary->hDev,
iModeNum,
lpDevMode,
dwFlags);
UserSessionSwitchLeaveCrit();
exit_api:
EnterCrit();
TRACE("NtUserEnumDisplaySettings");
ENDRECV();
}
#ifdef PRERELEASE
PTHREADINFO gptiLastChangedDisplaySettings;
#endif
LONG
NtUserChangeDisplaySettings(
IN PUNICODE_STRING pstrDeviceName,
IN LPDEVMODEW pDevMode,
IN DWORD dwFlags,
IN PVOID lParam)
{
BEGINRECV(LONG, DISP_CHANGE_FAILED);
/*
* Prevent restricted threads from changing display settings.
*/
if (IS_CURRENT_THREAD_RESTRICTED(JOB_OBJECT_UILIMIT_DISPLAYSETTINGS)) {
MSGERROR(0);
}
#ifdef PRERELEASE
/*
* Remember the last guy who tried to change the display settings
* (per the request from the shell team).
* N.b. it doesn't care if the call was succeeded or not.
*/
gptiLastChangedDisplaySettings = PtiCurrent();
#endif
/*
* Address checking, etc., occurs in GRE.
*/
retval = xxxUserChangeDisplaySettings(pstrDeviceName,
pDevMode,
NULL,
dwFlags,
lParam,
UserMode);
TRACE("NtUserChangeDisplaySettings");
ENDRECV();
}
BOOL NtUserCallMsgFilter( // API CallMsgFilterA/W
IN OUT LPMSG lpMsg,
IN int nCode)
{
MSG msg;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
try {
ProbeForWriteMessage(lpMsg);
msg = *lpMsg;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _CallMsgFilter(
&msg,
nCode);
try {
*lpMsg = msg;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
TRACE("NtUserCallMsgFilter");
ENDRECV();
}
int NtUserDrawMenuBarTemp( // private DrawMenuBarTemp
IN HWND hwnd,
IN HDC hdc,
IN LPCRECT lprc,
IN HMENU hMenu,
IN HFONT hFont)
{
PMENU pMenu;
TL tlpMenu;
RECT rc;
BEGINRECV_HWNDLOCK(int, 0, hwnd);
/*
* Probe and capture arguments.
*/
try {
rc = ProbeAndReadRect(lprc);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
ValidateHMENU(pMenu, hMenu);
ThreadLockAlwaysWithPti(ptiCurrent, pMenu, &tlpMenu);
retval = xxxDrawMenuBarTemp(
pwnd,
hdc,
&rc,
pMenu,
hFont);
ThreadUnlock(&tlpMenu);
TRACE("NtUserDrawMenuBarTemp");
ENDRECV_HWNDLOCK();
}
BOOL NtUserDrawCaptionTemp( // private DrawCaptionTempA/W
IN HWND hwnd,
IN HDC hdc,
IN LPCRECT lprc,
IN HFONT hFont,
IN HICON hIcon,
IN PUNICODE_STRING pstrText,
IN UINT flags)
{
PCURSOR pcur;
TL tlpcur;
RECT rc;
UNICODE_STRING strCapture;
PWND pwnd;
TL tlpwnd;
PTHREADINFO ptiCurrent;
TL tlBuffer;
BOOL fFreeBuffer = FALSE;
BEGINRECV(DWORD, FALSE);
ptiCurrent = PtiCurrent();
ValidateHWNDOPT(pwnd, hwnd);
ValidateHCURSOROPT(pcur, hIcon);
/*
* Probe and capture arguments. Capturing the text is ugly,
* but must be done because it is passed to GDI.
*/
try {
rc = ProbeAndReadRect(lprc);
strCapture = ProbeAndReadUnicodeString(pstrText);
if (strCapture.Buffer != NULL) {
PWSTR pszCapture = strCapture.Buffer;
ProbeForRead(strCapture.Buffer, strCapture.Length, CHARALIGN);
strCapture.Buffer = UserAllocPoolWithQuota(strCapture.Length+sizeof(UNICODE_NULL), TAG_TEXT);
if (strCapture.Buffer != NULL) {
fFreeBuffer = TRUE;
ThreadLockPool(ptiCurrent, strCapture.Buffer, &tlBuffer);
RtlCopyMemory(strCapture.Buffer, pszCapture, strCapture.Length);
strCapture.Buffer[strCapture.Length/sizeof(WCHAR)]=0; // null-terminate string
strCapture.MaximumLength = strCapture.Length+sizeof(UNICODE_NULL);
pstrText = &strCapture;
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
ThreadLockWithPti(ptiCurrent, pwnd, &tlpwnd);
ThreadLockWithPti(ptiCurrent, pcur, &tlpcur);
retval = xxxDrawCaptionTemp(
pwnd,
hdc,
&rc,
hFont,
pcur,
strCapture.Buffer ? &strCapture : NULL,
flags);
ThreadUnlock(&tlpcur);
ThreadUnlock(&tlpwnd);
CLEANUPRECV();
if (fFreeBuffer)
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
TRACE("NtUserDrawCaptionTemp");
ENDRECV();
}
BOOL NtUserGetKeyboardState( // API GetKeyboardState
OUT PBYTE pb)
{
int i;
PQ pq;
BEGINRECV_SHARED(SHORT, 0)
/*
* Probe arguments
*/
try {
ProbeForWrite(pb, 256, sizeof(BYTE));
pq = PtiCurrentShared()->pq;
for (i = 0; i < 256; i++, pb++) {
*pb = 0;
if (TestKeyStateDown(pq, i))
*pb |= 0x80;
if (TestKeyStateToggle(pq, i))
*pb |= 0x01;
}
retval = TRUE;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ENDRECV_SHARED();
}
SHORT NtUserGetKeyState(
IN int vk)
{
PTHREADINFO ptiCurrent;
BEGINRECV_SHARED(SHORT, 0)
ptiCurrent = PtiCurrentShared();
if (ptiCurrent->pq->QF_flags & QF_UPDATEKEYSTATE) {
/*
* We are going to change the system state, so we
* must have an exclusive lock
*/
ChangeAcquireResourceType();
/*
* If this thread needs a key state event, give one to it. There are
* cases where any app may be looping looking at GetKeyState(), plus
* calling PeekMessage(). Key state events don't get created unless
* new hardware input comes along. If the app isn't receiving hardware
* input, it won't get the new key state. So ResyncKeyState() will
* ensure that if the app is looping on GetKeyState(), it'll get the
* right key state.
*/
if (ptiCurrent->pq->QF_flags & QF_UPDATEKEYSTATE) {
PostUpdateKeyStateEvent(ptiCurrent->pq);
}
}
retval = _GetKeyState(vk);
/*
* Update the client side key state cache.
*/
try {
ptiCurrent->pClientInfo->dwKeyCache = gpsi->dwKeyCache;
RtlCopyMemory(ptiCurrent->pClientInfo->afKeyState,
ptiCurrent->pq->afKeyState,
CBKEYCACHE);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ENDRECV_SHARED();
}
/**************************************************************************\
* NtUserQueryWindow
*
* 03-18-95 JimA Created.
\**************************************************************************/
HANDLE NtUserQueryWindow(
IN HWND hwnd,
IN WINDOWINFOCLASS WindowInfo)
{
PTHREADINFO ptiWnd;
BEGINRECV_HWND_SHARED(HANDLE, NULL, hwnd);
ptiWnd = GETPTI(pwnd);
switch (WindowInfo) {
case WindowProcess:
/*
* Special case console windows
*/
if (ptiWnd->TIF_flags & TIF_CSRSSTHREAD &&
pwnd->pcls->atomClassName == gatomConsoleClass) {
retval = LongToHandle(_GetWindowLong(pwnd, 0));
} else {
retval = PsGetThreadProcessId(ptiWnd->pEThread);
}
break;
case WindowThread:
/*
* Special case console windows
*/
if (ptiWnd->TIF_flags & TIF_CSRSSTHREAD &&
pwnd->pcls->atomClassName == gatomConsoleClass) {
retval = LongToHandle(_GetWindowLong(pwnd, 4));
} else {
retval = GETPTIID(ptiWnd);
}
break;
case WindowActiveWindow:
retval = (HANDLE)HW(ptiWnd->pq->spwndActive);
break;
case WindowFocusWindow:
retval = (HANDLE)HW(ptiWnd->pq->spwndFocus);
break;
case WindowIsHung:
/*
* If the window is a ghost window, report that the window is hung.
*/
if ((GETFNID(pwnd) == FNID_GHOST)) {
retval = LongToHandle(TRUE);
} else {
retval = LongToHandle(FHungApp(ptiWnd, CMSHUNGAPPTIMEOUT));
}
break;
case WindowIsForegroundThread:
retval = LongToHandle(ptiWnd->pq == gpqForeground);
break;
case WindowDefaultImeWindow:
retval = HW(ptiWnd->spwndDefaultIme);
break;
case WindowDefaultInputContext:
retval = PtoH(ptiWnd->spDefaultImc);
break;
default:
RIPMSG1(RIP_WARNING,
"QueryWindow called with invalid index 0x%x",
WindowInfo);
retval = (HANDLE)NULL;
break;
}
ENDRECV_HWND_SHARED();
}
BOOL NtUserSBGetParms( // API GetScrollInfo, SBM_GETSCROLLINFO
IN HWND hwnd,
IN int code,
IN PSBDATA pw,
IN OUT LPSCROLLINFO lpsi)
{
SBDATA sbd;
SCROLLINFO si;
BEGINRECV_HWND_SHARED(BOOL, FALSE, hwnd);
/*
* Probe arguments
*/
try {
ProbeForWriteScrollInfo(lpsi);
/*
* Probe the 4 DWORDS (MIN, MAX, PAGE, POS)
*/
ProbeForRead(pw, sizeof(SBDATA), sizeof(DWORD));
RtlCopyMemory(&sbd, pw, sizeof(sbd));
RtlCopyMemory(&si, lpsi, sizeof(SCROLLINFO));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = _SBGetParms(pwnd, code, &sbd, &si);
try {
RtlCopyMemory(lpsi, &si, sizeof(SCROLLINFO));
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ENDRECV_HWND_SHARED();
}
BOOL NtUserBitBltSysBmp(
IN HDC hdc,
IN int xDest,
IN int yDest,
IN int cxDest,
IN int cyDest,
IN int xSrc,
IN int ySrc,
IN DWORD dwRop)
{
BEGINRECV(BOOL, FALSE);
/*
* Note: This interface requires exclusive ownership of the User crit
* sect in order to serialize use of HDCBITS. Only one thread at a time
* may use a DC.
*/
retval = GreBitBlt(hdc,
xDest,
yDest,
cxDest,
cyDest,
HDCBITS(),
xSrc,
ySrc,
dwRop,
0);
ENDRECV();
}
HPALETTE NtUserSelectPalette(
IN HDC hdc,
IN HPALETTE hpalette,
IN BOOL fForceBackground)
{
BEGINRECV(HPALETTE, NULL)
retval = _SelectPalette(hdc, hpalette, fForceBackground);
ENDRECV();
}
/*
* Message thunks
*/
LRESULT NtUserMessageCall(
IN HWND hwnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam,
IN ULONG_PTR xParam,
IN DWORD xpfnProc,
IN BOOL bAnsi)
{
BEGINRECV_HWNDLOCKFF(LRESULT, 0, hwnd, xpfnProc);
if ((msg & ~MSGFLAG_MASK) >= WM_USER) {
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
} else {
retval = gapfnMessageCall[MessageTable[(msg & ~MSGFLAG_MASK)].iFunction](
pwnd,
msg,
wParam,
lParam,
xParam,
xpfnProc,
bAnsi);
}
TRACE("NtUserMessageCall");
ENDRECV_HWNDLOCKFF();
}
MESSAGECALL(DWORD)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnDWORD");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnDWORD");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(NCDESTROY)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnNCDESTROY");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnNCDESTROY");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OPTOUTLPDWORDOPTOUTLPDWORD)
{
DWORD dwwParam, dwlParam;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOPTOUTLPDWORDOPTOUTLPDWORD");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
(WPARAM)&dwwParam,
(LPARAM)&dwlParam,
xParam);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(wParam)) {
ProbeAndWriteUlong((PULONG)wParam, dwwParam);
}
if (ARGUMENT_PRESENT(lParam)) {
ProbeAndWriteUlong((PULONG)lParam, dwlParam);
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0); // should messages with bad wParam/lParam SetLastError?
}
TRACE("fnOPTOUTLPDWORDOPTOUTLPDWORD");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTNEXTMENU)
{
MDINEXTMENU mnm;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTNEXTMENU");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteMDINextMenu((PMDINEXTMENU)lParam);
mnm = *(PMDINEXTMENU)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&mnm,
xParam);
try {
*(PMDINEXTMENU)lParam = mnm;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTNEXTMENU");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(DWORDOPTINLPMSG)
{
MSG msgstruct;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnDWORDOPTINLPMSG");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(lParam)) {
msgstruct = ProbeAndReadMessage((LPMSG)lParam);
lParam = (LPARAM)&msgstruct;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnDWORDOPTINLPMSG");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(COPYGLOBALDATA)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnCOPYGLOBALDATA");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForRead((PVOID)lParam, wParam, sizeof(BYTE));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! Data pointed to by lParam must be captured
* in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnCOPYGLOBALDATA");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(COPYDATA)
{
COPYDATASTRUCT cds;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnCOPYDATA");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
if (ARGUMENT_PRESENT(lParam)) {
cds = ProbeAndReadCopyDataStruct((PCOPYDATASTRUCT)lParam);
if (cds.lpData)
ProbeForRead(cds.lpData, cds.cbData, sizeof(BYTE));
lParam = (LPARAM)&cds;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! Data pointed to by cds.lpData must be captured
* in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnCOPYDATA");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(SENTDDEMSG)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnSENTDDEMSG");
UNREFERENCED_PARAMETER(bAnsi);
if (xpfnProc == FNID_CALLWINDOWPROC) {
retval = CALLPROC(xpfnProc)(pwnd,
msg | MSGFLAG_DDE_SPECIAL_SEND,
wParam, lParam, xParam);
} else if ((ptiCurrent->TIF_flags & TIF_16BIT) &&
(ptiCurrent->ptdb) &&
(ptiCurrent->ptdb->hTaskWow)) {
/*
* Note that this function may modify msg by ORing in a bit in the
* high word. This bit is ignored when thunking messages.
* This allows the DdeTrackSendMessage() hook to be skipped - which
* would cause an error - and instead allows this thunk to carry
* the message all the way across.
*/
retval = xxxDDETrackPostHook(&msg, pwnd, wParam, &lParam, TRUE);
switch (retval) {
case DO_POST:
/*
* Or in the MSGFLAG_DDE_SPECIAL_SEND so that
* xxxSendMessageTimeout() will not pass this on to
* xxxDdeTrackSendMsg() which would think it was evil.
*
* Since the SendMessage() thunks ignore the reserved bits
* it will still get maped to the fnSENTDDEMSG callback thunk.
*/
retval = CALLPROC(xpfnProc)(pwnd,
msg | MSGFLAG_DDE_SPECIAL_SEND,
wParam, lParam, xParam);
break;
case FAKE_POST:
case FAIL_POST:
retval = 0;
}
} else {
MSGERROR(0);
}
TRACE("fnSENTDDEMSG");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(DDEINIT)
{
PWND pwndFrom;
TL tlpwndFrom;
PDDEIMP pddei;
PSECURITY_QUALITY_OF_SERVICE pqos;
NTSTATUS Status;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnDDEINIT");
UNREFERENCED_PARAMETER(bAnsi);
ValidateHWND(pwndFrom, (HWND)wParam);
ThreadLockAlwaysWithPti(ptiCurrent, pwndFrom, &tlpwndFrom);
/*
* Create temporary DDEIMP property for client window - this stays around
* only during the initiate phase.
*/
if ((pddei = (PDDEIMP)_GetProp(pwndFrom, PROP_DDEIMP, TRUE))
== NULL) {
pddei = (PDDEIMP)UserAllocPoolWithQuota(sizeof(DDEIMP), TAG_DDEd);
if (pddei == NULL) {
RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "fnDDEINIT: LocalAlloc failed.");
MSGERRORCLEANUP(0);
}
pqos = (PSECURITY_QUALITY_OF_SERVICE)_GetProp(pwndFrom, PROP_QOS, TRUE);
if (pqos == NULL) {
pqos = &gqosDefault;
}
pddei->qos = *pqos;
Status = SeCreateClientSecurity(PsGetCurrentThread(),
pqos, FALSE, &pddei->ClientContext);
if (!NT_SUCCESS(Status)) {
RIPMSG0(RIP_WARNING, "SeCreateClientContext failed.");
UserFreePool(pddei);
MSGERRORCLEANUP(0);
}
pddei->cRefInit = 1;
pddei->cRefConv = 0;
InternalSetProp(pwndFrom, PROP_DDEIMP, pddei, PROPF_INTERNAL);
} else {
pddei->cRefInit++; // cover broadcast case!
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
/*
* Reaquire pddei incase pwndFrom was destroyed.
*/
pddei = (PDDEIMP)_GetProp(pwndFrom, PROP_DDEIMP, TRUE);
if (pddei != NULL) {
/*
* Decrement reference count from DDEImpersonate property and remove property.
*/
pddei->cRefInit--;
if (pddei->cRefInit == 0) {
InternalRemoveProp(pwndFrom, PROP_DDEIMP, TRUE);
if (pddei->cRefConv == 0) {
SeDeleteClientSecurity(&pddei->ClientContext);
UserFreePool(pddei);
}
}
}
CLEANUPRECV();
ThreadUnlock(&tlpwndFrom);
TRACE("fnDDEINIT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INPAINTCLIPBRD)
{
PAINTSTRUCT ps;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINPAINTCLIPBRD");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ps = ProbeAndReadPaintStruct((PPAINTSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&ps,
xParam);
TRACE("fnINPAINTCLIPBRD");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INSIZECLIPBRD)
{
RECT rc;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINSIZECLIPBRD");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
rc = ProbeAndReadRect((PRECT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&rc,
xParam);
TRACE("fnINSIZECLIPBRD");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTDRAG)
{
DROPSTRUCT ds;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTDRAG");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteDropStruct((PDROPSTRUCT)lParam);
ds = *(PDROPSTRUCT)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&ds,
xParam);
try {
*(PDROPSTRUCT)lParam = ds;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTDRAG");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(GETDBCSTEXTLENGTHS)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnGETDBCSTEXTLENGTHS");
UNREFERENCED_PARAMETER(lParam);
/*
* This is used by L/CB_GETTEXTLEN which should return -1 (L/CB_ERR)
* on error. If any error code path is introduced here, make sure we return the
* proper value.This is also used by WM_GETTEXTLEN.
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
bAnsi,
xParam);
TRACE("fnGETDBCSTEXTLENGTHS");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPCREATESTRUCT)
{
CREATESTRUCTEX csex;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPCREATESTRUCT");
if (ARGUMENT_PRESENT(lParam)) {
try {
csex.cs = ProbeAndReadCreateStruct((LPCREATESTRUCTW)lParam);
if (bAnsi) {
ProbeForRead(csex.cs.lpszName, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&csex.strName,
(LPSTR)csex.cs.lpszName, (UINT)-1);
if (IS_PTR(csex.cs.lpszClass)) {
ProbeForRead(csex.cs.lpszClass, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&csex.strClass,
(LPSTR)csex.cs.lpszClass, (UINT)-1);
}
} else {
ProbeForRead(csex.cs.lpszName, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&csex.strName,
csex.cs.lpszName, (UINT)-1);
if (IS_PTR(csex.cs.lpszClass)) {
ProbeForRead(csex.cs.lpszClass, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&csex.strClass,
csex.cs.lpszClass, (UINT)-1);
}
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
/*
* Per Win95, do not allow NULL lpcreatestructs for WM_NCCREATE [51986]
* Allowed for WM_CREATE in Win95 for ObjectVision
*/
else if (msg == WM_NCCREATE) {
MSGERROR(0) ;
}
/*
* !!! Strings pointed to by cs.cs must be captured in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam ? (LPARAM)&csex : 0,
xParam);
TRACE("fnINLPCREATESTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPMDICREATESTRUCT)
{
MDICREATESTRUCTEX mdics;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPMDICREATESTRUCT");
/*
* Probe arguments
*/
try {
mdics.mdics = ProbeAndReadMDICreateStruct((LPMDICREATESTRUCTW)lParam);
if (bAnsi) {
ProbeForRead(mdics.mdics.szTitle, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&mdics.strTitle,
(LPSTR)mdics.mdics.szTitle, (UINT)-1);
if (IS_PTR(mdics.mdics.szClass)) {
ProbeForRead(mdics.mdics.szClass, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&mdics.strClass,
(LPSTR)mdics.mdics.szClass, (UINT)-1);
} else {
/*
* mdics.mdics.szClass may be Atom.
*/
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&mdics.strClass,
NULL, 0);
}
} else {
ProbeForRead(mdics.mdics.szTitle, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&mdics.strTitle,
mdics.mdics.szTitle, (UINT)-1);
if (IS_PTR(mdics.mdics.szClass)) {
ProbeForRead(mdics.mdics.szClass, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&mdics.strClass,
mdics.mdics.szClass, (UINT)-1);
} else {
/*
* mdics.mdics.szClass may be Atom.
*/
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&mdics.strClass,
NULL, 0);
}
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! Strings pointed to by mdics must be captured in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&mdics,
xParam);
TRACE("fnINLPMDICREATESTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTLPSCROLLINFO)
{
SCROLLINFO scrollinfo;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTLPSCROLLINFO");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteScrollInfo((LPSCROLLINFO)lParam);
scrollinfo = *(LPSCROLLINFO)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&scrollinfo,
xParam);
try {
*(LPSCROLLINFO)lParam = scrollinfo;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTLPSCROLLINFO");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTLPPOINT5)
{
POINT5 pt5;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTLPPOINT5");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWritePoint5((LPPOINT5)lParam);
pt5 = *(LPPOINT5)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&pt5,
xParam);
try {
*(LPPOINT5)lParam = pt5;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTLPPOINT5");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INSTRING)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINSTRING");
/*
* Don't allow any app to send a LB_DIR or CB_DIR with the postmsgs bit
* set (ObjectVision does this). This is because there is actually a legal
* case that we need to thunk of user posting a LB_DIR or CB_DIR
* (DlgDirListHelper()). In the post case, we thunk the lParam (pointer
* to a string) differently, and we track that post case with the
* DDL_POSTMSGS bit. If an app sends a message with this bit, then our
* thunking gets confused, so clear it here. Let's hope that no app
* depends on this bit set when either of these messages are sent.
*
* These messages should return -1 on failure
*/
switch (msg) {
case LB_DIR:
case CB_DIR:
wParam &= ~DDL_POSTMSGS;
/* Fall through */
case LB_ADDFILE:
#if (LB_ERR != CB_ERR)
#error LB_ERR/CB_ERR conflict
#endif
errret = LB_ERR;
break;
}
/*
* Probe arguments
*/
try {
if (bAnsi) {
ProbeForRead((LPSTR)lParam, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&str,
(LPSTR)lParam, (UINT)-1);
} else {
ProbeForRead((LPWSTR)lParam, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&str,
(LPWSTR)lParam, (UINT)-1);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! str.Buffer must be captured in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
TRACE("fnINSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INSTRINGNULL)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINSTRINGNULL");
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lParam)) {
try {
if (bAnsi) {
ProbeForRead((LPSTR)lParam, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&str,
(LPSTR)lParam, (UINT)-1);
} else {
ProbeForRead((LPWSTR)lParam, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&str,
(LPWSTR)lParam, (UINT)-1);
}
lParam = (LPARAM)&str;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
/*
* !!! str.Buffer must be captured in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnINSTRINGNULL");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INDEVICECHANGE)
{
BOOL fPtr = (BOOL)((wParam & 0x8000) == 0x8000);
DWORD cbSize;
PBYTE bfr = NULL;
TL tlBuffer;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINDEVICECHANGE");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
if (fPtr && lParam) {
struct _DEV_BROADCAST_HEADER *pHdr;
PDEV_BROADCAST_DEVICEINTERFACE_W pInterfaceW;
PDEV_BROADCAST_PORT_W pPortW;
PDEV_BROADCAST_HANDLE pHandleW;
try {
pHdr = (struct _DEV_BROADCAST_HEADER *)lParam;
cbSize = ProbeAndReadUlong(&(pHdr->dbcd_size));
if (cbSize < sizeof(*pHdr)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
ProbeForRead(pHdr, cbSize, sizeof(BYTE));
bfr = UserAllocPoolWithQuota(cbSize+2, TAG_DEVICECHANGE); // add space for trailing NULL for test
if (bfr == NULL) {
RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "fnINDEVICECHANGE: LocalAlloc failed.");
MSGERRORCLEANUP(0);
}
ThreadLockPool(ptiCurrent, bfr, &tlBuffer);
RtlCopyMemory(bfr, (PBYTE)lParam,
cbSize);
((PWSTR)bfr)[cbSize/sizeof(WCHAR)] = 0; // trailing null to halt wcslen scan
lParam = (LPARAM)bfr;
pHdr = (struct _DEV_BROADCAST_HEADER *)lParam;
if (pHdr->dbcd_size != cbSize) {
MSGERRORCLEANUP(0);
}
switch(pHdr->dbcd_devicetype) {
case DBT_DEVTYP_PORT:
pPortW = (PDEV_BROADCAST_PORT_W)lParam;
if ((1+wcslen(pPortW->dbcp_name))*sizeof(WCHAR) + FIELD_OFFSET(DEV_BROADCAST_PORT_W, dbcp_name) > cbSize) {
MSGERRORCLEANUP(0);
}
break;
case DBT_DEVTYP_DEVICEINTERFACE:
pInterfaceW = (PDEV_BROADCAST_DEVICEINTERFACE_W)lParam;
if ((1+wcslen(pInterfaceW->dbcc_name))*sizeof(WCHAR) + FIELD_OFFSET(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name) > cbSize) {
MSGERRORCLEANUP(0);
}
break;
case DBT_DEVTYP_HANDLE:
pHandleW = (PDEV_BROADCAST_HANDLE)lParam;
/*
* Check if there is any text.
*/
if (wParam != DBT_CUSTOMEVENT) {
if (FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_eventguid) > cbSize) {
MSGERRORCLEANUP(0);
}
break;
}
if (pHandleW->dbch_nameoffset < 0) {
if (FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data) > cbSize) {
MSGERRORCLEANUP(0);
}
break;
}
if (pHandleW->dbch_nameoffset & (CHARALIGN - 1)) {
ExRaiseDatatypeMisalignment(); \
}
if ((DWORD)(FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data) + pHandleW->dbch_nameoffset) > cbSize) {
MSGERRORCLEANUP(0);
}
if (FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data) + pHandleW->dbch_nameoffset +
(1+wcslen((LPWSTR)(pHandleW->dbch_data+pHandleW->dbch_nameoffset)))*sizeof(WCHAR) >
cbSize) {
MSGERRORCLEANUP(0);
}
break;
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
CLEANUPRECV();
if (bfr)
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
TRACE("fnINDEVICECHANGE");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTNCCALCSIZE)
{
NCCALCSIZE_PARAMS params;
WINDOWPOS pos;
PWINDOWPOS pposClient;
RECT rc;
LPARAM lParamLocal;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTNCCALCSIZE");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
if (wParam != 0) {
ProbeForWriteNCCalcSize((LPNCCALCSIZE_PARAMS)lParam);
params = *(LPNCCALCSIZE_PARAMS)lParam;
ProbeForWriteWindowPos(params.lppos);
pposClient = params.lppos;
pos = *params.lppos;
params.lppos = &pos;
lParamLocal = (LPARAM)&params;
} else {
ProbeForWriteRect((LPRECT)lParam);
rc = *(LPRECT)lParam;
lParamLocal = (LPARAM)&rc;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParamLocal,
xParam);
try {
if (wParam != 0) {
*(LPNCCALCSIZE_PARAMS)lParam = params;
((LPNCCALCSIZE_PARAMS)lParam)->lppos = pposClient;
*pposClient = pos;
} else {
*(LPRECT)lParam = rc;
}
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTNCCALCSIZE");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTSTYLECHANGE)
{
STYLESTRUCT ss;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTSTYLECHANGE");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteStyleStruct((LPSTYLESTRUCT)lParam);
ss = *(LPSTYLESTRUCT)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&ss,
xParam);
try {
*(LPSTYLESTRUCT)lParam = ss;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTSTYLECHANGE");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTLPRECT)
{
RECT rc;
BEGINRECV_MESSAGECALL((msg == LB_GETITEMRECT ? LB_ERR : 0));
TRACETHUNK("fnINOUTLPRECT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteRect((PRECT)lParam);
rc = *(PRECT)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&rc,
xParam);
try {
*(PRECT)lParam = rc;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTLPRECT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTLPSCROLLINFO)
{
SCROLLINFO scrollinfo;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTLPSCROLLINFO");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&scrollinfo,
xParam);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure((LPSCROLLINFO)lParam, scrollinfo, SCROLLINFO);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("fnOUTLPSCROLLINFO");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTLPRECT)
{
RECT rc;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTLPRECT");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&rc,
xParam);
/*
* Probe arguments
*/
try {
ProbeAndWriteStructure((PRECT)lParam, rc, RECT);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("fnOUTLPRECT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPCOMPAREITEMSTRUCT)
{
COMPAREITEMSTRUCT compareitemstruct;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPCOMPAREITEMSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
compareitemstruct = ProbeAndReadCompareItemStruct((PCOMPAREITEMSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&compareitemstruct,
xParam);
TRACE("fnINLPCOMPAREITEMSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPDELETEITEMSTRUCT)
{
DELETEITEMSTRUCT deleteitemstruct;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPDELETEITEMSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
deleteitemstruct = ProbeAndReadDeleteItemStruct((PDELETEITEMSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&deleteitemstruct,
xParam);
TRACE("fnINLPDELETEITEMSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPHLPSTRUCT)
{
HLP hlp;
LPHLP phlp = NULL;
TL tlBuffer;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPHLPSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
hlp = ProbeAndReadHelp((LPHLP)lParam);
if (hlp.cbData < sizeof(HLP)) {
MSGERROR(0);
}
phlp = UserAllocPoolWithQuota(hlp.cbData, TAG_SYSTEM);
if (phlp == NULL) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
ThreadLockPool(ptiCurrent, phlp, &tlBuffer);
RtlCopyMemory(phlp, (PVOID)lParam, hlp.cbData);
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)phlp,
xParam);
CLEANUPRECV();
if (phlp) {
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
}
TRACE("fnINLPHLPSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPHELPINFOSTRUCT)
{
HELPINFO helpinfo;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPHELPINFOSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
helpinfo = ProbeAndReadHelpInfo((LPHELPINFO)lParam);
if (helpinfo.cbSize != sizeof(HELPINFO)) {
RIPMSG1(RIP_WARNING, "HELPINFO.cbSize %d is wrong", helpinfo.cbSize);
MSGERROR(ERROR_INVALID_PARAMETER);
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&helpinfo,
xParam);
TRACE("fnINLPHELPINFOSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPDRAWITEMSTRUCT)
{
DRAWITEMSTRUCT drawitemstruct;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPDRAWITEMSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
drawitemstruct = ProbeAndReadDrawItemStruct((PDRAWITEMSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&drawitemstruct,
xParam);
TRACE("fnINLPDRAWITEMSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTLPMEASUREITEMSTRUCT)
{
MEASUREITEMSTRUCT measureitemstruct;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTLPMEASUREITEMSTRUCT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteMeasureItemStruct((PMEASUREITEMSTRUCT)lParam);
measureitemstruct = *(PMEASUREITEMSTRUCT)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&measureitemstruct,
xParam);
try {
*(PMEASUREITEMSTRUCT)lParam = measureitemstruct;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTLPMEASUREITEMSTRUCT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTSTRING)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTSTRING");
/*
* Probe all arguments
*/
try {
str.bAnsi = bAnsi;
str.MaximumLength = (ULONG)wParam;
if (!bAnsi) {
str.MaximumLength *= sizeof(WCHAR);
}
str.Length = 0;
str.Buffer = (PVOID)lParam;
#if defined(_X86_)
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE));
#else
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength,
str.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! String buffer must be created in xxxInterSendMsgEx and
* lParam probed for write again upon return.
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
/*
* A dialog function returning FALSE means no text to copy out,
* but an empty string also has retval == 0: put a null char in
* pstr for the latter case.
*/
if (!retval && wParam != 0) {
try {
NullTerminateString((PVOID)lParam, bAnsi);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("fnOUTSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTDWORDINDWORD)
{
DWORD dw;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTDWORDINDWORD");
UNREFERENCED_PARAMETER(bAnsi);
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
(WPARAM)&dw,
lParam,
xParam);
/*
* Probe wParam
*/
try {
ProbeAndWriteUlong((PULONG)wParam, dw);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("fnOUTDWORDINDWORD");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INCNTOUTSTRING)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINCNTOUTSTRING");
/*
* Probe arguments
*/
try {
str.bAnsi = bAnsi;
str.MaximumLength = ProbeAndReadUshort((LPWORD)lParam);
if (!bAnsi) {
str.MaximumLength *= sizeof(WCHAR);
}
if (str.MaximumLength < sizeof(WORD)) {
RIPMSG0(RIP_WARNING, "fnINCNTOUTSTRING buffer is too small");
MSGERROR(0);
}
str.Length = 0;
str.Buffer = (LPBYTE)lParam;
#if defined(_X86_)
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE));
#else
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength,
str.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! String buffer must be created in xxxInterSendMsgEx and
* lParam probed for write again upon return.
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
/*
* A dialog function returning FALSE means no text to copy out,
* but an empty string also has retval == 0: put a null char in
* pstr for the latter case.
*/
if (!retval) {
try {
NullTerminateString((PVOID)lParam, bAnsi);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("fnINCNTOUTSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INCNTOUTSTRINGNULL)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINCNTOUTSTRINGNULL");
/*
* Probe arguments
*/
try {
if (wParam < 2) { // This prevents a possible GP
MSGERROR(0);
}
str.bAnsi = bAnsi;
str.MaximumLength = (ULONG)wParam;
if (!bAnsi) {
str.MaximumLength *= sizeof(WCHAR);
}
str.Length = 0;
str.Buffer = (LPBYTE)lParam;
#if defined(_X86_)
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE));
#else
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength,
str.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
*((LPWSTR)str.Buffer) = 0; // mark incase message is not handled
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! String buffer must be created in xxxInterSendMsgEx and
* lParam probed for write again upon return.
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
TRACE("fnINCNTOUTSTRINGNULL");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(POUTLPINT)
{
BEGINRECV_MESSAGECALL(LB_ERR);
/*
* If we use this for other messages, then that return value might not be appropriate.
*/
UserAssert(msg == LB_GETSELITEMS);
TRACETHUNK("fnPOUTLPINT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
#if defined(_X86_)
ProbeForWriteBuffer((LPINT)lParam, wParam, sizeof(BYTE));
#else
ProbeForWriteBuffer((LPINT)lParam, wParam, sizeof(INT));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! Buffer must be created in xxxInterSendMsgEx and
* lParam probed for write again upon return.
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnPOUTLPINT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(POPTINLPUINT)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnPOPTINLPUINT");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
#if defined(_X86_)
if (lParam)
ProbeForReadBuffer((LPUINT)lParam, wParam, sizeof(BYTE));
#else
if (lParam)
ProbeForReadBuffer((LPUINT)lParam, wParam, sizeof(DWORD));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* !!! Data pointed to by lParam must be captured in xxxInterSendMsgEx
*/
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnPOPTINLPUINT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INOUTLPWINDOWPOS)
{
WINDOWPOS pos;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTLPWINDOWPOS");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteWindowPos((PWINDOWPOS)lParam);
pos = *(PWINDOWPOS)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&pos,
xParam);
try {
*(PWINDOWPOS)lParam = pos;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTLPWINDOWPOS");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLPWINDOWPOS)
{
WINDOWPOS pos;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINLPWINDOWPOS");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
pos = ProbeAndReadWindowPos((PWINDOWPOS)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&pos,
xParam);
TRACE("fnINLPWINDOWPOS");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INLBOXSTRING)
{
BEGINRECV_MESSAGECALL(LB_ERR);
TRACETHUNK("fnINLBOXSTRING");
if (!(pwnd->style & LBS_HASSTRINGS) &&
(pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))) {
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
} else if (msg == LB_FINDSTRING) {
retval = NtUserfnINSTRINGNULL(
pwnd,
msg,
wParam,
lParam,
xParam,
xpfnProc,
bAnsi);
} else {
retval = NtUserfnINSTRING(
pwnd,
msg,
wParam,
lParam,
xParam,
xpfnProc,
bAnsi);
}
TRACE("fnINLBOXSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTLBOXSTRING)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(LB_ERR);
TRACETHUNK("fnOUTLBOXSTRING");
/*
* Need to get the string length ahead of time. This isn't passed in
* with this message. Code assumes app already knows the size of
* the string and has passed a pointer to a buffer of adequate size.
* To do client/server copying of this string, we need to ahead of
* time the Unicode size of this string. We add one character because
* GETTEXTLEN excludes the null terminator.
*/
retval = NtUserfnGETDBCSTEXTLENGTHS(
pwnd,
LB_GETTEXTLEN,
wParam,
lParam,
xParam,
xpfnProc,
/*IS_DBCS_ENABLED() &&*/ bAnsi); // HiroYama: LATER
if (retval == LB_ERR)
MSGERROR(0);
retval++;
/*
* Probe all arguments
*/
try {
str.bAnsi = bAnsi;
if (bAnsi) {
str.MaximumLength = (ULONG)retval;
} else {
str.MaximumLength = (ULONG)retval * sizeof(WCHAR);
}
str.Length = 0;
str.Buffer = (PVOID)lParam;
#if defined(_X86_)
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE));
#else
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength,
str.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
/*
* If the control is ownerdraw and does not have the LBS_HASSTRINGS
* style, then a 32-bits of application data has been obtained,
* not a string.
*/
if (!(pwnd->style & LBS_HASSTRINGS) &&
(pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))) {
if (bAnsi) {
retval = sizeof(ULONG_PTR)/sizeof(CHAR); // 4 CHARs just like win3.1
} else {
retval = sizeof(ULONG_PTR)/sizeof(WCHAR); // 2 WCHARs
}
}
TRACE("fnOUTLBOXSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INCBOXSTRING)
{
BEGINRECV_MESSAGECALL(CB_ERR);
TRACETHUNK("fnINCBOXSTRING");
if (!(pwnd->style & CBS_HASSTRINGS) &&
(pwnd->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))) {
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
} else if (msg == CB_FINDSTRING) {
retval = NtUserfnINSTRINGNULL(
pwnd,
msg,
wParam,
lParam,
xParam,
xpfnProc,
bAnsi);
} else {
retval = NtUserfnINSTRING(
pwnd,
msg,
wParam,
lParam,
xParam,
xpfnProc,
bAnsi);
}
TRACE("fnINCBOXSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTCBOXSTRING)
{
LARGE_STRING str;
BEGINRECV_MESSAGECALL(CB_ERR);
TRACETHUNK("fnOUTCBOXSTRING");
/*
* Need to get the string length ahead of time. This isn't passed in
* with this message. Code assumes app already knows the size of
* the string and has passed a pointer to a buffer of adequate size.
* To do client/server copying of this string, we need to ahead of
* time the size of this string. We add one character because
* GETTEXTLEN excludes the null terminator.
*/
retval = NtUserfnGETDBCSTEXTLENGTHS(
pwnd,
CB_GETLBTEXTLEN,
wParam,
lParam,
xParam,
xpfnProc,
/*IS_DBCS_ENABLED() &&*/ bAnsi); // HiroYama: LATER
if (retval == CB_ERR)
MSGERROR(0);
retval++;
/*
* Probe all arguments
*/
try {
str.bAnsi = bAnsi;
if (bAnsi) {
str.MaximumLength = (ULONG)retval;
} else {
str.MaximumLength = (ULONG)retval * sizeof(WCHAR);
}
str.Length = 0;
str.Buffer = (PVOID)lParam;
#if defined(_X86_)
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE));
#else
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength,
str.bAnsi ? sizeof(BYTE) : sizeof(WORD));
#endif
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&str,
xParam);
/*
* If the control is ownerdraw and does not have the CBS_HASSTRINGS
* style, then a 32-bits of application data has been obtained,
* not a string.
*/
if (!(pwnd->style & CBS_HASSTRINGS) &&
(pwnd->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))) {
if (bAnsi) {
retval = sizeof(ULONG_PTR)/sizeof(CHAR); // 4 CHARs just like win3.1
} else {
retval = sizeof(ULONG_PTR)/sizeof(WCHAR); // 2 WCHARs
}
}
TRACE("fnOUTCBOXSTRING");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(INWPARAMCHAR)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINWPARAMCHAR");
/*
* The server always expects the characters to be unicode so
* if this was generated from an ANSI routine convert it to Unicode
*/
if (bAnsi) {
if (msg == WM_CHARTOITEM || msg == WM_MENUCHAR) {
WPARAM dwT = wParam & 0xFFFF; // mask of caret pos
RtlMBMessageWParamCharToWCS(msg, &dwT); // convert key portion
wParam = MAKELONG(LOWORD(dwT),HIWORD(wParam)); // rebuild pos & key wParam
} else {
RtlMBMessageWParamCharToWCS(msg, &wParam);
}
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lParam,
xParam);
TRACE("fnINWPARAMCHAR");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(KERNELONLY)
{
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnKERNELONLY");
UNREFERENCED_PARAMETER(pwnd);
UNREFERENCED_PARAMETER(msg);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(xParam);
UNREFERENCED_PARAMETER(xpfnProc);
UNREFERENCED_PARAMETER(bAnsi);
RIPMSG0(RIP_WARNING,
"Message sent from client to kernel for a process which has only kernel side");
retval = 0;
TRACE("fnKERNELONLY");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(IMECONTROL)
{
CANDIDATEFORM CandForm;
COMPOSITIONFORM CompForm;
LOGFONTW LogFontW;
LPARAM lData = lParam;
PSOFTKBDDATA pSoftKbdData = NULL;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnIMECONTROL");
UNREFERENCED_PARAMETER(bAnsi);
/*
* wParam range validation:
* No need to check lower limit, 'cause we assume IMC_FIRST == 0
* and wParam is unsigned.
*/
#if (IMC_FIRST != 0)
#error IMC_FIRST: unexpected value
#endif
if (msg != WM_IME_CONTROL || wParam > IMC_LAST) {
MSGERROR(0);
}
/*
* Probe arguments
*/
try {
switch (wParam) {
case IMC_GETCANDIDATEPOS:
ProbeForWriteCandidateForm((PCANDIDATEFORM)lParam);
break;
case IMC_GETCOMPOSITIONWINDOW:
ProbeForWriteCompositionForm((PCOMPOSITIONFORM)lParam);
break;
case IMC_GETCOMPOSITIONFONT:
case IMC_GETSOFTKBDFONT:
ProbeForWriteLogFontW((PLOGFONTW)lParam);
break;
case IMC_SETCANDIDATEPOS:
CandForm = ProbeAndReadCandidateForm((PCANDIDATEFORM)lParam);
lData = (LPARAM)&CandForm;
break;
case IMC_SETCOMPOSITIONWINDOW:
CompForm = ProbeAndReadCompositionForm((PCOMPOSITIONFORM)lParam);
lData = (LPARAM)&CompForm;
break;
case IMC_SETCOMPOSITIONFONT:
LogFontW = ProbeAndReadLogFontW((PLOGFONTW)lParam);
lData = (LPARAM)&LogFontW;
break;
case IMC_SETSOFTKBDDATA:
pSoftKbdData = ProbeAndCaptureSoftKbdData((PSOFTKBDDATA)lParam);
if (pSoftKbdData == NULL)
MSGERROR(0);
lData = (LPARAM)pSoftKbdData;
break;
default:
break;
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lData,
xParam);
CLEANUPRECV();
if (pSoftKbdData != NULL) {
UserFreePool(pSoftKbdData);
}
TRACE("fnIMECONTROL");
ENDRECV_MESSAGECALL();
}
#ifdef LATER
MESSAGECALL(IMEREQUEST)
{
LPARAM lData = lParam;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnIMEREQUEST");
UNREFERENCED_PARAMETER(bAnsi);
if (GETPTI(pwnd) != PtiCurrent()) {
/*
* Does not allow to send WM_IME_REQUEST to
* the different thread.
*/
MSGERROR(ERROR_WINDOW_OF_OTHER_THREAD);
}
/*
* Probe arguments
*/
try {
switch (wParam) {
case IMR_COMPOSITIONWINDOW:
ProbeForWriteCompositionForm((PCOMPOSITIONFORM)lParam);
break;
case IMR_CANDIDATEWINDOW:
ProbeForWriteCandidateForm((PCANDIDATEFORM)lParam);
break;
case IMR_COMPOSITIONFONT:
ProbeForWriteLogFontW((PLOGFONTW)lParam);
break;
case IMR_RECONVERTSTRING:
case IMR_DOCUMENTFEED:
if (lParam) {
ProbeForWriteReconvertString((LPRECONVERTSTRING)lParam);
}
break;
case IMR_CONFIRMRECONVERTSTRING:
//ProbeAndCaptureReconvertString((LPRECONVERTSTRING)lParam);
//ProbeForWriteReconvertString((LPRECONVERTSTRING)lParam);
ProbeForReadReconvertString((LPRECONVERTSTRING)lParam);
break;
case IMR_QUERYCHARPOSITION:
ProbeForWriteImeCharPosition((LPPrivateIMECHARPOSITION)lParam);
break;
default:
MSGERROR(0);
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
lData,
xParam);
CLEANUPRECV();
TRACE("fnIMEREQUEST");
ENDRECV_MESSAGECALL();
}
#endif
/*
* Hook stubs
*/
LRESULT NtUserfnHkINLPCBTCREATESTRUCT(
IN UINT msg,
IN WPARAM wParam,
IN LPCBT_CREATEWND pcbt,
IN BOOL bAnsi)
{
CBT_CREATEWND cbt;
CREATESTRUCTEX csex;
LPCREATESTRUCT lpcsSave;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
cbt = ProbeAndReadCBTCreateStruct(pcbt);
ProbeForWriteCreateStruct(cbt.lpcs);
lpcsSave = cbt.lpcs;
csex.cs = *cbt.lpcs;
cbt.lpcs = (LPCREATESTRUCT)&csex;
if (bAnsi) {
ProbeForRead(csex.cs.lpszName, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&csex.strName,
(LPSTR)csex.cs.lpszName, (UINT)-1);
if (IS_PTR(csex.cs.lpszClass)) {
ProbeForRead(csex.cs.lpszClass, sizeof(CHAR), sizeof(CHAR));
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&csex.strClass,
(LPSTR)csex.cs.lpszClass, (UINT)-1);
}
} else {
ProbeForRead(csex.cs.lpszName, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&csex.strName,
csex.cs.lpszName, (UINT)-1);
if (IS_PTR(csex.cs.lpszClass)) {
ProbeForRead(csex.cs.lpszClass, sizeof(WCHAR), CHARALIGN);
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&csex.strClass,
csex.cs.lpszClass, (UINT)-1);
}
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
msg,
wParam,
(LPARAM)&cbt);
try {
pcbt->hwndInsertAfter = cbt.hwndInsertAfter;
lpcsSave->x = cbt.lpcs->x;
lpcsSave->y = cbt.lpcs->y;
lpcsSave->cx = cbt.lpcs->cx;
lpcsSave->cy = cbt.lpcs->cy;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
TRACE("NtUserfnHkINLPCBTCREATESTRUCT");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkINLPRECT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPRECT lParam)
{
RECT rc;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
rc = ProbeAndReadRect((PRECT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&rc);
TRACE("NtUserfnHkINLPRECT");
ENDRECV_HOOKCALL();
}
#ifdef REDIRECTION
LRESULT NtUserfnHkINLPPOINT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPPOINT lParam)
{
POINT pt;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
pt = ProbeAndReadPoint((LPPOINT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&pt);
TRACE("NtUserfnHkINLPPOINT");
ENDRECV_HOOKCALL();
}
/**************************************************************************\
* NtUserGetProcessRedirectionMode
*
* 04-06-01 MSadek Created.
\**************************************************************************/
BOOL
NtUserGetProcessRedirectionMode(
HANDLE hProcess,
PBOOL pbRedirectionMode)
{
PEPROCESS Process;
PPROCESSINFO ppi;
BEGINRECV(BOOL, FALSE);
if (hProcess == NtCurrentProcess()) {
ppi = PpiCurrent();
} else {
NTSTATUS Status;
Status = ObReferenceObjectByHandle(hProcess,
PROCESS_QUERY_INFORMATION,
*PsProcessType,
UserMode,
&Process,
NULL);
if (!NT_SUCCESS(Status)) {
RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetProcessRedirectionMode: Failed with Process handle == %X, Status = %x",
hProcess, Status);
MSGERROR(0);
}
/*
* Make sure they are from the same session.
*/
if (PsGetProcessSessionId(Process) != gSessionId) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetProcessRedirectionMode: Different session. Failed with Process handle == %X", hProcess);
ObDereferenceObject(Process);
MSGERROR(0);
}
ppi = PpiFromProcess(Process);
if (ppi == NULL) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetProcessRedirectionMode: Non GUI process. Process handle == %X", hProcess);
ObDereferenceObject(Process);
MSGERROR(0);
}
try {
ProbeAndWriteLong(pbRedirectionMode, ppi->dwRedirection & PF_REDIRECTED);
ObDereferenceObject(Process);
} except (StubExceptionHandler(TRUE)) {
ObDereferenceObject(Process);
MSGERROR(0);
}
retval = TRUE;
}
TRACE("NtUserGetProcessRedirectionMode");
ENDRECV();
}
/**************************************************************************\
* NtUserSetProcessRedirectionMode
*
* 04-06-01 MSadek Created.
\**************************************************************************/
BOOL
NtUserSetProcessRedirectionMode(
HANDLE hProcess,
BOOL bRedirectionMode)
{
PEPROCESS Process;
PPROCESSINFO ppi;
BEGINRECV(BOOL, FALSE);
/*
* A host process can not redirect itself.
*/
if (hProcess == NtCurrentProcess()) {
RIPERR0(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"NtUserSetProcessRedirectionMode: A process tried to change redirection mode for itself.");
MSGERROR(0);
} else {
NTSTATUS Status;
Status = ObReferenceObjectByHandle(hProcess,
PROCESS_SET_INFORMATION,
*PsProcessType,
UserMode,
&Process,
NULL);
if (!NT_SUCCESS(Status)) {
RIPERR2(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"NtUserSetProcessRedirectionMode: Failed with Process handle == 0x%x, Status = 0x%x",
hProcess,
Status);
MSGERROR(0);
}
/*
* Cannot allow CSRSS to be redirected.
*/
if (Process == gpepCSRSS) {
ObDereferenceObject(Process);
MSGERROR(ERROR_ACCESS_DENIED);
}
/*
* Make sure they are from the same session.
*/
if (PsGetProcessSessionId(Process) != gSessionId) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserSetProcessRedirectionMode: Different session. Failed with Process handle == %X", hProcess);
ObDereferenceObject(Process);
MSGERROR(0);
}
ppi = PpiFromProcess(Process);
if (ppi == NULL) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserSetProcessRedirectionMode: Non GUI process. Process handle == %X", hProcess);
ObDereferenceObject(Process);
MSGERROR(0);
}
/*
* Fail if the target process is a redirection host.
*/
if (ppi-> dwRedirection & PF_REDIRECTIONHOST) {
RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserSetProcessRedirectionMode: trying to redirect a host process == %X, Status = %x",
hProcess, Status);
ObDereferenceObject(Process);
MSGERROR(0);
}
PpiCurrent()->dwRedirection = PF_REDIRECTIONHOST;
if (bRedirectionMode) {
ppi->dwRedirection |= PF_REDIRECTED;
} else {
ppi->dwRedirection &= ~PF_REDIRECTED;
}
xxxSetProcessRedirectionMode(bRedirectionMode, ppi);
ObDereferenceObject(Process);
retval = TRUE;
}
TRACE("NtUserSetProcessRedirectionMode");
ENDRECV();
}
/**************************************************************************\
* NtUserGetDesktopRedirectionMode
*
* 04-06-01 MSadek Created.
\**************************************************************************/
BOOL
NtUserGetDesktopRedirectionMode(
HDESK hDesk,
PBOOL pbRedirectionMode)
{
PDESKTOP pDesk;
NTSTATUS Status;
BEGINRECV(BOOL, FALSE);
Status = ValidateHdesk(hDesk, UserMode, DESKTOP_QUERY_INFORMATION, &pDesk);
if (!NT_SUCCESS(Status)) {
RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetDesktopRedirectionMode: Failed with Desktop handle == %X, Status = %x",
hDesk, Status);
MSGERROR(0);
}
try {
ProbeAndWriteLong(pbRedirectionMode, pDesk->dwDTFlags & DF_REDIRECTED);
ObDereferenceObject(pDesk);
} except (StubExceptionHandler(TRUE)) {
ObDereferenceObject(pDesk);
MSGERROR(0);
}
retval = TRUE;
TRACE("NtUserGetDesktopRedirectionMode");
ENDRECV();
}
/**************************************************************************\
* NtUserSetDesktopRedirectionMode
*
* 04-06-01 MSadek Created.
\**************************************************************************/
BOOL
NtUserSetDesktopRedirectionMode(
HDESK hDesk,
BOOL bRedirectionMode)
{
PDESKTOP pDesk;
NTSTATUS Status;
BEGINRECV(BOOL, FALSE);
Status = ValidateHdesk(hDesk, UserMode, DESKTOP_REDIRECT, &pDesk);
if (!NT_SUCCESS(Status)) {
RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetDesktopRedirectionMode: Failed with Desktop handle == %X, Status = %x",
hDesk, Status);
MSGERROR(0);
}
PpiCurrent()->dwRedirection = PF_REDIRECTIONHOST;
if (bRedirectionMode) {
pDesk->dwDTFlags |= DF_REDIRECTED;
} else {
pDesk->dwDTFlags &= ~DF_REDIRECTED;
}
xxxSetDesktopRedirectionMode(bRedirectionMode, pDesk, PpiCurrent());
ObDereferenceObject(pDesk);
retval = TRUE;
TRACE("NtUserSetDesktopRedirectionMode");
ENDRECV();
}
#endif // REDIRECTION
LRESULT NtUserfnHkINLPMSG(
IN int iHook,
IN DWORD nCode,
IN WPARAM wParam,
IN LPMSG lParam)
{
MSG msg;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
msg = ProbeAndReadMessage((PMSG)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&msg);
/*
* If this is GetMessageHook, the hook should be
* able to change the message, as stated in SDK document.
*/
if (iHook == WH_GETMESSAGE) {
try {
*(PMSG)lParam = msg;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("NtUserfnHkINLPMSG");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkINLPDEBUGHOOKSTRUCT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPDEBUGHOOKINFO lParam)
{
DEBUGHOOKINFO hookinfo;
DWORD cbDbgLParam;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
hookinfo = ProbeAndReadHookInfo((PDEBUGHOOKINFO)lParam);
cbDbgLParam = GetDebugHookLParamSize(wParam, &hookinfo);
ProbeForRead(hookinfo.lParam, cbDbgLParam, DATAALIGN);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&hookinfo);
TRACE("NtUserfnHkINLPDEBUGHOOKSTRUCT");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkOPTINLPEVENTMSG(
IN DWORD nCode,
IN WPARAM wParam,
IN OUT LPEVENTMSGMSG lParam OPTIONAL)
{
EVENTMSG event;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lParam)) {
try {
ProbeForWriteEvent((LPEVENTMSGMSG)lParam);
event = *(LPEVENTMSGMSG)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)(lParam ? &event : NULL));
if (ARGUMENT_PRESENT(lParam)) {
try {
*(LPEVENTMSGMSG)lParam = event;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("NtUserfnHkINLPEVENTMSG");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkINLPMOUSEHOOKSTRUCTEX(
IN DWORD nCode,
IN WPARAM wParam,
IN LPMOUSEHOOKSTRUCTEX lParam)
{
MOUSEHOOKSTRUCTEX mousehook;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
mousehook = ProbeAndReadMouseHook((PMOUSEHOOKSTRUCTEX)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&mousehook);
TRACE("NtUserfnHkINLPMOUSEHOOKSTRUCTEX");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkINLPKBDLLHOOKSTRUCT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPKBDLLHOOKSTRUCT lParam)
{
KBDLLHOOKSTRUCT kbdhook;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
kbdhook = ProbeAndReadKbdHook((PKBDLLHOOKSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&kbdhook);
TRACE("NtUserfnHkINLPKBDLLHOOKSTRUCT");
ENDRECV_HOOKCALL();
}
LRESULT NtUserfnHkINLPMSLLHOOKSTRUCT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPMSLLHOOKSTRUCT lParam)
{
MSLLHOOKSTRUCT msllhook;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
msllhook = ProbeAndReadMsllHook((PMSLLHOOKSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&msllhook);
TRACE("NtUserfnHkINLPMSLLHOOKSTRUCT");
ENDRECV_HOOKCALL();
}
#ifdef REDIRECTION
LRESULT NtUserfnHkINLPHTHOOKSTRUCT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPHTHOOKSTRUCT lParam)
{
HTHOOKSTRUCT hthook;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
hthook = ProbeAndReadHTHook((PHTHOOKSTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&hthook);
TRACE("NtUserfnHkINLPHTHOOKSTRUCT");
ENDRECV_HOOKCALL();
}
#endif // REDIRECTION
LRESULT NtUserfnHkINLPCBTACTIVATESTRUCT(
IN DWORD nCode,
IN WPARAM wParam,
IN LPCBTACTIVATESTRUCT lParam)
{
CBTACTIVATESTRUCT cbtactivate;
BEGINRECV_HOOKCALL();
/*
* Probe arguments
*/
try {
cbtactivate = ProbeAndReadCBTActivateStruct((LPCBTACTIVATESTRUCT)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = xxxCallNextHookEx(
nCode,
wParam,
(LPARAM)&cbtactivate);
TRACE("NtUserfnHkINLPCBTACTIVATESTRUCT");
ENDRECV_HOOKCALL();
}
LRESULT NtUserCallNextHookEx(
int nCode,
WPARAM wParam,
LPARAM lParam,
BOOL bAnsi)
{
BEGINRECV(LRESULT, 0);
if (PtiCurrent()->sphkCurrent == NULL) {
MSGERROR(0);
}
switch (PtiCurrent()->sphkCurrent->iHook) {
case WH_CBT:
/*
* There are many different types of CBT hooks!
*/
switch (nCode) {
case HCBT_CLICKSKIPPED:
goto MouseHook;
break;
case HCBT_CREATEWND:
/*
* This hook type points to a CREATESTRUCT, so we need to
* be fancy it's thunking, because a CREATESTRUCT contains
* a pointer to CREATEPARAMS which can be anything... so
* funnel this through our message thunks.
*/
retval = NtUserfnHkINLPCBTCREATESTRUCT(
nCode,
wParam,
(LPCBT_CREATEWND)lParam,
bAnsi);
break;
#ifdef REDIRECTION
case HCBT_GETCURSORPOS:
/*
* This hook type points to a POINT structure.
*/
retval = NtUserfnHkINLPPOINT(nCode, wParam, (LPPOINT)lParam);
break;
#endif // REDIRECTION
case HCBT_MOVESIZE:
/*
* This hook type points to a RECT structure.
*/
retval = NtUserfnHkINLPRECT(nCode, wParam, (LPRECT)lParam);
break;
case HCBT_ACTIVATE:
/*
* This hook type points to a CBTACTIVATESTRUCT
*/
retval = NtUserfnHkINLPCBTACTIVATESTRUCT(nCode, wParam,
(LPCBTACTIVATESTRUCT)lParam);
break;
default:
/*
* The rest of the cbt hooks are all dword parameters.
*/
retval = xxxCallNextHookEx(
nCode,
wParam,
lParam);
break;
}
break;
case WH_FOREGROUNDIDLE:
case WH_KEYBOARD:
case WH_SHELL:
/*
* These are dword parameters and are therefore real easy.
*/
retval = xxxCallNextHookEx(
nCode,
wParam,
lParam);
break;
case WH_MSGFILTER:
case WH_SYSMSGFILTER:
case WH_GETMESSAGE:
/*
* These take an lpMsg as their last parameter. Since these are
* exclusively posted parameters, and since nowhere on the server
* do we post a message with a pointer to some other structure in
* it, the lpMsg structure contents can all be treated verbatim.
*/
retval = NtUserfnHkINLPMSG(PtiCurrent()->sphkCurrent->iHook, nCode, wParam, (LPMSG)lParam);
break;
case WH_JOURNALPLAYBACK:
case WH_JOURNALRECORD:
/*
* These take an OPTIONAL lpEventMsg.
*/
retval = NtUserfnHkOPTINLPEVENTMSG(nCode, wParam, (LPEVENTMSGMSG)lParam);
break;
case WH_DEBUG:
/*
* This takes an lpDebugHookStruct.
*/
retval = NtUserfnHkINLPDEBUGHOOKSTRUCT(nCode, wParam, (LPDEBUGHOOKINFO)lParam);
break;
case WH_KEYBOARD_LL:
/*
* This takes an lpKbdllHookStruct.
*/
retval = NtUserfnHkINLPKBDLLHOOKSTRUCT(nCode, wParam, (LPKBDLLHOOKSTRUCT)lParam);
break;
case WH_MOUSE_LL:
/*
* This takes an lpMsllHookStruct.
*/
retval = NtUserfnHkINLPMSLLHOOKSTRUCT(nCode, wParam, (LPMSLLHOOKSTRUCT)lParam);
break;
case WH_MOUSE:
/*
* This takes an lpMouseHookStructEx.
*/
MouseHook:
retval = NtUserfnHkINLPMOUSEHOOKSTRUCTEX(nCode, wParam, (LPMOUSEHOOKSTRUCTEX)lParam);
break;
#ifdef REDIRECTION
case WH_HITTEST:
/*
* This takes an lpHTHookStruct.
*/
retval = NtUserfnHkINLPHTHOOKSTRUCT(nCode, wParam, (LPHTHOOKSTRUCT)lParam);
break;
#endif // REDIRECTION
default:
RIPMSG1(RIP_WARNING, "NtUserCallNextHookEx: Invalid hook type %x",
PtiCurrent()->sphkCurrent->iHook);
MSGERROR(0);
}
TRACE("NtUserCallNextHookEx");
ENDRECV();
}
HIMC NtUserCreateInputContext(
IN ULONG_PTR dwClientImcData)
{
BEGINRECV(HIMC, (HIMC)NULL);
ValidateIMMEnabled();
if (dwClientImcData == 0) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid hMemClientIC parameter");
MSGERROR(0);
}
retval = (HIMC)CreateInputContext(dwClientImcData);
retval = (HIMC)PtoH((PVOID)retval);
TRACE("NtUserCreateInputContext");
ENDRECV();
}
BOOL NtUserDestroyInputContext(
IN HIMC hImc)
{
PIMC pImc;
BEGINATOMICRECV(BOOL, FALSE);
ValidateIMMEnabled();
ValidateHIMC(pImc, hImc);
retval = DestroyInputContext(pImc);
TRACE("NtUserDestroyInputContext");
ENDATOMICRECV();
}
AIC_STATUS NtUserAssociateInputContext(
IN HWND hwnd,
IN HIMC hImc,
IN DWORD dwFlag)
{
PIMC pImc;
BEGINATOMICRECV_HWND(AIC_STATUS, AIC_ERROR, hwnd);
ValidateIMMEnabled();
ValidateHIMCOPT(pImc, hImc);
retval = AssociateInputContextEx(pwnd, pImc, dwFlag);
TRACE("NtUserAssociateInputContext");
ENDATOMICRECV_HWND();
}
BOOL NtUserUpdateInputContext(
IN HIMC hImc,
IN UPDATEINPUTCONTEXTCLASS UpdateType,
IN ULONG_PTR UpdateValue)
{
PIMC pImc;
BEGINATOMICRECV(BOOL, FALSE);
ValidateIMMEnabled();
ValidateHIMC(pImc, hImc);
retval = UpdateInputContext(pImc, UpdateType, UpdateValue);
TRACE("NtUserUpdateInputContext");
ENDATOMICRECV();
}
ULONG_PTR NtUserQueryInputContext(
IN HIMC hImc,
IN INPUTCONTEXTINFOCLASS InputContextInfo)
{
PTHREADINFO ptiImc;
PIMC pImc;
BEGINRECV_SHARED(ULONG_PTR, 0);
ValidateIMMEnabled();
ValidateHIMC(pImc, hImc);
ptiImc = GETPTI(pImc);
switch (InputContextInfo) {
case InputContextProcess:
retval = (ULONG_PTR)PsGetThreadProcessId(ptiImc->pEThread);
break;
case InputContextThread:
retval = (ULONG_PTR)GETPTIID(ptiImc);
break;
case InputContextDefaultImeWindow:
retval = (ULONG_PTR)HW(ptiImc->spwndDefaultIme);
break;
case InputContextDefaultInputContext:
retval = (ULONG_PTR)PtoH(ptiImc->spDefaultImc);
break;
}
ENDRECV_SHARED();
}
NTSTATUS NtUserBuildHimcList( // private IMM BuildHimcList
IN DWORD idThread,
IN UINT cHimcMax,
OUT HIMC *phimcFirst,
OUT PUINT pcHimcNeeded)
{
PTHREADINFO pti;
UINT cHimcNeeded;
BEGINATOMICRECV(NTSTATUS, STATUS_UNSUCCESSFUL);
ValidateIMMEnabled();
switch (idThread) {
case 0:
pti = PtiCurrent();
break;
case (DWORD)-1:
pti = NULL;
break;
default:
pti = PtiFromThreadId(idThread);
if (pti == NULL || pti->rpdesk == NULL) {
MSGERROR(0);
}
break;
}
/*
* Probe arguments
*/
try {
ProbeForWriteBuffer(phimcFirst, cHimcMax, sizeof(DWORD));
ProbeForWriteUlong(pcHimcNeeded);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
/*
* phimcFirst is client-side.
*/
cHimcNeeded = BuildHimcList(pti, cHimcMax, phimcFirst);
if (cHimcNeeded <= cHimcMax) {
retval = STATUS_SUCCESS;
} else {
retval = STATUS_BUFFER_TOO_SMALL;
}
try {
*pcHimcNeeded = cHimcNeeded;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("NtUserBuildHimcList");
ENDATOMICRECV();
}
BOOL NtUserGetImeInfoEx( // private ImmGetImeInfoEx
IN OUT PIMEINFOEX piiex,
IN IMEINFOEXCLASS SearchType)
{
IMEINFOEX iiex;
BEGINRECV_SHARED(BOOL, FALSE);
ValidateIMMEnabled();
try {
ProbeForWrite(piiex, sizeof(*piiex), sizeof(BYTE));
RtlCopyMemory(&iiex, piiex, sizeof(IMEINFOEX));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = GetImeInfoEx(
_GetProcessWindowStation(NULL),
&iiex,
SearchType);
try {
RtlCopyMemory(piiex, &iiex, sizeof(IMEINFOEX));
} except (StubExceptionHandler(FALSE)) {
}
TRACE("NtUserGetImeInfoEx");
ENDRECV_SHARED();
}
BOOL NtUserSetImeInfoEx(
IN PIMEINFOEX piiex)
{
IMEINFOEX iiex;
BEGINRECV(BOOL, FALSE);
ValidateIMMEnabled();
/*
* Probe arguments
*/
try {
ProbeForRead(piiex, sizeof(*piiex), sizeof(BYTE));
RtlCopyMemory(&iiex, piiex, sizeof(IMEINFOEX));
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = SetImeInfoEx(
_GetProcessWindowStation(NULL),
&iiex);
TRACE("NtUserSetImeInfoEx");
ENDRECV();
}
BOOL NtUserGetImeHotKey(
IN DWORD dwID,
OUT PUINT puModifiers,
OUT PUINT puVKey,
OUT LPHKL phkl)
{
UINT uModifiers;
UINT uVKey;
HKL hkl;
LPHKL phklIn = NULL;
BEGINRECV(BOOL, FALSE);
try {
ProbeForWriteUlong(((PULONG)puModifiers));
ProbeForWriteUlong(((PULONG)puVKey));
if (ARGUMENT_PRESENT(phkl)) {
ProbeForWriteHandle((PHANDLE)phkl);
phklIn = &hkl;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = GetImeHotKey( dwID, &uModifiers, &uVKey, phklIn);
if (retval) {
try {
*puModifiers = uModifiers;
*puVKey = uVKey;
if (ARGUMENT_PRESENT(phkl)) {
*phkl = *phklIn;
}
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetImeHotKey");
ENDRECV();
}
BOOL NtUserSetImeHotKey(
IN DWORD dwID,
IN UINT uModifiers,
IN UINT uVKey,
IN HKL hkl,
IN DWORD dwFlags)
{
BEGINRECV(BOOL, FALSE);
retval = SetImeHotKey( dwID, uModifiers, uVKey, hkl, dwFlags );
TRACE("NtUserSetImeHotKey");
ENDRECV();
}
/*
* Set per-window application level for IME control.
* Used only for Korean 3.x ( both 16 bit and 32 bit)
* applications.
*
* return value
*
* TRUE : success
* FALSE: error
*/
BOOL NtUserSetAppImeLevel(
IN HWND hwnd,
IN DWORD dwLevel)
{
BEGINRECV_HWND(BOOL, FALSE, hwnd);
ValidateIMMEnabled();
if ( GETPTI(pwnd)->ppi == PpiCurrent() ) {
InternalSetProp(pwnd, PROP_IMELEVEL, LongToHandle(dwLevel), PROPF_INTERNAL | PROPF_NOPOOL);
retval = TRUE;
} else {
MSGERROR(0);
}
TRACE("NtUserSetAppImeLevel");
ENDRECV_HWND();
}
/*
* Get per-window application level for IME control.
* Used only for Korean 3.x ( both 16 bit and 32 bit)
* applications.
*
* return value
*
* 0 : error
* non zero value : level
*/
DWORD NtUserGetAppImeLevel(
IN HWND hwnd)
{
BEGINRECV_HWND_SHARED(DWORD, 0, hwnd);
ValidateIMMEnabled();
if ( GETPTI(pwnd)->ppi == PtiCurrentShared()->ppi ) {
retval = (DWORD)(ULONG_PTR)_GetProp(pwnd, PROP_IMELEVEL, TRUE);
} else {
MSGERROR(0);
}
TRACE("NtUserGetAppImeLevel");
ENDRECV_HWND_SHARED();
}
DWORD NtUserCheckImeHotKey(
UINT uVKey,
LPARAM lParam)
{
PIMEHOTKEYOBJ pImeHotKeyObj;
BEGINRECV(DWORD, IME_INVALID_HOTKEY);
if (gpqForeground == NULL)
MSGERROR(0);
ValidateIMMEnabled();
pImeHotKeyObj = CheckImeHotKey(gpqForeground, uVKey, lParam);
if (pImeHotKeyObj) {
retval = pImeHotKeyObj->hk.dwHotKeyID;
} else {
retval = IME_INVALID_HOTKEY;
}
TRACE("NtUserCheckImeHotKey");
ENDRECV();
}
/**************************************************************************\
* NtUserSetImeOwnerWindow
*
* History:
* 17-July-2001 Mohamed Removed re-ownership code and created
ImeSetOwnerWindow. Added this call for ownership
assignment of spwndActive to avoid cyclic
ownership.
\**************************************************************************/
BOOL NtUserSetImeOwnerWindow(
IN HWND hwndIme,
IN HWND hwndFocus)
{
PWND pwndFocus;
BEGINATOMICRECV_HWND(BOOL, FALSE, hwndIme);
ValidateIMMEnabled();
/*
* Make sure this really is an IME window.
*/
if (GETFNID(pwnd) != FNID_IME)
MSGERROR(0);
ValidateHWNDOPT(pwndFocus, hwndFocus);
if (pwndFocus != NULL) {
ImeSetOwnerWindow(pwnd, pwndFocus);
ImeCheckTopmost(pwnd);
} else {
PTHREADINFO ptiImeWnd = GETPTI(pwnd);
PWND pwndActive = ptiImeWnd->pq->spwndActive;
/*
* If pwndFocus == NULL, active window in the queue should become the
* owner window of the IME window, except: if IME related windows
* somehow got a focus, or the active window belongs to the other thread.
*/
if (pwndActive == NULL || pwndActive != pwnd->spwndOwner) {
if (pwndActive == NULL || IsWndImeRelated(pwndActive) || ptiImeWnd != GETPTI(pwndActive)) {
/*
* We should avoid improper window to be an owner of IME window.
*/
ImeSetFutureOwner(pwnd, pwnd->spwndOwner);
} else {
ImeSetOwnerWindow(pwnd, pwndActive);
}
ImeCheckTopmost(pwnd);
}
}
retval = TRUE;
TRACE("NtUserSetImeNewOwner");
ENDATOMICRECV_HWND();
}
VOID NtUserSetThreadLayoutHandles(
IN HKL hklNew,
IN HKL hklOld)
{
PTHREADINFO ptiCurrent;
PKL pklNew;
BEGINRECV_VOID();
ptiCurrent = PtiCurrent();
if (ptiCurrent->spklActive != NULL && ptiCurrent->spklActive->hkl != hklOld)
MSGERROR_VOID();
if ((pklNew = HKLtoPKL(ptiCurrent, hklNew)) == NULL)
MSGERROR_VOID();
/*
* hklPrev is only used for IME, non-IME toggle hotkey.
* The purpose we remember hklPrev is to jump from
* non-IME keyboard layout to the most recently used
* IME layout, or to jump from an IME layout to
* the most recently used non-IME layout. Therefore
* piti->hklPrev is updated only when [ IME -> non-IME ]
* or [ non-IME -> IME ] transition is happened.
*/
if (IS_IME_KBDLAYOUT(hklNew) ^ IS_IME_KBDLAYOUT(hklOld))
ptiCurrent->hklPrev = hklOld;
Lock(&ptiCurrent->spklActive, pklNew);
TRACEVOID("NtUserSetThreadLayoutHandles");
ENDRECV_VOID();
}
VOID NtUserNotifyIMEStatus(
IN HWND hwnd,
IN DWORD dwOpen,
IN DWORD dwConversion)
{
BEGINRECV_HWNDLOCK_VOID(hwnd);
ValidateIMMEnabledVOID();
xxxNotifyIMEStatus( pwnd, dwOpen, dwConversion );
TRACEVOID("NtUserNotifyIMEStatus");
ENDRECV_HWNDLOCK_VOID()
}
BOOL NtUserDisableThreadIme(
IN DWORD dwThreadId)
{
PTHREADINFO ptiCurrent, pti;
BEGINRECV(BOOL, FALSE);
ValidateIMMEnabled();
ptiCurrent = PtiCurrent();
if (dwThreadId == -1) {
// IME processing is disabled for all the thread in the current process
ptiCurrent->ppi->W32PF_Flags |= W32PF_DISABLEIME;
// destory IME stuff
pti = ptiCurrent->ppi->ptiList;
while (pti) {
pti->TIF_flags |= TIF_DISABLEIME;
if (pti->spwndDefaultIme != NULL) {
xxxDestroyWindow(pti->spwndDefaultIme);
// Start the search over from beginning
// Since the ptilist may be updated
pti = ptiCurrent->ppi->ptiList;
continue;
}
pti = pti->ptiSibling;
}
} else {
if (dwThreadId == 0) {
pti = ptiCurrent;
} else {
pti = PtiFromThreadId(dwThreadId);
if (pti == NULL || pti->ppi != ptiCurrent->ppi)
MSGERROR(0);
}
pti->TIF_flags |= TIF_DISABLEIME;
if (pti->spwndDefaultIme != NULL) {
xxxDestroyWindow(pti->spwndDefaultIme);
}
}
retval = TRUE;
TRACE("NtUserDisableThreadIme");
ENDRECV();
}
BOOL
NtUserEnumDisplayMonitors( // API EnumDisplayMonitors
IN HDC hdc,
IN LPCRECT lprcClip,
IN MONITORENUMPROC lpfnEnum,
IN LPARAM dwData)
{
RECT rc;
LPRECT lprc = (LPRECT) lprcClip;
BEGINRECV(BOOL, FALSE);
/*
* Probe arguments
*/
if (ARGUMENT_PRESENT(lprc)) {
try {
rc = ProbeAndReadRect(lprc);
lprc = &rc;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
retval = xxxEnumDisplayMonitors(
hdc,
lprc,
lpfnEnum,
dwData,
FALSE);
TRACE("NtUserEnumDisplayMonitors");
ENDRECV();
}
#ifdef PRERELEASE
/*
* NtUserQueryUserCounters() retrieves statistics on win32k
*
* QUERYUSER_TYPE_USER retrieves the handle counters
*
* QUERYUSER_TYPE_CS will fill the result buffer with USER critical section
* usage data.
*/
BOOL NtUserQueryUserCounters( // private QueryUserCounters
IN DWORD dwQueryType,
IN LPVOID pvIn,
IN DWORD dwInSize,
OUT LPVOID pvResult,
IN DWORD dwOutSize)
{
PDWORD pdwInternalIn = NULL;
PDWORD pdwInternalResult = NULL;
BEGINRECV(BOOL, FALSE);
#if defined (USER_PERFORMANCE)
if (dwQueryType == QUERYUSER_CS) {
CSSTATISTICS* pcsData;
if (dwOutSize != sizeof(CSSTATISTICS)) {
MSGERROR(0);
}
try {
ProbeForWrite((PDWORD)pvResult, dwOutSize, sizeof(DWORD));
/*
* Checking for overflow on these counters is caller responsability
*/
pcsData = (CSSTATISTICS*)pvResult;
pcsData->cExclusive = gCSStatistics.cExclusive;
pcsData->cShared = gCSStatistics.cShared;
pcsData->i64TimeExclusive = gCSStatistics.i64TimeExclusive;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = TRUE;
MSGERROR_VOID();
} else
#endif // USER_PERFORMANCE
if (dwQueryType == QUERYUSER_HANDLES) {
/*
* Probe arguments, dwInSize should be multiple of 4
*/
if (dwInSize & (sizeof(DWORD)-1) ||
dwOutSize != TYPE_CTYPES*dwInSize) {
MSGERROR(0)
}
try {
ProbeForRead((PDWORD)pvIn, dwInSize, sizeof(DWORD));
pdwInternalIn = UserAllocPoolWithQuota(dwInSize, TAG_SYSTEM);
if (!pdwInternalIn) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
RtlCopyMemory(pdwInternalIn, pvIn, dwInSize);
ProbeForWrite(pvResult, dwOutSize, sizeof(DWORD));
pdwInternalResult = UserAllocPoolWithQuota(dwOutSize, TAG_SYSTEM);
if (!pdwInternalResult) {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
_QueryUserHandles(pdwInternalIn,
dwInSize/sizeof(DWORD),
(DWORD (*)[TYPE_CTYPES])pdwInternalResult);
retval = TRUE;
try {
RtlCopyMemory(pvResult, pdwInternalResult, dwOutSize);
} except (StubExceptionHandler(FALSE)) {
MSGERRORCLEANUP(0);
}
} else {
MSGERROR(0);
}
CLEANUPRECV();
if (pdwInternalIn) {
UserFreePool(pdwInternalIn);
}
if (pdwInternalResult) {
UserFreePool(pdwInternalResult);
}
TRACE("NtUserQueryCounters");
ENDRECV();
}
#endif
/***************************************************************************\
* NtUserINOUTGETMENUINFO
*
* History:
* 11-12-96 GerardoB - Created
\***************************************************************************/
MESSAGECALL(INOUTMENUGETOBJECT)
{
MENUGETOBJECTINFO mgoi;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnINOUTMENUGETOBJECT");
UNREFERENCED_PARAMETER(bAnsi);
try {
/*
* Capture now so xxxInterSendMsgEx won't have to.
*/
mgoi = ProbeAndReadMenuGetObjectInfo((PMENUGETOBJECTINFO)lParam);
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&mgoi,
xParam);
try {
*((PMENUGETOBJECTINFO)lParam) = mgoi;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnINOUTMENUGETOBJECT");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTLPCOMBOBOXINFO)
{
COMBOBOXINFO cbinfo;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTLPCOMBOBOXINFO");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteComboBoxInfo((PCOMBOBOXINFO)lParam);
cbinfo = *(PCOMBOBOXINFO)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&cbinfo,
xParam);
try {
*(PCOMBOBOXINFO)lParam = cbinfo;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnOUTLPCOMBOBOXINFO");
ENDRECV_MESSAGECALL();
}
MESSAGECALL(OUTLPSCROLLBARINFO)
{
SCROLLBARINFO sbinfo;
BEGINRECV_MESSAGECALL(0);
TRACETHUNK("fnOUTLPSCROLLBARINFO");
UNREFERENCED_PARAMETER(bAnsi);
/*
* Probe arguments
*/
try {
ProbeForWriteScrollBarInfo((PSCROLLBARINFO)lParam);
sbinfo = *(PSCROLLBARINFO)lParam;
} except (StubExceptionHandler(FALSE)) {
MSGERROR(0);
}
retval = CALLPROC(xpfnProc)(
pwnd,
msg,
wParam,
(LPARAM)&sbinfo,
xParam);
try {
*(PSCROLLBARINFO)lParam = sbinfo;
} except (StubExceptionHandler(FALSE)) {
}
TRACE("fnOUTLPSCROLLBARINFO");
ENDRECV_MESSAGECALL();
}
/***************************************************************************\
* NtUserFlashWindowEx
*
* History:
* 11-16-96 MCostea - Created
\***************************************************************************/
BOOL
NtUserFlashWindowEx( // API FlashWindowEx
IN PFLASHWINFO pfwi)
{
FLASHWINFO fwiInternal;
TL tlpwnd;
PWND pwnd;
BEGINRECV(BOOL, FALSE);
DBG_THREADLOCK_START(FlashWindowEx);
/*
* Probe arguments
*/
try {
fwiInternal = ProbeAndReadStructure(pfwi, FLASHWINFO);
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if ((pwnd = ValidateHwnd(fwiInternal.hwnd)) == NULL ||
fwiInternal.cbSize != sizeof(FLASHWINFO) ||
fwiInternal.dwFlags & ~FLASHW_VALID) {
RIPMSG0(RIP_WARNING, "NtUserFlashWindowEx: Invalid Parameter");
MSGERROR(ERROR_INVALID_PARAMETER);
}
else {
ThreadLockAlwaysWithPti(PtiCurrent(), pwnd, &tlpwnd);
retval = xxxFlashWindow(pwnd,
MAKELONG(fwiInternal.dwFlags, fwiInternal.uCount),
fwiInternal.dwTimeout);
ThreadUnlock(&tlpwnd);
}
DBG_THREADLOCK_END(FlashWindowEx);
TRACE("NtUserFlashWindowEx");
ENDRECV();
}
BOOL NtUserUpdateLayeredWindow( // API UpdateLayeredWindow
IN HWND hwnd,
IN HDC hdcDst,
IN POINT *pptDst,
IN SIZE *psize,
IN HDC hdcSrc,
IN POINT *pptSrc,
IN COLORREF crKey,
IN BLENDFUNCTION *pblend,
IN DWORD dwFlags)
{
PWND pwnd;
POINT ptSrc;
SIZE size;
POINT ptDst;
BLENDFUNCTION blend;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWND(pwnd, hwnd);
/*
* Probe and validate arguments.
*/
try {
if (ARGUMENT_PRESENT(pptSrc)) {
ptSrc = ProbeAndReadPoint(pptSrc);
pptSrc = &ptSrc;
}
if (ARGUMENT_PRESENT(psize)) {
size = ProbeAndReadSize(psize);
psize = &size;
if (psize->cx < 0 || psize->cy < 0) {
MSGERROR(ERROR_INVALID_PARAMETER); // this is a jump out of try!
}
}
if (ARGUMENT_PRESENT(pptDst)) {
ptDst = ProbeAndReadPoint(pptDst);
pptDst = &ptDst;
}
if (ARGUMENT_PRESENT(pblend)) {
blend = ProbeAndReadBlendfunction(pblend);
pblend = &blend;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (dwFlags & ~ULW_VALID) {
RIPMSG0(RIP_WARNING, "UpdateLayeredWindow: Invalid Parameter");
MSGERROR(ERROR_INVALID_PARAMETER);
} else {
retval = _UpdateLayeredWindow(
pwnd,
hdcDst,
pptDst,
psize,
hdcSrc,
pptSrc,
crKey,
pblend,
dwFlags);
}
TRACE("NtUserUpdateLayeredWindow");
ENDATOMICRECV();
}
BOOL NtUserGetLayeredWindowAttributes(
IN HWND hwnd,
OUT OPTIONAL COLORREF *pcrKey,
OUT OPTIONAL BYTE *pbAlpha,
OUT OPTIONAL DWORD *pdwFlags)
{
PWND pwnd;
COLORREF crKey;
BYTE bAlpha;
DWORD dwFlags;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWND(pwnd, hwnd);
retval = _GetLayeredWindowAttributes(pwnd, &crKey, &bAlpha, &dwFlags);
if (retval) {
try {
if (ARGUMENT_PRESENT(pcrKey)) {
ProbeForWrite(pcrKey, sizeof(COLORREF), sizeof(COLORREF));
*pcrKey = crKey;
}
if (ARGUMENT_PRESENT(pbAlpha)) {
ProbeForWrite(pbAlpha, sizeof(BYTE), sizeof(BYTE));
*pbAlpha = bAlpha;
}
if (ARGUMENT_PRESENT(pdwFlags)) {
ProbeForWrite(pdwFlags, sizeof(DWORD), sizeof(DWORD));
*pdwFlags = dwFlags & ULW_VALID;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
TRACE("NtUserGetLayeredWindowAttributes");
ENDATOMICRECV();
}
BOOL NtUserSetLayeredWindowAttributes(
IN HWND hwnd,
IN COLORREF crKey,
IN BYTE bAlpha,
IN DWORD dwFlags)
{
PWND pwnd;
BEGINATOMICRECV(BOOL, FALSE);
ValidateHWND(pwnd, hwnd);
if (dwFlags & ~LWA_VALID) {
RIPMSG0(RIP_WARNING, "SetLayeredWindowAttributes: Invalid Parameter");
MSGERROR(ERROR_INVALID_PARAMETER);
} else {
retval = _SetLayeredWindowAttributes(pwnd, crKey, bAlpha, dwFlags);
}
TRACE("NtUserSetLayeredWindowAttributes");
ENDATOMICRECV();
}
BOOL NtUserPrintWindow(
IN HWND hwnd,
IN HDC hdcBlt,
IN UINT nFlags)
{
BEGINRECV_HWNDLOCK_ND(BOOL, FALSE, hwnd);
if ((nFlags & PW_VALID) != nFlags) {
RIPMSG2(RIP_WARNING, "PrintWindow: Invalid Parameter nFlags=%d on HWND=0x%p", nFlags, hwnd);
MSGERROR(ERROR_INVALID_PARAMETER);
} else {
retval = xxxPrintWindow(pwndND, hdcBlt, nFlags);
}
TRACE("NtUserPrintWindow");
ENDRECV_HWNDLOCK_ND();
}
/***************************************************************************\
* GetHDevName
* Called by NtUserCallTwoParam in GetMonitorInfo to query
* gre about the HDev name
*
* 1-July-1998 MCostea created
\***************************************************************************/
BOOL GetHDevName(HMONITOR hMon, PWCHAR pName)
{
PMONITOR pMonitor;
WCHAR wszName[CCHDEVICENAME];
BOOL fResult = FALSE;
CheckCritIn();
pMonitor = ValidateHmonitor(hMon);
if (!pMonitor) {
return FALSE;
}
if (DrvGetHdevName(pMonitor->hDev, wszName)) {
/*
* Make sure it's NULL terminated.
*/
wszName[CCHDEVICENAME - 1] = 0;
try {
ProbeForWrite(pName, CCHDEVICENAME * sizeof(WCHAR), sizeof(DWORD));
RtlCopyMemory(pName, wszName, CCHDEVICENAME * sizeof(WCHAR));
} except (StubExceptionHandler(TRUE)) {
goto _exit;
}
fResult = TRUE;
}
_exit:
return fResult;
}
#ifdef GENERIC_INPUT
/***************************************************************************\
* NtUserGetRawInputData
* Gets the HIDDATA structure from its HRAWINPUT handle.
*
* Returns the number of bytes written to pRawInput. On error, it returns -1 and zero
* in *pcbSize. If pRawInput is NULL, it returns zero and the number of bytes need to
* receive the data in pcbSize.
*
* If pRawInput is not big enough, it return -1 and the number of bytes needed to
* receive the data in pcbSize.
*
* 25-February-2000 JasonSch created
\***************************************************************************/
UINT NtUserGetRawInputData(
HRAWINPUT hRawInput,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize,
UINT cbSizeHeader)
{
PHIDDATA pHidData;
UINT cbOutSize, cbBufferSize;
BEGINATOMICRECV(UINT, (UINT)-1);
if (cbSizeHeader != sizeof(RAWINPUTHEADER)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
/*
* Get the report data contents.
*/
pHidData = HMValidateHandle(hRawInput, TYPE_HIDDATA);
if (pHidData == NULL) {
RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING, "NtUserGetRawInputData: invalid handle %p", hRawInput);
MSGERROR(0);
}
/*
* Check the type of the raw input data.
*/
switch (pHidData->rid.header.dwType) {
case RIM_TYPEMOUSE:
case RIM_TYPEKEYBOARD:
case RIM_TYPEHID:
break;
default:
/*
* The handle is valid, but the internal state of the object is
* weird.
*/
RIPERR2(ERROR_INVALID_HANDLE,
RIP_ERROR,
"Invalid type 0x%x in pHidData %p",
pHidData->rid.header.dwType,
pHidData);
MSGERROR(0);
}
/*
* Calculate the size of the data
*/
switch (uiCommand) {
case RID_INPUT:
cbOutSize = pHidData->rid.header.dwSize;
break;
case RID_HEADER:
cbOutSize = sizeof pHidData->rid.header;
break;
default:
MSGERROR(ERROR_INVALID_PARAMETER);
break;
}
#if DBG
if (pHidData->rid.header.dwType == RIM_TYPEHID && uiCommand == RID_INPUT) {
/*
* TYPEHID has variable length array of report data.
*/
TAGMSG3(DBGTAG_PNP, "NtUserGetRawInputData: pHidData=%p, dwOutSize=%x, calc'ed=%x",
pHidData,
cbOutSize, FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + pHidData->rid.data.hid.dwSizeHid * pHidData->rid.data.hid.dwCount);
UserAssert(cbOutSize == FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + pHidData->rid.data.hid.dwSizeHid * pHidData->rid.data.hid.dwCount);
}
#endif
if (pData == NULL) {
/*
* The caller wants to get the required size of the buffer.
*/
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbOutSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = 0;
} else {
try {
ProbeForRead(pcbSize, sizeof(UINT), sizeof(DWORD));
cbBufferSize = *pcbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
if (cbBufferSize >= cbOutSize) {
try {
switch (uiCommand) {
case RID_INPUT:
ProbeForWrite(pData, cbOutSize, sizeof(DWORD));
RtlCopyMemory(pData, &pHidData->rid, cbOutSize);
break;
case RID_HEADER:
{
PRAWINPUTHEADER pHeader = (PRAWINPUTHEADER)pData;
UserAssert(cbOutSize == sizeof(RAWINPUTHEADER));
ProbeAndWriteStructure(pHeader, pHidData->rid.header, RAWINPUTHEADER);
}
break;
default:
UserAssert(FALSE);
break;
}
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
retval = cbOutSize;
} else {
retval = errret;
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbBufferSize;
UserSetLastError(ERROR_INSUFFICIENT_BUFFER);
} except(StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
}
}
TRACE("NtUserGetRawInputData");
ENDATOMICRECV();
}
UINT NtUserGetRawInputDeviceInfo(
HANDLE hDevice,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize)
{
PDEVICEINFO pDeviceInfo;
UINT cbOutSize = 0;
UINT cbBufferSize;
BEGINATOMICRECV(DWORD, (UINT)-1);
try {
ProbeForRead(pcbSize, sizeof(UINT), sizeof(DWORD));
cbBufferSize = *pcbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
EnterDeviceInfoListCrit();
pDeviceInfo = HMValidateHandle(hDevice, TYPE_DEVICEINFO);
if (pDeviceInfo == NULL) {
RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING, "NtUserGetRawInputDeviceInfo: invalid handle=%p", hDevice);
MSGERRORCLEANUP(0);
}
/*
* Compute the size of the output and evaluate the uiCommand.
*/
switch (uiCommand) {
case RIDI_PREPARSEDDATA:
if (pDeviceInfo->type == DEVICE_TYPE_HID) {
cbOutSize = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.DescriptorSize;
} else {
cbOutSize = 0;
}
break;
case RIDI_DEVICENAME:
/*
* N.b. UNICODE_STRING counts the length by the BYTE count, not by the character count.
* Our APIs always treat the strings by the character count. Thus, for RIDI_DEVICNAME
* only, cbOutSize holds the character count, not the byte count, in spite of its
* name. Confusing, but cch is the way to be consistent.
*/
cbOutSize = pDeviceInfo->ustrName.Length / sizeof(WCHAR) + 1; // for Null terminator
break;
case RIDI_DEVICEINFO:
cbOutSize = sizeof(RID_DEVICE_INFO);
break;
default:
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "NtUserGetRawInputDeviceInfo: invalid uiCommand=%x", uiCommand);
MSGERRORCLEANUP(0);
break;
}
if (pData == NULL) {
/*
* The app wants to get the required size.
*/
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbOutSize;
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = 0;
} else {
if (cbBufferSize >= cbOutSize) {
try {
ProbeForWrite(pData, cbBufferSize, sizeof(DWORD));
switch (uiCommand) {
case RIDI_PREPARSEDDATA:
if (pDeviceInfo->type == DEVICE_TYPE_HID) {
RtlCopyMemory(pData, pDeviceInfo->hid.pHidDesc->pPreparsedData, cbOutSize);
} else {
UserAssert(cbOutSize == 0);
}
break;
case RIDI_DEVICENAME:
UserAssert((cbOutSize -1) * sizeof(WCHAR) == pDeviceInfo->ustrName.Length);
RtlCopyMemory(pData, pDeviceInfo->ustrName.Buffer, pDeviceInfo->ustrName.Length);
((WCHAR*)pData)[cbOutSize - 1] = 0; // make it null terminated
break;
case RIDI_DEVICEINFO:
{
PRID_DEVICE_INFO prdi = (PRID_DEVICE_INFO)pData;
ProbeForRead(prdi, sizeof(UINT), sizeof(DWORD));
if (prdi->cbSize != cbOutSize) {
MSGERRORCLEANUP(ERROR_INVALID_PARAMETER);
}
ProbeForWrite(prdi, sizeof(RID_DEVICE_INFO), sizeof(DWORD));
RtlZeroMemory(prdi, sizeof(RID_DEVICE_INFO));
prdi->cbSize = cbOutSize;
switch (pDeviceInfo->type) {
case DEVICE_TYPE_HID:
prdi->dwType = RIM_TYPEHID;
prdi->hid.dwVendorId = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.VendorID;
prdi->hid.dwProductId = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.ProductID;
prdi->hid.dwVersionNumber = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.VersionNumber;
prdi->hid.usUsagePage = pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage;
prdi->hid.usUsage = pDeviceInfo->hid.pHidDesc->hidpCaps.Usage;
break;
case DEVICE_TYPE_MOUSE:
prdi->dwType = RIM_TYPEMOUSE;
prdi->mouse.dwId = pDeviceInfo->mouse.Attr.MouseIdentifier;
prdi->mouse.dwNumberOfButtons = pDeviceInfo->mouse.Attr.NumberOfButtons;
prdi->mouse.dwSampleRate = pDeviceInfo->mouse.Attr.SampleRate;
break;
case DEVICE_TYPE_KEYBOARD:
prdi->dwType = RIM_TYPEKEYBOARD;
prdi->keyboard.dwType = GET_KEYBOARD_DEVINFO_TYPE(pDeviceInfo);
prdi->keyboard.dwSubType = GET_KEYBOARD_DEVINFO_SUBTYPE(pDeviceInfo);
prdi->keyboard.dwKeyboardMode = pDeviceInfo->keyboard.Attr.KeyboardMode;
prdi->keyboard.dwNumberOfFunctionKeys = pDeviceInfo->keyboard.Attr.NumberOfFunctionKeys;
prdi->keyboard.dwNumberOfIndicators = pDeviceInfo->keyboard.Attr.NumberOfIndicators;
prdi->keyboard.dwNumberOfKeysTotal = pDeviceInfo->keyboard.Attr.NumberOfKeysTotal;
break;
}
}
break;
default:
UserAssert(FALSE);
break;
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = cbOutSize;
} else {
/*
* The buffer size is too small.
* Returns error, storing the required size in *pcbSize.
*/
retval = errret;
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbOutSize;
UserSetLastError(ERROR_INSUFFICIENT_BUFFER);
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
}
}
CLEANUPRECV();
LeaveDeviceInfoListCrit();
TRACE("NtUserGetRawInputDeviceInfo");
ENDATOMICRECV();
}
UINT NtUserGetRawInputDeviceList(
PRAWINPUTDEVICELIST pRawInputDeviceList,
PUINT puiNumDevices,
UINT cbSize)
{
UINT nDevices = 0;
PDEVICEINFO pDeviceInfo;
BEGINATOMICRECV(DWORD, (UINT)-1);
if (cbSize != sizeof(RAWINPUTDEVICELIST)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
EnterDeviceInfoListCrit();
/*
* Firstly, count up the number of devices
* attached to the system.
*/
for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) {
++nDevices;
}
if (pRawInputDeviceList == NULL) {
/*
* Application simply wants the number of devices.
*/
try {
/*
* Store number of devices.
*/
ProbeForWrite(puiNumDevices, sizeof(UINT), sizeof(DWORD));
*puiNumDevices = nDevices;
/*
* Set retval as 0, to indicate the API succeeded.
*/
retval = 0;
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
} else {
/*
* Write out the device info list.
*/
try {
UINT i;
ProbeForRead(puiNumDevices, sizeof(UINT), sizeof(DWORD));
if (*puiNumDevices < nDevices) {
/*
* If the buffer size is not sufficient, set the required
* number of buffers, then return error.
*/
ProbeForWrite(puiNumDevices, sizeof(UINT), sizeof(DWORD));
*puiNumDevices = nDevices;
MSGERRORCLEANUP(ERROR_INSUFFICIENT_BUFFER);
}
ProbeForWrite(pRawInputDeviceList, sizeof(RAWINPUTDEVICELIST) * nDevices, sizeof(HANDLE));
for (i = 0, pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext, ++i) {
UserAssert(i < nDevices);
pRawInputDeviceList[i].hDevice = PtoHq(pDeviceInfo);
pRawInputDeviceList[i].dwType = pDeviceInfo->type;
}
UserAssert(i == nDevices);
retval = i;
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
}
CLEANUPRECV();
LeaveDeviceInfoListCrit();
TRACE("NtUserGetRawInputDeviceList");
ENDATOMICRECV();
}
BOOL NtUserRegisterRawInputDevices(
PRAWINPUTDEVICE pRawInputDevices,
UINT uiNumDevices,
UINT cbSize)
{
PVOID pLocalRawInputDevices = NULL;
TL tlBuffer;
PTHREADINFO ptiCurrent;
BEGINATOMICRECV(BOOL, FALSE);
ptiCurrent = PtiCurrent();
if (pRawInputDevices == NULL || uiNumDevices == 0 || cbSize != sizeof(RAWINPUTDEVICE)) {
/*
* TBD:
* What should we do if pRawInputDevices is NULL?
* Perhaps should start receiving all HID input?
*/
MSGERROR(ERROR_INVALID_PARAMETER);
}
try {
ProbeForReadBuffer(pRawInputDevices, uiNumDevices, sizeof(PRAWINPUTDEVICE));
pLocalRawInputDevices = UserAllocPoolWithQuota(uiNumDevices * cbSize, TAG_SYSTEM);
if (pLocalRawInputDevices) {
ThreadLockPool(ptiCurrent, pLocalRawInputDevices, &tlBuffer);
RtlCopyMemory(pLocalRawInputDevices, pRawInputDevices, uiNumDevices * cbSize);
} else {
ExRaiseStatus(STATUS_NO_MEMORY);
}
} except (StubExceptionHandler(TRUE)) {
MSGERRORCLEANUP(0);
}
retval = _RegisterRawInputDevices(pLocalRawInputDevices, uiNumDevices);
CLEANUPRECV();
if (pLocalRawInputDevices) {
ThreadUnlockAndFreePool(ptiCurrent, &tlBuffer);
}
TRACE("NtUserSetRawInputDevices");
ENDATOMICRECV();
}
UINT NtUserGetRegisteredRawInputDevices(
PRAWINPUTDEVICE pRawInputDevices,
PUINT puiNumDevices,
UINT cbSize)
{
BEGINATOMICRECV(DWORD, (UINT)-1);
if (cbSize != sizeof(RAWINPUTDEVICE)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
retval = _GetRegisteredRawInputDevices(pRawInputDevices, puiNumDevices);
ENDATOMICRECV();
}
#ifdef _WIN64
# ifndef QWORD_ALIGN
# define QWORD_ALIGN(x) (((x) + 7) & ~7)
# endif
#define RI_ALIGN(x) QWORD_ALIGN(x)
#else
#define RI_ALIGN(x) DWORD_ALIGN(x)
#endif // _Win64
UINT NtUserGetRawInputBuffer(
PRAWINPUT pData,
PUINT pcbSize,
#ifdef LATER
DWORD dwFlags,
#endif
UINT cbSizeHeader)
{
UINT cbBytes = 0; /* # of bytes written to the buffer */
UINT cbWriteSize = 0; /* the # of bytes to write into pData */
PQMSG pqmsg;
PTHREADINFO ptiCurrent;
PQ pq;
PHIDDATA pHidData;
UINT cbBufferSize; /* the size of the passed in buffer */
UINT cRICount = 0; /* # of RAWINPUT structures written to the buffer */
BEGINATOMICRECV(UINT, -1);
#ifdef LATER
if (dwFlags != 0) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
#endif
if (cbSizeHeader != sizeof(RAWINPUTHEADER)) {
MSGERROR(ERROR_INVALID_PARAMETER);
}
try {
ProbeForRead(pcbSize, sizeof(UINT), sizeof(DWORD));
cbBufferSize = *pcbSize;
} except (StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
ptiCurrent = PtiCurrent();
pq = ptiCurrent->pq;
pqmsg = pq->mlInput.pqmsgRead;
while (pqmsg) {
// Remember the next pqmsg, for the current pqmsg may be freed in this loop
PQMSG pqmsgNext = pqmsg->pqmsgNext;
if (pqmsg->msg.message == WM_INPUT) {
pHidData = HMValidateHandle((HRAWINPUT)pqmsg->msg.lParam, TYPE_HIDDATA);
UserAssert(pHidData != NULL);
cbWriteSize = RI_ALIGN(pHidData->rid.header.dwSize);
if (pData == NULL || (cbBytes + cbWriteSize) > cbBufferSize) {
break;
}
try {
ProbeForWrite(pData, cbWriteSize, sizeof(DWORD));
RtlCopyMemory(pData, &pHidData->rid, pHidData->rid.header.dwSize);
++cRICount;
(PBYTE)pData += cbWriteSize;
cbBytes += cbWriteSize;
} except (StubExceptionHandler(TRUE)) {
RIPMSG3(RIP_WARNING, "NtUserGetRawInputBuffer: exception: src=%p target=%p %x bytes",
&pHidData->rid, pData, pHidData->rid.header.dwSize);
MSGERROR(0);
}
// Update the time of the messages
ptiCurrent->timeLast = pqmsg->msg.time;
// Remove this msg from the queue
DelQEntry(&pq->mlInput, pqmsg);
FreeHidData(pHidData);
}
pqmsg = pqmsgNext;
}
/*
* If pqmsg is NULL then we went through the entire MLIST. This will
* only happen if we have copied all of the WM_INPUTs into the buffer or
* there were none to begin with. Either way, there are none left. So
* turn off QS_RAWINPUT.
*/
if (pqmsg == NULL && pData != NULL) {
ClearWakeBit(ptiCurrent, QS_RAWINPUT, FALSE);
}
if (cbBufferSize <= cbWriteSize || pData == NULL) {
if (pData == NULL) {
retval = 0;
} else {
retval = errret;
UserSetLastError(ERROR_INSUFFICIENT_BUFFER);
}
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbWriteSize;
} except(StubExceptionHandler(TRUE)) {
MSGERROR(0);
}
} else {
// Update the last time read
SET_TIME_LAST_READ(ptiCurrent);
retval = cRICount;
}
TRACE("NtUserGetRawInputBuffer");
ENDATOMICRECV();
}
#undef RI_ALIGN
#endif
BOOL NtUserValidateTimerCallback(
IN ULONG_PTR pfnCallback)
{
BEGINRECV_SHARED(BOOL, FALSE);
retval = ValidateTimerCallback(PtiCurrentShared(), pfnCallback);
ENDRECV_SHARED();
}