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.
515 lines
17 KiB
515 lines
17 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: getsetc.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* This module contains window manager information routines
|
|
*
|
|
* History:
|
|
* 10-Mar-1993 JerrySh Pulled functions from user\server.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/***************************************************************************\
|
|
* _GetWindowWord (supports the GetWindowWord API)
|
|
*
|
|
* Return a window word. Positive index values return application window words
|
|
* while negative index values return system window words. The negative
|
|
* indices are published in WINDOWS.H.
|
|
*
|
|
* History:
|
|
* 11-26-90 darrinm Wrote.
|
|
\***************************************************************************/
|
|
|
|
WORD _GetWindowWord(
|
|
PWND pwnd,
|
|
int index)
|
|
{
|
|
if (GETFNID(pwnd) != 0) {
|
|
if ((index >= 0) && (index <
|
|
(int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
|
|
|
|
switch (GETFNID(pwnd)) {
|
|
case FNID_MDICLIENT:
|
|
if (index == 0)
|
|
break;
|
|
goto DoDefault;
|
|
|
|
case FNID_BUTTON:
|
|
/*
|
|
* CorelDraw does a get/set on the first button window word.
|
|
* Allow it to.
|
|
*/
|
|
if (index == 0) {
|
|
/*
|
|
* Since we now use a lookaside buffer for the control's
|
|
* private data, we need to indirect into this structure.
|
|
*/
|
|
PBUTN pbutn = ((PBUTNWND)pwnd)->pbutn;
|
|
if (!pbutn || (LONG_PTR)pbutn == (LONG_PTR)-1) {
|
|
return 0;
|
|
} else {
|
|
return (WORD)(pbutn->buttonState);
|
|
}
|
|
}
|
|
goto DoDefault;
|
|
|
|
case FNID_DIALOG:
|
|
if (index == DWLP_USER)
|
|
return LOWORD(((PDIALOG)pwnd)->unused);
|
|
if (index == DWLP_USER+2)
|
|
return HIWORD(((PDIALOG)pwnd)->unused);
|
|
goto DoDefault;
|
|
|
|
default:
|
|
DoDefault:
|
|
RIPERR3(ERROR_INVALID_INDEX,
|
|
RIP_WARNING,
|
|
"GetWindowWord: Trying to read private server data pwnd=(%#p) index=(%ld) fnid=(%lX)",
|
|
pwnd, index, (DWORD)pwnd->fnid);
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index == GWLP_USERDATA)
|
|
return (WORD)pwnd->dwUserData;
|
|
|
|
if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pwnd->cbwndExtra)) {
|
|
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
} else {
|
|
return *((WORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pwnd + 1) + index));
|
|
}
|
|
}
|
|
|
|
ULONG_PTR GetWindowData(PWND pwnd, int index, BOOL bAnsi);
|
|
|
|
/***************************************************************************\
|
|
* _GetWindowLong (supports GetWindowLongA/W API)
|
|
*
|
|
* Return a window long. Positive index values return application window longs
|
|
* while negative index values return system window longs. The negative
|
|
* indices are published in WINDOWS.H.
|
|
*
|
|
* History:
|
|
* 11-26-90 darrinm Wrote.
|
|
\***************************************************************************/
|
|
|
|
ULONG_PTR _GetWindowLongPtr(
|
|
PWND pwnd,
|
|
int index,
|
|
BOOL bAnsi)
|
|
{
|
|
ULONG_PTR dwProc;
|
|
DWORD dwCPDType = 0;
|
|
ULONG_PTR UNALIGNED * KPTR_MODIFIER pudw;
|
|
|
|
/*
|
|
* If it's a dialog window, only a few indices are permitted.
|
|
*/
|
|
if (GETFNID(pwnd) != 0) {
|
|
if (TestWF(pwnd, WFDIALOGWINDOW)) {
|
|
switch (index) {
|
|
case DWLP_DLGPROC: // See similar case GWLP_WNDGPROC
|
|
|
|
/*
|
|
* Hide the window proc from other processes
|
|
*/
|
|
if (!TestWindowProcess(pwnd)) {
|
|
RIPERR1(ERROR_ACCESS_DENIED,
|
|
RIP_WARNING,
|
|
"Access denied to \"pwnd\" (%#p) in _GetWindowLong",
|
|
pwnd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
dwProc = (ULONG_PTR)PDLG(pwnd)->lpfnDlg;
|
|
|
|
/*
|
|
* If a proc exists check it to see if we need a translation
|
|
*/
|
|
if (dwProc) {
|
|
|
|
/*
|
|
* May need to return a CallProc handle if there is an
|
|
* Ansi/Unicode transition
|
|
*/
|
|
if (bAnsi != ((PDLG(pwnd)->flags & DLGF_ANSI) ? TRUE : FALSE)) {
|
|
dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
|
|
}
|
|
|
|
if (dwCPDType) {
|
|
ULONG_PTR cpd;
|
|
|
|
cpd = GetCPD(pwnd, dwCPDType | CPD_DIALOG, dwProc);
|
|
|
|
if (cpd) {
|
|
dwProc = cpd;
|
|
} else {
|
|
RIPMSG0(RIP_WARNING, "GetWindowLong unable to alloc CPD returning handle\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* return proc (or CPD handle)
|
|
*/
|
|
return dwProc;
|
|
|
|
case DWLP_MSGRESULT:
|
|
return (ULONG_PTR)((PDIALOG)pwnd)->resultWP;
|
|
|
|
case DWLP_USER:
|
|
return (ULONG_PTR)((PDIALOG)pwnd)->unused;
|
|
|
|
default:
|
|
if (index >= 0 && index < DLGWINDOWEXTRA) {
|
|
RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (index >= 0 &&
|
|
(index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
|
|
switch (GETFNID(pwnd)) {
|
|
case FNID_MDICLIENT:
|
|
/*
|
|
* Allow the 0 index (which is reserved) to be set/get.
|
|
* Quattro Pro 1.0 uses this index!
|
|
*/
|
|
if (index != 0)
|
|
break;
|
|
|
|
goto GetData;
|
|
break;
|
|
|
|
case FNID_EDIT:
|
|
|
|
if (index != 0)
|
|
break;
|
|
|
|
/*
|
|
* If we get to this point we need to return the first
|
|
* entry in the lookaside. This will provide backward
|
|
* compatibilty for 3.51 that allowed edit-controls to
|
|
* do this. PeachTree is one app which required this.
|
|
*/
|
|
pudw = (ULONG_PTR UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pwnd + 1));
|
|
|
|
/*
|
|
* Do not dereference the pointer if we are not in
|
|
* the proper address space. Apps like Spyxx like to
|
|
* do this on other process' windows
|
|
*/
|
|
return (TestWindowProcess(pwnd) ? *(ULONG_PTR UNALIGNED *)*pudw : (ULONG_PTR)pudw);
|
|
|
|
}
|
|
|
|
RIPERR3(ERROR_INVALID_INDEX,
|
|
RIP_WARNING,
|
|
"GetWindowLong: Trying to read private server data pwnd=(%#p) index=(%ld) fnid (%lX)",
|
|
pwnd, index, (DWORD)pwnd->fnid);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index < 0) {
|
|
return GetWindowData(pwnd, index, bAnsi);
|
|
} else {
|
|
if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pwnd->cbwndExtra) {
|
|
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
} else {
|
|
|
|
GetData:
|
|
pudw = (ULONG_PTR UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pwnd + 1) + index);
|
|
return *pudw;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _WIN64
|
|
DWORD _GetWindowLong(
|
|
PWND pwnd,
|
|
int index,
|
|
BOOL bAnsi)
|
|
{
|
|
DWORD UNALIGNED * KPTR_MODIFIER pudw;
|
|
|
|
/*
|
|
* If it's a dialog window, only a few indices are permitted.
|
|
*/
|
|
if (GETFNID(pwnd) != 0) {
|
|
if (TestWF(pwnd, WFDIALOGWINDOW)) {
|
|
switch (index) {
|
|
case DWLP_DLGPROC: // See similar case GWLP_WNDPROC
|
|
RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "GetWindowLong: invalid index %d", index);
|
|
return 0;
|
|
|
|
case DWLP_MSGRESULT:
|
|
return (DWORD)((PDIALOG)pwnd)->resultWP;
|
|
|
|
case DWLP_USER:
|
|
return (DWORD)((PDIALOG)pwnd)->unused;
|
|
|
|
default:
|
|
if (index >= 0 && index < DLGWINDOWEXTRA) {
|
|
RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (index >= 0 &&
|
|
(index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
|
|
switch (GETFNID(pwnd)) {
|
|
case FNID_MDICLIENT:
|
|
/*
|
|
* Allow the 0 index (which is reserved) to be set/get.
|
|
* Quattro Pro 1.0 uses this index!
|
|
*/
|
|
if (index != 0)
|
|
break;
|
|
|
|
goto GetData;
|
|
break;
|
|
|
|
case FNID_EDIT:
|
|
|
|
if (index != 0)
|
|
break;
|
|
|
|
/*
|
|
* If we get to this point we need to return the first
|
|
* entry in the lookaside. This will provide backward
|
|
* compatibilty for 3.51 that allowed edit-controls to
|
|
* do this. PeachTree is one app which required this.
|
|
*/
|
|
pudw = (DWORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pwnd + 1));
|
|
|
|
/*
|
|
* Do not dereference the pointer if we are not in
|
|
* the proper address space. Apps like Spyxx like to
|
|
* do this on other process' windows
|
|
*/
|
|
return (TestWindowProcess(pwnd) ? *(DWORD UNALIGNED *)*(ULONG_PTR UNALIGNED *)pudw : PtrToUlong(pudw));
|
|
|
|
|
|
}
|
|
|
|
RIPERR3(ERROR_INVALID_INDEX,
|
|
RIP_WARNING,
|
|
"GetWindowLong: Trying to read private server data pwnd=(%#p) index=(%ld) fnid (%lX)",
|
|
pwnd, index, (DWORD)pwnd->fnid);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index < 0) {
|
|
if ((index != GWL_STYLE) && (index != GWL_EXSTYLE) && (index != GWL_ID) && (index != GWLP_USERDATA)) {
|
|
RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "GetWindowLong: invalid index %d", index);
|
|
return 0;
|
|
}
|
|
return (DWORD)GetWindowData(pwnd, index, bAnsi);
|
|
} else {
|
|
if ((UINT)index + sizeof(DWORD) > (UINT)pwnd->cbwndExtra) {
|
|
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
} else {
|
|
|
|
GetData:
|
|
pudw = (DWORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pwnd + 1) + index);
|
|
return *pudw;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
* GetWindowData
|
|
*
|
|
* History:
|
|
* 11-26-90 darrinm Wrote.
|
|
\***************************************************************************/
|
|
|
|
ULONG_PTR GetWindowData(
|
|
PWND pwnd,
|
|
int index,
|
|
BOOL bAnsi)
|
|
{
|
|
KERNEL_ULONG_PTR dwProc;
|
|
DWORD dwCPDType = 0;
|
|
PWND pwndParent;
|
|
|
|
switch (index) {
|
|
case GWLP_USERDATA:
|
|
return KERNEL_ULONG_PTR_TO_ULONG_PTR(pwnd->dwUserData);
|
|
|
|
case GWL_EXSTYLE:
|
|
/*
|
|
* Apps should not mess with unused bits. We use them privately
|
|
*/
|
|
return pwnd->ExStyle & WS_EX_ALLVALID;
|
|
|
|
case GWL_STYLE:
|
|
return pwnd->style;
|
|
|
|
case GWLP_ID:
|
|
if (TestwndChild(pwnd)) {
|
|
return (ULONG_PTR)pwnd->spmenu;
|
|
} else if (pwnd->spmenu != NULL) {
|
|
PMENU pmenu;
|
|
|
|
pmenu = REBASEALWAYS(pwnd, spmenu);
|
|
return (ULONG_PTR)PtoH(pmenu);
|
|
}
|
|
return 0;
|
|
|
|
case GWLP_HINSTANCE:
|
|
return (ULONG_PTR)pwnd->hModule;
|
|
|
|
case GWLP_WNDPROC: // See similar case DWLP_DLGPROC
|
|
/*
|
|
* Hide the window proc from other processes
|
|
*/
|
|
if (!TestWindowProcess(pwnd)) {
|
|
RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "Can not subclass another process's window %#p", pwnd);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* If the client queries a server-side winproc we return the
|
|
* address of the client-side winproc (expecting ANSI or Unicode
|
|
* depending on bAnsi)
|
|
*/
|
|
if (TestWF(pwnd, WFSERVERSIDEPROC)) {
|
|
dwProc = MapServerToClientPfn((KERNEL_ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
|
|
if (dwProc == 0)
|
|
RIPMSG1(RIP_WARNING, "GetWindowLong: GWL_WNDPROC: Kernel-side wndproc can't be mapped for pwnd=%#p", pwnd);
|
|
} else {
|
|
|
|
/*
|
|
* Keep edit control behavior compatible with NT 3.51.
|
|
*/
|
|
if (GETFNID(pwnd) == FNID_EDIT) {
|
|
dwProc = (ULONG_PTR)MapKernelClientFnToClientFn(pwnd->lpfnWndProc);
|
|
goto CheckAnsiUnicodeMismatch;
|
|
} else {
|
|
PCLS pcls = REBASEALWAYS(pwnd, pcls);
|
|
dwProc = MapClientNeuterToClientPfn(pcls, (KERNEL_ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
|
|
}
|
|
|
|
/*
|
|
* If the client mapping didn't change the window proc then see if
|
|
* we need a callproc handle.
|
|
*/
|
|
if (dwProc == (KERNEL_ULONG_PTR)pwnd->lpfnWndProc) {
|
|
CheckAnsiUnicodeMismatch:
|
|
/*
|
|
* Need to return a CallProc handle if there is an Ansi/Unicode mismatch
|
|
*/
|
|
if (bAnsi != (TestWF(pwnd, WFANSIPROC) ? TRUE : FALSE)) {
|
|
dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
|
|
}
|
|
}
|
|
|
|
if (dwCPDType) {
|
|
ULONG_PTR cpd;
|
|
|
|
cpd = GetCPD(pwnd, dwCPDType | CPD_WND, KERNEL_ULONG_PTR_TO_ULONG_PTR(dwProc));
|
|
|
|
if (cpd) {
|
|
dwProc = cpd;
|
|
} else {
|
|
RIPMSG0(RIP_WARNING, "GetWindowLong unable to alloc CPD returning handle\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* return proc (or CPD handle)
|
|
*/
|
|
return KERNEL_ULONG_PTR_TO_ULONG_PTR(dwProc);
|
|
|
|
case GWLP_HWNDPARENT:
|
|
|
|
/*
|
|
* If the window is the desktop window, return
|
|
* NULL to keep it compatible with Win31 and
|
|
* to prevent any access to the desktop owner
|
|
* window.
|
|
*/
|
|
if (GETFNID(pwnd) == FNID_DESKTOP) {
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Special case for pre-1.1 versions of Windows
|
|
* Set/GetWindowWord(GWL_HWNDPARENT) needs to be mapped
|
|
* to the hwndOwner for top level windows.
|
|
*
|
|
* Note that we find the desktop window through the
|
|
* pti because the PWNDDESKTOP macro only works in
|
|
* the server.
|
|
*/
|
|
|
|
/*
|
|
* Remove this test when we later add a test for WFDESTROYED
|
|
* in Client handle validation.
|
|
*/
|
|
if (pwnd->spwndParent == NULL) {
|
|
return 0;
|
|
}
|
|
pwndParent = REBASEALWAYS(pwnd, spwndParent);
|
|
if (GETFNID(pwndParent) == FNID_DESKTOP) {
|
|
pwnd = REBASEPWND(pwnd, spwndOwner);
|
|
return (ULONG_PTR)HW(pwnd);
|
|
}
|
|
|
|
return (ULONG_PTR)HW(pwndParent);
|
|
|
|
/*
|
|
* WOW uses a pointer straight into the window structure.
|
|
*/
|
|
case GWLP_WOWWORDS:
|
|
return (ULONG_PTR) &pwnd->state;
|
|
|
|
}
|
|
|
|
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef GENERIC_INPUT
|
|
|
|
FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, GetRawInputBuffer, PRAWINPUT, pData, PUINT, pcbSize, UINT, cbSizeHeader)
|
|
UINT GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
|
|
{
|
|
CLIENTTHREADINFO *pcti;
|
|
|
|
pcti = GETCLIENTTHREADINFO();
|
|
|
|
// Validate parameters
|
|
if (pcbSize == NULL || cbSizeHeader != sizeof(RAWINPUTHEADER)) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
|
|
return -1;
|
|
}
|
|
|
|
// Don't even go into the kernel if there's no reason to
|
|
if (pcti == NULL || (pcti->fsWakeBits & QS_RAWINPUT) == 0) {
|
|
*pcbSize = 0;
|
|
return 0;
|
|
}
|
|
|
|
return NtUserGetRawInputBuffer(pData, pcbSize, cbSizeHeader);
|
|
}
|
|
#endif // GENERIC_INPUT
|
|
|