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.
3463 lines
98 KiB
3463 lines
98 KiB
/**************************************************************************\
|
|
* Module Name: server.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Server support routines for the CSR stuff. This basically performs the
|
|
* startup/initialization for USER.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "prefetch.h"
|
|
|
|
extern WORD gDispatchTableValues;
|
|
|
|
BOOL gbUserInitialized;
|
|
|
|
/*
|
|
* Initialization Routines (external).
|
|
*/
|
|
NTSTATUS InitQEntryLookaside(VOID);
|
|
NTSTATUS InitSMSLookaside(VOID);
|
|
|
|
NTSTATUS InitCreateSharedSection(VOID);
|
|
NTSTATUS InitCreateObjectDirectory(VOID);
|
|
BOOL InitCreateUserSubsystem(VOID);
|
|
VOID InitFunctionTables(VOID);
|
|
VOID InitMessageTables(VOID);
|
|
VOID InitWindowMsgTable(PBYTE*, PUINT, CONST WORD*);
|
|
|
|
VOID VerifySyncOnlyMessages(VOID);
|
|
BOOL InitOLEFormats(VOID);
|
|
NTSTATUS Win32UserInitialize(VOID);
|
|
|
|
#pragma alloc_text(INIT, InitCreateSharedSection)
|
|
#pragma alloc_text(INIT, InitCreateUserCrit)
|
|
#pragma alloc_text(INIT, InitCreateObjectDirectory)
|
|
#pragma alloc_text(INIT, InitCreateUserSubsystem)
|
|
#pragma alloc_text(INIT, InitFunctionTables)
|
|
#pragma alloc_text(INIT, InitMessageTables)
|
|
#pragma alloc_text(INIT, InitWindowMsgTable)
|
|
|
|
#pragma alloc_text(INIT, VerifySyncOnlyMessages)
|
|
#pragma alloc_text(INIT, InitOLEFormats)
|
|
#pragma alloc_text(INIT, Win32UserInitialize)
|
|
|
|
/*
|
|
* Constants pertaining to the user-initialization.
|
|
*/
|
|
#define USRINIT_SHAREDSECT_SIZE 32
|
|
#define USRINIT_ATOMBUCKET_SIZE 37
|
|
|
|
#define USRINIT_WINDOWSECT_SIZE 512
|
|
#define USRINIT_NOIOSECT_SIZE 128
|
|
|
|
#define USRINIT_SHAREDSECT_BUFF_SIZE 640
|
|
#define USRINIT_SHAREDSECT_READ_SIZE (USRINIT_SHAREDSECT_BUFF_SIZE-33)
|
|
|
|
|
|
/***************************************************************************\
|
|
* Globals stored in the INIT section. These should only be accessed at
|
|
* load time!
|
|
\***************************************************************************/
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma data_seg("INIT$Data")
|
|
#endif
|
|
|
|
CONST WCHAR szCHECKPOINT_PROP_NAME[] = L"SysCP";
|
|
CONST WCHAR szDDETRACK_PROP_NAME[] = L"SysDT";
|
|
CONST WCHAR szQOS_PROP_NAME[] = L"SysQOS";
|
|
CONST WCHAR szDDEIMP_PROP_NAME[] = L"SysDDEI";
|
|
CONST WCHAR szWNDOBJ_PROP_NAME[] = L"SysWNDO";
|
|
CONST WCHAR szIMELEVEL_PROP_NAME[] = L"SysIMEL";
|
|
CONST WCHAR szLAYER_PROP_NAME[] = L"SysLayer";
|
|
CONST WCHAR szUSER32[] = L"USER32";
|
|
CONST WCHAR szCONTEXTHELPIDPROP[] = L"SysCH";
|
|
CONST WCHAR szICONSM_PROP_NAME[] = L"SysICS";
|
|
CONST WCHAR szICON_PROP_NAME[] = ICON_PROP_NAME;
|
|
CONST WCHAR szSHELLHOOK[] = L"SHELLHOOK";
|
|
CONST WCHAR szACTIVATESHELLWINDOW[] = L"ACTIVATESHELLWINDOW";
|
|
CONST WCHAR szOTHERWINDOWCREATED[] = L"OTHERWINDOWCREATED";
|
|
CONST WCHAR szOTHERWINDOWDESTROYED[] = L"OTHERWINDOWDESTROYED";
|
|
CONST WCHAR szOLEMAINTHREADWNDCLASS[] = L"OleMainThreadWndClass";
|
|
CONST WCHAR szFLASHWSTATE[] = L"FlashWState";
|
|
|
|
#ifdef HUNGAPP_GHOSTING
|
|
CONST WCHAR szGHOST[] = L"Ghost";
|
|
#endif
|
|
|
|
CONST WCHAR szSHADOW[] = L"SysShadow";
|
|
|
|
/***************************************************************************\
|
|
* Message Tables
|
|
*
|
|
* DefDlgProc
|
|
* MenuWndProc
|
|
* ScrollBarWndProc
|
|
* StaticWndProc
|
|
* ButtonWndProc
|
|
* ListboxWndProc
|
|
* ComboWndProc
|
|
* EditWndProc
|
|
* DefWindowMsgs
|
|
* DefWindowSpecMsgs
|
|
*
|
|
* These are used in InitMessageTables() to initialize gSharedInfo.awmControl[]
|
|
* using the INITMSGTABLE() macro.
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created comment block.
|
|
\***************************************************************************/
|
|
|
|
CONST WORD gawDefDlgProc[] = {
|
|
WM_COMPAREITEM,
|
|
WM_VKEYTOITEM,
|
|
WM_CHARTOITEM,
|
|
WM_INITDIALOG,
|
|
WM_QUERYDRAGICON,
|
|
WM_CTLCOLOR,
|
|
WM_CTLCOLORMSGBOX,
|
|
WM_CTLCOLOREDIT,
|
|
WM_CTLCOLORLISTBOX,
|
|
WM_CTLCOLORBTN,
|
|
WM_CTLCOLORDLG,
|
|
WM_CTLCOLORSCROLLBAR,
|
|
WM_CTLCOLORSTATIC,
|
|
WM_ERASEBKGND,
|
|
WM_SHOWWINDOW,
|
|
WM_SYSCOMMAND,
|
|
WM_SYSKEYDOWN,
|
|
WM_ACTIVATE,
|
|
WM_SETFOCUS,
|
|
WM_CLOSE,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
DM_REPOSITION,
|
|
DM_SETDEFID,
|
|
DM_GETDEFID,
|
|
WM_NEXTDLGCTL,
|
|
WM_ENTERMENULOOP,
|
|
WM_LBUTTONDOWN,
|
|
WM_NCLBUTTONDOWN,
|
|
WM_GETFONT,
|
|
WM_NOTIFYFORMAT,
|
|
WM_INPUTLANGCHANGEREQUEST,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawMenuWndProc[] = {
|
|
WM_NCCREATE,
|
|
WM_FINALDESTROY,
|
|
WM_PAINT,
|
|
WM_NCCALCSIZE,
|
|
WM_CHAR,
|
|
WM_SYSCHAR,
|
|
WM_KEYDOWN,
|
|
WM_SYSKEYDOWN,
|
|
WM_TIMER,
|
|
MN_SETHMENU,
|
|
MN_SIZEWINDOW,
|
|
MN_OPENHIERARCHY,
|
|
MN_CLOSEHIERARCHY,
|
|
MN_SELECTITEM,
|
|
MN_SELECTFIRSTVALIDITEM,
|
|
MN_CANCELMENUS,
|
|
MN_FINDMENUWINDOWFROMPOINT,
|
|
MN_SHOWPOPUPWINDOW,
|
|
MN_BUTTONDOWN,
|
|
MN_MOUSEMOVE,
|
|
MN_BUTTONUP,
|
|
MN_SETTIMERTOOPENHIERARCHY,
|
|
WM_ACTIVATE,
|
|
MN_GETHMENU,
|
|
MN_DBLCLK,
|
|
MN_ACTIVATEPOPUP,
|
|
MN_ENDMENU,
|
|
MN_DODRAGDROP,
|
|
WM_ACTIVATEAPP,
|
|
WM_MOUSELEAVE,
|
|
WM_SIZE,
|
|
WM_MOVE,
|
|
WM_NCHITTEST,
|
|
WM_NCPAINT,
|
|
WM_PRINT,
|
|
WM_PRINTCLIENT,
|
|
WM_ERASEBKGND,
|
|
WM_WINDOWPOSCHANGING,
|
|
WM_WINDOWPOSCHANGED,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawDesktopWndProc[] = {
|
|
WM_PAINT,
|
|
WM_ERASEBKGND,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawScrollBarWndProc[] = {
|
|
WM_CREATE,
|
|
WM_SETFOCUS,
|
|
WM_KILLFOCUS,
|
|
WM_ERASEBKGND,
|
|
WM_PAINT,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_LBUTTONDOWN,
|
|
WM_KEYUP,
|
|
WM_KEYDOWN,
|
|
WM_ENABLE,
|
|
SBM_ENABLE_ARROWS,
|
|
SBM_SETPOS,
|
|
SBM_SETRANGEREDRAW,
|
|
SBM_SETRANGE,
|
|
SBM_SETSCROLLINFO,
|
|
SBM_GETSCROLLINFO,
|
|
SBM_GETSCROLLBARINFO,
|
|
WM_PRINTCLIENT,
|
|
WM_MOUSEMOVE,
|
|
WM_MOUSELEAVE,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawStaticWndProc[] = {
|
|
STM_GETICON,
|
|
STM_GETIMAGE,
|
|
STM_SETICON,
|
|
STM_SETIMAGE,
|
|
WM_ERASEBKGND,
|
|
WM_PAINT,
|
|
WM_PRINTCLIENT,
|
|
WM_CREATE,
|
|
WM_DESTROY,
|
|
WM_NCCREATE,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
WM_NCHITTEST,
|
|
WM_LBUTTONDOWN,
|
|
WM_NCLBUTTONDOWN,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_NCLBUTTONDBLCLK,
|
|
WM_SETTEXT,
|
|
WM_ENABLE,
|
|
WM_GETDLGCODE,
|
|
WM_SETFONT,
|
|
WM_GETFONT,
|
|
WM_GETTEXT,
|
|
WM_TIMER,
|
|
WM_INPUTLANGCHANGEREQUEST,
|
|
WM_UPDATEUISTATE,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawButtonWndProc[] = {
|
|
WM_NCHITTEST,
|
|
WM_ERASEBKGND,
|
|
WM_PRINTCLIENT,
|
|
WM_PAINT,
|
|
WM_SETFOCUS,
|
|
WM_GETDLGCODE,
|
|
WM_CAPTURECHANGED,
|
|
WM_KILLFOCUS,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_LBUTTONUP,
|
|
WM_MOUSEMOVE,
|
|
WM_LBUTTONDOWN,
|
|
WM_CHAR,
|
|
BM_CLICK,
|
|
WM_KEYDOWN,
|
|
WM_KEYUP,
|
|
WM_SYSKEYUP,
|
|
BM_GETSTATE,
|
|
BM_SETSTATE,
|
|
BM_GETCHECK,
|
|
BM_SETCHECK,
|
|
BM_SETSTYLE,
|
|
WM_SETTEXT,
|
|
WM_ENABLE,
|
|
WM_SETFONT,
|
|
WM_GETFONT,
|
|
BM_GETIMAGE,
|
|
BM_SETIMAGE,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
WM_NCCREATE,
|
|
WM_INPUTLANGCHANGEREQUEST,
|
|
WM_UPDATEUISTATE,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawListboxWndProc[] = {
|
|
LB_GETTOPINDEX,
|
|
LB_SETTOPINDEX,
|
|
WM_SIZE,
|
|
WM_ERASEBKGND,
|
|
LB_RESETCONTENT,
|
|
WM_TIMER,
|
|
WM_MOUSEMOVE,
|
|
WM_MBUTTONDOWN,
|
|
WM_LBUTTONDOWN,
|
|
WM_LBUTTONUP,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_CAPTURECHANGED,
|
|
LBCB_STARTTRACK,
|
|
LBCB_ENDTRACK,
|
|
WM_PRINTCLIENT,
|
|
WM_PAINT,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
WM_SETFOCUS,
|
|
WM_KILLFOCUS,
|
|
WM_VSCROLL,
|
|
WM_HSCROLL,
|
|
WM_GETDLGCODE,
|
|
WM_CREATE,
|
|
WM_SETREDRAW,
|
|
WM_ENABLE,
|
|
WM_SETFONT,
|
|
WM_GETFONT,
|
|
WM_DRAGSELECT,
|
|
WM_DRAGLOOP,
|
|
WM_DRAGMOVE,
|
|
WM_DROPFILES,
|
|
WM_QUERYDROPOBJECT,
|
|
WM_DROPOBJECT,
|
|
LB_GETITEMRECT,
|
|
LB_GETITEMDATA,
|
|
LB_SETITEMDATA,
|
|
LB_ADDSTRINGUPPER,
|
|
LB_ADDSTRINGLOWER,
|
|
LB_ADDSTRING,
|
|
LB_INSERTSTRINGUPPER,
|
|
LB_INSERTSTRINGLOWER,
|
|
LB_INSERTSTRING,
|
|
LB_INITSTORAGE,
|
|
LB_DELETESTRING,
|
|
LB_DIR,
|
|
LB_ADDFILE,
|
|
LB_SETSEL,
|
|
LB_SETCURSEL,
|
|
LB_GETSEL,
|
|
LB_GETCURSEL,
|
|
LB_SELITEMRANGE,
|
|
LB_SELITEMRANGEEX,
|
|
LB_GETTEXTLEN,
|
|
LB_GETTEXT,
|
|
LB_GETCOUNT,
|
|
LB_SETCOUNT,
|
|
LB_SELECTSTRING,
|
|
LB_FINDSTRING,
|
|
LB_GETLOCALE,
|
|
LB_SETLOCALE,
|
|
WM_KEYDOWN,
|
|
WM_CHAR,
|
|
LB_GETSELITEMS,
|
|
LB_GETSELCOUNT,
|
|
LB_SETTABSTOPS,
|
|
LB_GETHORIZONTALEXTENT,
|
|
LB_SETHORIZONTALEXTENT,
|
|
LB_SETCOLUMNWIDTH,
|
|
LB_SETANCHORINDEX,
|
|
LB_GETANCHORINDEX,
|
|
LB_SETCARETINDEX,
|
|
LB_GETCARETINDEX,
|
|
LB_SETITEMHEIGHT,
|
|
LB_GETITEMHEIGHT,
|
|
LB_FINDSTRINGEXACT,
|
|
LB_ITEMFROMPOINT,
|
|
LB_SETLOCALE,
|
|
LB_GETLOCALE,
|
|
LBCB_CARETON,
|
|
LBCB_CARETOFF,
|
|
LB_GETLISTBOXINFO,
|
|
WM_NCCREATE,
|
|
WM_WINDOWPOSCHANGED,
|
|
WM_MOUSEWHEEL,
|
|
WM_STYLECHANGED,
|
|
WM_STYLECHANGING,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawComboWndProc[] = {
|
|
CBEC_KILLCOMBOFOCUS,
|
|
WM_COMMAND,
|
|
WM_CTLCOLORMSGBOX,
|
|
WM_CTLCOLOREDIT,
|
|
WM_CTLCOLORLISTBOX,
|
|
WM_CTLCOLORBTN,
|
|
WM_CTLCOLORDLG,
|
|
WM_CTLCOLORSCROLLBAR,
|
|
WM_CTLCOLORSTATIC,
|
|
WM_CTLCOLOR,
|
|
WM_GETTEXT,
|
|
WM_GETTEXTLENGTH,
|
|
WM_CLEAR,
|
|
WM_CUT,
|
|
WM_PASTE,
|
|
WM_COPY,
|
|
WM_SETTEXT,
|
|
WM_CREATE,
|
|
WM_ERASEBKGND,
|
|
WM_GETFONT,
|
|
WM_PRINT,
|
|
WM_PRINTCLIENT,
|
|
WM_PAINT,
|
|
WM_GETDLGCODE,
|
|
WM_SETFONT,
|
|
WM_SYSKEYDOWN,
|
|
WM_KEYDOWN,
|
|
WM_CHAR,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_LBUTTONDOWN,
|
|
WM_CAPTURECHANGED,
|
|
WM_LBUTTONUP,
|
|
WM_MOUSEMOVE,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
WM_SETFOCUS,
|
|
WM_KILLFOCUS,
|
|
WM_SETREDRAW,
|
|
WM_ENABLE,
|
|
WM_SIZE,
|
|
CB_GETDROPPEDSTATE,
|
|
CB_GETDROPPEDCONTROLRECT,
|
|
CB_SETDROPPEDWIDTH,
|
|
CB_GETDROPPEDWIDTH,
|
|
CB_DIR,
|
|
CB_SETEXTENDEDUI,
|
|
CB_GETEXTENDEDUI,
|
|
CB_GETEDITSEL,
|
|
CB_LIMITTEXT,
|
|
CB_SETEDITSEL,
|
|
CB_ADDSTRING,
|
|
CB_DELETESTRING,
|
|
CB_INITSTORAGE,
|
|
CB_SETTOPINDEX,
|
|
CB_GETTOPINDEX,
|
|
CB_GETCOUNT,
|
|
CB_GETCURSEL,
|
|
CB_GETLBTEXT,
|
|
CB_GETLBTEXTLEN,
|
|
CB_INSERTSTRING,
|
|
CB_RESETCONTENT,
|
|
CB_GETHORIZONTALEXTENT,
|
|
CB_SETHORIZONTALEXTENT,
|
|
CB_FINDSTRING,
|
|
CB_FINDSTRINGEXACT,
|
|
CB_SELECTSTRING,
|
|
CB_SETCURSEL,
|
|
CB_GETITEMDATA,
|
|
CB_SETITEMDATA,
|
|
CB_SETITEMHEIGHT,
|
|
CB_GETITEMHEIGHT,
|
|
CB_SHOWDROPDOWN,
|
|
CB_SETLOCALE,
|
|
CB_GETLOCALE,
|
|
CB_GETCOMBOBOXINFO,
|
|
WM_MEASUREITEM,
|
|
WM_DELETEITEM,
|
|
WM_DRAWITEM,
|
|
WM_COMPAREITEM,
|
|
WM_NCCREATE,
|
|
WM_HELP,
|
|
WM_MOUSEWHEEL,
|
|
WM_MOUSELEAVE,
|
|
WM_STYLECHANGED,
|
|
WM_STYLECHANGING,
|
|
WM_UPDATEUISTATE,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawEditWndProc[] = {
|
|
EM_CANUNDO,
|
|
EM_CHARFROMPOS,
|
|
EM_EMPTYUNDOBUFFER,
|
|
EM_FMTLINES,
|
|
EM_GETFIRSTVISIBLELINE,
|
|
EM_GETFIRSTVISIBLELINE,
|
|
EM_GETHANDLE,
|
|
EM_GETLIMITTEXT,
|
|
EM_GETLINE,
|
|
EM_GETLINECOUNT,
|
|
EM_GETMARGINS,
|
|
EM_GETMODIFY,
|
|
EM_GETPASSWORDCHAR,
|
|
EM_GETRECT,
|
|
EM_GETSEL,
|
|
EM_GETWORDBREAKPROC,
|
|
EM_SETIMESTATUS,
|
|
EM_GETIMESTATUS,
|
|
EM_LINEFROMCHAR,
|
|
EM_LINEINDEX,
|
|
EM_LINELENGTH,
|
|
EM_LINESCROLL,
|
|
EM_POSFROMCHAR,
|
|
EM_REPLACESEL,
|
|
EM_SCROLL,
|
|
EM_SCROLLCARET,
|
|
EM_SETHANDLE,
|
|
EM_SETLIMITTEXT,
|
|
EM_SETMARGINS,
|
|
EM_SETMODIFY,
|
|
EM_SETPASSWORDCHAR,
|
|
EM_SETREADONLY,
|
|
EM_SETRECT,
|
|
EM_SETRECTNP,
|
|
EM_SETSEL,
|
|
EM_SETTABSTOPS,
|
|
EM_SETWORDBREAKPROC,
|
|
EM_UNDO,
|
|
WM_CAPTURECHANGED,
|
|
WM_CHAR,
|
|
WM_CLEAR,
|
|
WM_CONTEXTMENU,
|
|
WM_COPY,
|
|
WM_CREATE,
|
|
WM_CUT,
|
|
WM_ENABLE,
|
|
WM_ERASEBKGND,
|
|
WM_GETDLGCODE,
|
|
WM_GETFONT,
|
|
WM_GETTEXT,
|
|
WM_GETTEXTLENGTH,
|
|
WM_HSCROLL,
|
|
WM_IME_STARTCOMPOSITION,
|
|
WM_IME_ENDCOMPOSITION,
|
|
WM_IME_COMPOSITION,
|
|
WM_IME_SETCONTEXT,
|
|
WM_IME_NOTIFY,
|
|
WM_IME_COMPOSITIONFULL,
|
|
WM_IME_SELECT,
|
|
WM_IME_CHAR,
|
|
WM_IME_REQUEST,
|
|
WM_INPUTLANGCHANGE,
|
|
WM_KEYUP,
|
|
WM_KEYDOWN,
|
|
WM_KILLFOCUS,
|
|
WM_MBUTTONDOWN,
|
|
WM_LBUTTONDBLCLK,
|
|
WM_LBUTTONDOWN,
|
|
WM_LBUTTONUP,
|
|
WM_MOUSEMOVE,
|
|
WM_NCCREATE,
|
|
WM_NCDESTROY,
|
|
WM_RBUTTONDOWN,
|
|
WM_RBUTTONUP,
|
|
WM_FINALDESTROY,
|
|
WM_PAINT,
|
|
WM_PASTE,
|
|
WM_PRINTCLIENT,
|
|
WM_SETFOCUS,
|
|
WM_SETFONT,
|
|
WM_SETREDRAW,
|
|
WM_SETTEXT,
|
|
WM_SIZE,
|
|
WM_STYLECHANGED,
|
|
WM_STYLECHANGING,
|
|
WM_SYSCHAR,
|
|
WM_SYSKEYDOWN,
|
|
WM_SYSTIMER,
|
|
WM_UNDO,
|
|
WM_VSCROLL,
|
|
WM_MOUSEWHEEL,
|
|
0
|
|
};
|
|
|
|
CONST WORD gawImeWndProc[] = {
|
|
WM_ERASEBKGND,
|
|
WM_PAINT,
|
|
WM_DESTROY,
|
|
WM_NCDESTROY,
|
|
WM_FINALDESTROY,
|
|
WM_CREATE,
|
|
WM_IME_SYSTEM,
|
|
WM_IME_SELECT,
|
|
WM_IME_CONTROL,
|
|
WM_IME_SETCONTEXT,
|
|
WM_IME_NOTIFY,
|
|
WM_IME_COMPOSITION,
|
|
WM_IME_STARTCOMPOSITION,
|
|
WM_IME_ENDCOMPOSITION,
|
|
WM_IME_REQUEST,
|
|
WM_COPYDATA,
|
|
0
|
|
};
|
|
|
|
/*
|
|
* This array is for all the messages that need to be passed straight
|
|
* across to the server for handling.
|
|
*/
|
|
CONST WORD gawDefWindowMsgs[] = {
|
|
WM_GETHOTKEY,
|
|
WM_SETHOTKEY,
|
|
WM_SETREDRAW,
|
|
WM_SETTEXT,
|
|
WM_PAINT,
|
|
WM_CLOSE,
|
|
WM_ERASEBKGND,
|
|
WM_CANCELMODE,
|
|
WM_SETCURSOR,
|
|
WM_PAINTICON,
|
|
WM_ICONERASEBKGND,
|
|
WM_DRAWITEM,
|
|
WM_KEYF1,
|
|
WM_ISACTIVEICON,
|
|
WM_NCCREATE,
|
|
WM_SETICON,
|
|
WM_NCCALCSIZE,
|
|
WM_NCPAINT,
|
|
WM_NCACTIVATE,
|
|
WM_NCMOUSEMOVE,
|
|
WM_NCRBUTTONUP,
|
|
WM_NCRBUTTONDOWN,
|
|
#ifndef LAME_BUTTON
|
|
WM_NCLBUTTONDOWN,
|
|
#endif
|
|
WM_NCLBUTTONUP,
|
|
WM_NCLBUTTONDBLCLK,
|
|
WM_KEYUP,
|
|
WM_SYSKEYUP,
|
|
#ifndef LAME_BUTTON
|
|
WM_SYSCHAR,
|
|
WM_SYSCOMMAND,
|
|
#endif
|
|
WM_QUERYDROPOBJECT,
|
|
WM_CLIENTSHUTDOWN,
|
|
WM_SYNCPAINT,
|
|
WM_PRINT,
|
|
WM_GETICON,
|
|
WM_CONTEXTMENU,
|
|
WM_SYSMENU,
|
|
WM_INPUTLANGCHANGEREQUEST,
|
|
WM_INPUTLANGCHANGE,
|
|
WM_UPDATEUISTATE,
|
|
WM_NCUAHDRAWCAPTION,
|
|
WM_NCUAHDRAWFRAME,
|
|
WM_UAHINIT,
|
|
0
|
|
};
|
|
|
|
/*
|
|
* This array is for all messages that can be handled with some special
|
|
* code by the client. DefWindowProcWorker returns 0 for all messages
|
|
* that aren't in this array or the one above.
|
|
*/
|
|
CONST WORD gawDefWindowSpecMsgs[] = {
|
|
WM_ACTIVATE,
|
|
WM_GETTEXT,
|
|
WM_GETTEXTLENGTH,
|
|
WM_RBUTTONUP,
|
|
WM_QUERYENDSESSION,
|
|
WM_QUERYOPEN,
|
|
WM_SHOWWINDOW,
|
|
WM_MOUSEACTIVATE,
|
|
WM_HELP,
|
|
WM_VKEYTOITEM,
|
|
WM_CHARTOITEM,
|
|
WM_KEYDOWN,
|
|
#ifdef LAME_BUTTON
|
|
WM_SYSCOMMAND,
|
|
WM_SYSCHAR,
|
|
#endif
|
|
WM_SYSKEYDOWN,
|
|
WM_UNICHAR,
|
|
WM_DROPOBJECT,
|
|
WM_WINDOWPOSCHANGING,
|
|
WM_WINDOWPOSCHANGED,
|
|
WM_KLUDGEMINRECT,
|
|
WM_CTLCOLOR,
|
|
WM_CTLCOLORMSGBOX,
|
|
WM_CTLCOLOREDIT,
|
|
WM_CTLCOLORLISTBOX,
|
|
WM_CTLCOLORBTN,
|
|
WM_CTLCOLORDLG,
|
|
WM_CTLCOLORSCROLLBAR,
|
|
WM_NCHITTEST,
|
|
#ifdef LAME_BUTTON
|
|
WM_NCLBUTTONDOWN,
|
|
#endif
|
|
WM_NCXBUTTONUP,
|
|
WM_CTLCOLORSTATIC,
|
|
WM_NOTIFYFORMAT,
|
|
WM_DEVICECHANGE,
|
|
WM_POWERBROADCAST,
|
|
WM_MOUSEWHEEL,
|
|
WM_XBUTTONUP,
|
|
WM_IME_KEYDOWN,
|
|
WM_IME_KEYUP,
|
|
WM_IME_CHAR,
|
|
WM_IME_COMPOSITION,
|
|
WM_IME_STARTCOMPOSITION,
|
|
WM_IME_ENDCOMPOSITION,
|
|
WM_IME_COMPOSITIONFULL,
|
|
WM_IME_SETCONTEXT,
|
|
WM_IME_CONTROL,
|
|
WM_IME_NOTIFY,
|
|
WM_IME_SELECT,
|
|
WM_IME_SYSTEM,
|
|
WM_LPKDRAWSWITCHWND,
|
|
WM_QUERYDRAGICON,
|
|
WM_CHANGEUISTATE,
|
|
WM_QUERYUISTATE,
|
|
WM_APPCOMMAND,
|
|
0
|
|
};
|
|
|
|
static CONST LPCWSTR lpszOLEFormats[] = {
|
|
L"ObjectLink",
|
|
L"OwnerLink",
|
|
L"Native",
|
|
L"Binary",
|
|
L"FileName",
|
|
L"FileNameW",
|
|
L"NetworkName",
|
|
L"DataObject",
|
|
L"Embedded Object",
|
|
L"Embed Source",
|
|
L"Custom Link Source",
|
|
L"Link Source",
|
|
L"Object Descriptor",
|
|
L"Link Source Descriptor",
|
|
L"OleDraw",
|
|
L"PBrush",
|
|
L"MSDraw",
|
|
L"Ole Private Data",
|
|
L"Screen Picture",
|
|
L"OleClipboardPersistOnFlush",
|
|
L"MoreOlePrivateData"
|
|
};
|
|
|
|
static CONST LPCWSTR lpszControls[] = {
|
|
L"Button",
|
|
L"Edit",
|
|
L"Static",
|
|
L"ListBox",
|
|
L"ScrollBar",
|
|
L"ComboBox",
|
|
L"MDIClient",
|
|
L"ComboLBox",
|
|
L"DDEMLEvent",
|
|
L"DDEMLMom",
|
|
L"DMGClass",
|
|
L"DDEMLAnsiClient",
|
|
L"DDEMLUnicodeClient",
|
|
L"DDEMLAnsiServer",
|
|
L"DDEMLUnicodeServer",
|
|
L"IME",
|
|
};
|
|
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
/***************************************************************************\
|
|
* DispatchServerMessage
|
|
*
|
|
*
|
|
* 19-Aug-1992 MikeKe Created
|
|
\***************************************************************************/
|
|
|
|
#define WRAPPFN(pfn, type) \
|
|
LRESULT xxxWrap ## pfn( \
|
|
PWND pwnd, \
|
|
UINT message, \
|
|
WPARAM wParam, \
|
|
LPARAM lParam, \
|
|
ULONG_PTR xParam) \
|
|
{ \
|
|
UNREFERENCED_PARAMETER(xParam); \
|
|
\
|
|
return xxx ## pfn((type)pwnd, message, wParam, lParam); \
|
|
}
|
|
|
|
WRAPPFN(SBWndProc, PSBWND)
|
|
WRAPPFN(MenuWindowProc, PWND)
|
|
WRAPPFN(DesktopWndProc, PWND);
|
|
WRAPPFN(RealDefWindowProc, PWND)
|
|
WRAPPFN(SwitchWndProc, PWND)
|
|
|
|
LRESULT xxxWrapSendMessageCallback(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
SNDMSGCALLBACK smcb;
|
|
TL tlpwnd;
|
|
LRESULT lRet = 0;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
UserAssert (xParam != 0L);
|
|
|
|
/*
|
|
* Prevent apps from setting hi 16 bits so we can use them internally.
|
|
*/
|
|
if (message & MSGFLAG_MASK) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid message");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Probe all read arguments
|
|
*/
|
|
try {
|
|
ProbeForWrite((PVOID)xParam, sizeof(smcb), sizeof(ULONG));
|
|
smcb = *(PSNDMSGCALLBACK)xParam;
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return 0;
|
|
}
|
|
|
|
if (pwnd != PWND_BROADCAST)
|
|
ThreadLockAlways(pwnd, &tlpwnd);
|
|
|
|
lRet = (LRESULT)xxxSendMessageCallback(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam,
|
|
smcb.lpResultCallBack,
|
|
smcb.dwData,
|
|
TRUE);
|
|
if (pwnd != PWND_BROADCAST)
|
|
ThreadUnlock(&tlpwnd);
|
|
|
|
return lRet;
|
|
}
|
|
|
|
LRESULT xxxWrapSendNotifyMessage(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
TL tlpwnd;
|
|
LRESULT lRet = 0;
|
|
|
|
UNREFERENCED_PARAMETER(xParam);
|
|
|
|
if (message & MSGFLAG_MASK) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid message");
|
|
return 0;
|
|
}
|
|
|
|
if (pwnd != PWND_BROADCAST) {
|
|
ThreadLockAlways(pwnd, &tlpwnd);
|
|
}
|
|
|
|
lRet = (LRESULT)xxxSendNotifyMessage(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam);
|
|
if (pwnd != PWND_BROADCAST) {
|
|
ThreadUnlock(&tlpwnd);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
LRESULT xxxWrapSendMessage(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(xParam);
|
|
|
|
return xxxSendMessageTimeout(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam,
|
|
SMTO_NORMAL,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
LRESULT xxxWrapSendMessageBSM(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
BROADCASTSYSTEMMSGPARAMS bsmParams;
|
|
LRESULT lRet;
|
|
|
|
try {
|
|
ProbeForWriteBroadcastSystemMsgParams((LPBROADCASTSYSTEMMSGPARAMS)xParam);
|
|
RtlCopyMemory(&bsmParams, (LPBROADCASTSYSTEMMSGPARAMS)xParam, sizeof(BROADCASTSYSTEMMSGPARAMS));
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* If this broadcast is going to all desktops, make sure the thread has
|
|
* sufficient privileges. Do the check here, so we don't effect kernel
|
|
* generated broadcasts (i.e power messages).
|
|
*/
|
|
if (bsmParams.dwRecipients & (BSM_ALLDESKTOPS)) {
|
|
if (!IsPrivileged(&psTcb)) {
|
|
bsmParams.dwRecipients &= ~(BSM_ALLDESKTOPS);
|
|
try {
|
|
RtlCopyMemory((LPBROADCASTSYSTEMMSGPARAMS)xParam, &bsmParams, sizeof(BROADCASTSYSTEMMSGPARAMS));
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
/* empty */
|
|
}
|
|
}
|
|
}
|
|
|
|
lRet = xxxSendMessageBSM(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam,
|
|
&bsmParams);
|
|
/*
|
|
* If our query was denied, return who denied the query.
|
|
*/
|
|
if (lRet == 0 && (bsmParams.dwFlags & BSF_QUERY)) {
|
|
try {
|
|
RtlCopyMemory((LPBROADCASTSYSTEMMSGPARAMS)xParam, &bsmParams, sizeof(BROADCASTSYSTEMMSGPARAMS));
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxUnusedFunctionId
|
|
*
|
|
* This function is catches attempts to access invalid entries in the server
|
|
* side function dispatch table.
|
|
*
|
|
\***************************************************************************/
|
|
LRESULT xxxUnusedFunctionId(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(pwnd);
|
|
UNREFERENCED_PARAMETER(message);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(xParam);
|
|
|
|
UserAssert(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxWrapCallWindowProc
|
|
*
|
|
* Warning should only be called with valid CallProc Handles or the
|
|
* EditWndProc special handlers.
|
|
*
|
|
*
|
|
* 21-Apr-1993 JohnC Created
|
|
\***************************************************************************/
|
|
|
|
LRESULT xxxWrapCallWindowProc(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
ULONG_PTR xParam)
|
|
{
|
|
PCALLPROCDATA pCPD;
|
|
LRESULT lRet = 0;
|
|
|
|
if (pCPD = HMValidateHandleNoRip((PVOID)xParam, TYPE_CALLPROC)) {
|
|
|
|
lRet = ScSendMessage(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam,
|
|
pCPD->pfnClientPrevious,
|
|
gpsi->apfnClientW.pfnDispatchMessage,
|
|
(pCPD->wType & CPD_UNICODE_TO_ANSI) ?
|
|
SCMS_FLAGS_ANSI : 0);
|
|
|
|
} else {
|
|
|
|
/*
|
|
* If it is not a real call proc handle it must be a special
|
|
* handler for editwndproc or regular EditWndProc
|
|
*/
|
|
lRet = ScSendMessage(pwnd,
|
|
message,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
gpsi->apfnClientA.pfnDispatchMessage,
|
|
(xParam == (ULONG_PTR)gpsi->apfnClientA.pfnEditWndProc) ?
|
|
SCMS_FLAGS_ANSI : 0);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
#if DBG
|
|
VOID VerifySyncOnlyMessages(VOID)
|
|
{
|
|
int i;
|
|
|
|
TRACE_INIT(("UserInit: Verify Sync Only Messages\n"));
|
|
|
|
/*
|
|
* There are a couple of thunks that just pass parameters. There are other
|
|
* thunks besides SfnDWORD that do a straight pass through because they
|
|
* do other processing beside the wparam and lparam
|
|
*/
|
|
|
|
/*
|
|
* Allow posting of LB_DIR and CB_DIR because DlgDirList allows a DDL_POSTMSGS
|
|
* flag that makes the API post the messages. This should be OK as long as we
|
|
* don't handle these messages in the kernel. NT 3.51 allowed posting these.
|
|
*/
|
|
for (i=0; i<WM_USER; i++) {
|
|
if ( i != LB_DIR
|
|
&& i != CB_DIR
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnDWORD)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnNCDESTROY)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnINWPARAMCHAR)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnINWPARAMDBCSCHAR)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnSENTDDEMSG)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnPOWERBROADCAST)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnLOGONNOTIFY)
|
|
&& (gapfnScSendMessage[MessageTable[i].iFunction] != SfnINDESTROYCLIPBRD)) {
|
|
if (!(TESTSYNCONLYMESSAGE(i,0x8000)))
|
|
RIPMSG1(RIP_ERROR, "InitSyncOnly: is this message sync-only 0x%lX", i);
|
|
} else {
|
|
if (TESTSYNCONLYMESSAGE(i,0))
|
|
RIPMSG1(RIP_VERBOSE, "InitSyncOnly: is this message not sync-only 0x%lX", i);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
/***************************************************************************\
|
|
* InitWindowMsgTables
|
|
*
|
|
* This function generates a bit-array lookup table from a list of messages.
|
|
* The lookup table is used to determine whether the message needs to be
|
|
* passed over to the server for handling or whether it can be handled
|
|
* directly on the client.
|
|
*
|
|
* LATER: Some memory (a couple hundred bytes per process) could be saved
|
|
* by putting this in the shared read-only heap.
|
|
*
|
|
*
|
|
* 27-Mar-1992 DarrinM Created.
|
|
* 06-Dec-1993 MikeKe Added support for all of our window procs.
|
|
\***************************************************************************/
|
|
VOID InitWindowMsgTable(
|
|
PBYTE *ppbyte,
|
|
PUINT pmax,
|
|
CONST WORD *pw)
|
|
{
|
|
UINT i;
|
|
WORD msg;
|
|
UINT cbTable;
|
|
|
|
*pmax = 0;
|
|
for (i = 0; (msg = pw[i]) != 0; i++) {
|
|
if (msg > *pmax)
|
|
*pmax = msg;
|
|
}
|
|
|
|
cbTable = *pmax / 8 + 1;
|
|
*ppbyte = SharedAlloc(cbTable);
|
|
if (*ppbyte == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; (msg = pw[i]) != 0; i++) {
|
|
(*ppbyte)[msg / 8] |= (BYTE)(1 << (msg & 7));
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* InitFunctionTables
|
|
*
|
|
* Initialize the procedures and function tables.
|
|
*
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created comment block.
|
|
\***************************************************************************/
|
|
VOID InitFunctionTables(
|
|
VOID)
|
|
{
|
|
UINT i;
|
|
|
|
TRACE_INIT(("UserInit: Initialize Function Tables\n"));
|
|
|
|
UserAssert(sizeof(CLIENTINFO) <= sizeof(NtCurrentTeb()->Win32ClientInfo));
|
|
|
|
/*
|
|
* This table is used to convert from server procs to client procs.
|
|
*/
|
|
STOCID(FNID_SCROLLBAR) = (WNDPROC_PWND)xxxSBWndProc;
|
|
STOCID(FNID_ICONTITLE) = xxxDefWindowProc;
|
|
STOCID(FNID_MENU) = xxxMenuWindowProc;
|
|
STOCID(FNID_DESKTOP) = xxxDesktopWndProc;
|
|
STOCID(FNID_DEFWINDOWPROC) = xxxDefWindowProc;
|
|
STOCID(FNID_MESSAGEWND) = xxxDefWindowProc;
|
|
|
|
/*
|
|
* This table is used to determine the number minimum number of reserved
|
|
* windows words required for the server proc.
|
|
*/
|
|
CBFNID(FNID_SCROLLBAR) = sizeof(SBWND);
|
|
CBFNID(FNID_ICONTITLE) = sizeof(WND);
|
|
CBFNID(FNID_MENU) = sizeof(MENUWND);
|
|
|
|
/*
|
|
* Initialize this data structure (api function table).
|
|
*/
|
|
for (i = 0; i < FNID_ARRAY_SIZE; i++) {
|
|
FNID((i + FNID_START)) = xxxUnusedFunctionId;
|
|
}
|
|
FNID(FNID_SCROLLBAR) = xxxWrapSBWndProc;
|
|
FNID(FNID_ICONTITLE) = xxxWrapRealDefWindowProc;
|
|
FNID(FNID_MENU) = xxxWrapMenuWindowProc;
|
|
FNID(FNID_DESKTOP) = xxxWrapDesktopWndProc;
|
|
FNID(FNID_DEFWINDOWPROC) = xxxWrapRealDefWindowProc;
|
|
FNID(FNID_MESSAGEWND) = xxxWrapRealDefWindowProc;
|
|
FNID(FNID_SENDMESSAGE) = xxxWrapSendMessage;
|
|
FNID(FNID_HKINLPCWPEXSTRUCT) = fnHkINLPCWPEXSTRUCT;
|
|
FNID(FNID_HKINLPCWPRETEXSTRUCT) = fnHkINLPCWPRETEXSTRUCT;
|
|
FNID(FNID_SENDMESSAGEFF) = xxxSendMessageFF;
|
|
FNID(FNID_SENDMESSAGEEX) = xxxSendMessageEx;
|
|
FNID(FNID_CALLWINDOWPROC) = xxxWrapCallWindowProc;
|
|
FNID(FNID_SENDMESSAGEBSM) = xxxWrapSendMessageBSM;
|
|
FNID(FNID_SWITCH) = xxxWrapSwitchWndProc;
|
|
FNID(FNID_SENDNOTIFYMESSAGE) = xxxWrapSendNotifyMessage;
|
|
FNID(FNID_SENDMESSAGECALLBACK) = xxxWrapSendMessageCallback;
|
|
|
|
#if DBG
|
|
{
|
|
PULONG_PTR pdw;
|
|
|
|
/*
|
|
* Make sure that everyone got initialized.
|
|
*/
|
|
for (pdw = (PULONG_PTR)&STOCID(FNID_START);
|
|
(ULONG_PTR)pdw<(ULONG_PTR)(&STOCID(FNID_WNDPROCEND)); pdw++) {
|
|
UserAssert(*pdw);
|
|
}
|
|
|
|
for (pdw=(PULONG_PTR)&FNID(FNID_START);
|
|
(ULONG_PTR)pdw<(ULONG_PTR)(&FNID(FNID_WNDPROCEND)); pdw++) {
|
|
UserAssert(*pdw);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* InitMessageTables
|
|
*
|
|
* Initialize the message tables.
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
VOID InitMessageTables(
|
|
VOID)
|
|
{
|
|
TRACE_INIT(("UserInit: Initialize Message Tables\n"));
|
|
|
|
#define INITMSGTABLE(member, procname) \
|
|
InitWindowMsgTable(&(gSharedInfo.member.abMsgs), \
|
|
&(gSharedInfo.member.maxMsgs), \
|
|
gaw ## procname);
|
|
|
|
INITMSGTABLE(DefWindowMsgs, DefWindowMsgs);
|
|
INITMSGTABLE(DefWindowSpecMsgs, DefWindowSpecMsgs);
|
|
|
|
INITMSGTABLE(awmControl[FNID_DIALOG - FNID_START], DefDlgProc);
|
|
INITMSGTABLE(awmControl[FNID_SCROLLBAR - FNID_START], ScrollBarWndProc);
|
|
INITMSGTABLE(awmControl[FNID_MENU - FNID_START], MenuWndProc);
|
|
INITMSGTABLE(awmControl[FNID_DESKTOP - FNID_START], DesktopWndProc);
|
|
INITMSGTABLE(awmControl[FNID_STATIC - FNID_START], StaticWndProc);
|
|
INITMSGTABLE(awmControl[FNID_BUTTON - FNID_START], ButtonWndProc);
|
|
INITMSGTABLE(awmControl[FNID_LISTBOX - FNID_START], ListboxWndProc);
|
|
INITMSGTABLE(awmControl[FNID_COMBOBOX - FNID_START], ComboWndProc);
|
|
INITMSGTABLE(awmControl[FNID_COMBOLISTBOX - FNID_START], ListboxWndProc);
|
|
INITMSGTABLE(awmControl[FNID_EDIT - FNID_START], EditWndProc);
|
|
INITMSGTABLE(awmControl[FNID_IME - FNID_START], ImeWndProc);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* InitOLEFormats
|
|
*
|
|
* OLE performance hack. OLE was previously having to call the server 15
|
|
* times for clipboard formats and another 15 LPC calls for the global atoms.
|
|
* Now we preregister them. We also assert they are in order so OLE only has
|
|
* to query the first to know them all. We call AddAtom directly instead of
|
|
* RegisterClipboardFormat.
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
BOOL InitOLEFormats(
|
|
VOID)
|
|
{
|
|
UINT idx;
|
|
ATOM a1;
|
|
ATOM a2;
|
|
BOOL fSuccess = TRUE;
|
|
|
|
TRACE_INIT(("UserInit: Initialize OLE Formats\n"));
|
|
|
|
a1 = UserAddAtom(lpszOLEFormats[0], TRUE);
|
|
|
|
for (idx = 1; idx < ARRAY_SIZE(lpszOLEFormats); idx++) {
|
|
a2 = UserAddAtom(lpszOLEFormats[idx], TRUE);
|
|
fSuccess &= !!a2;
|
|
|
|
UserAssert(((a1 + 1) == a2) && (a1 = a2));
|
|
}
|
|
|
|
if (!fSuccess) {
|
|
RIPMSG0(RIP_ERROR, "InitOLEFormats: at least one atom not registered");
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
#if DBG
|
|
/***************************************************************************\
|
|
* InitGlobalRIPFlags (CHK only).
|
|
*
|
|
* This initializes the global RIP flags from the registry.
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
VOID InitGlobalRIPFlags(
|
|
VOID)
|
|
{
|
|
|
|
UINT idx;
|
|
UINT nCount;
|
|
DWORD dwFlag;
|
|
|
|
static CONST struct {
|
|
LPWSTR lpszKey;
|
|
DWORD dwDef;
|
|
DWORD dwFlag;
|
|
} aRIPFlags[] = {
|
|
{L"fPromptOnError" , 1, RIPF_PROMPTONERROR},
|
|
{L"fPromptOnWarning", 0, RIPF_PROMPTONWARNING},
|
|
{L"fPromptOnVerbose", 0, RIPF_PROMPTONVERBOSE},
|
|
{L"fPrintError" , 1, RIPF_PRINTONERROR},
|
|
{L"fPrintWarning" , 1, RIPF_PRINTONWARNING},
|
|
{L"fPrintVerbose" , 0, RIPF_PRINTONVERBOSE},
|
|
{L"fPrintFileLine" , 0, RIPF_PRINTFILELINE},
|
|
};
|
|
|
|
TRACE_INIT(("UserInit: Initialize Global RIP Flags\n"));
|
|
|
|
nCount = ARRAY_SIZE(aRIPFlags);
|
|
|
|
/*
|
|
* Turn off the rip-on-warning bit. This is necessary to prevent the
|
|
* FastGetProfileDwordW() routine from breaking into the debugger if an
|
|
* entry can't be found. Since we provide default values, there's no sense
|
|
* to break.
|
|
*/
|
|
CLEAR_FLAG(gpsi->dwRIPFlags, RIPF_PROMPTONWARNING);
|
|
CLEAR_FLAG(gpsi->dwRIPFlags, RIPF_PRINTONWARNING);
|
|
|
|
for (idx = 0; idx < nCount; idx++) {
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_WINDOWSM,
|
|
aRIPFlags[idx].lpszKey,
|
|
aRIPFlags[idx].dwDef,
|
|
&dwFlag,
|
|
0);
|
|
|
|
SET_OR_CLEAR_FLAG(gpsi->dwRIPFlags, aRIPFlags[idx].dwFlag, dwFlag);
|
|
}
|
|
}
|
|
#else
|
|
#define InitGlobalRIPFlags()
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
* _GetTextMetricsW
|
|
* _TextOutW
|
|
*
|
|
* Server shared function thunks.
|
|
*
|
|
* History:
|
|
* 10-Nov-1993 MikeKe Created
|
|
\***************************************************************************/
|
|
BOOL _GetTextMetricsW(
|
|
HDC hdc,
|
|
LPTEXTMETRICW ptm)
|
|
{
|
|
TMW_INTERNAL tmi;
|
|
BOOL fret;
|
|
|
|
fret = GreGetTextMetricsW(hdc, &tmi);
|
|
|
|
*ptm = tmi.tmw;
|
|
|
|
return fret;
|
|
}
|
|
|
|
BOOL _TextOutW(
|
|
HDC hdc,
|
|
int x,
|
|
int y,
|
|
LPCWSTR lp,
|
|
UINT cc)
|
|
{
|
|
return GreExtTextOutW(hdc, x, y, 0, NULL, (LPWSTR)lp, cc, NULL);
|
|
}
|
|
|
|
|
|
#define ROUND_UP_TO_PAGES(SIZE) \
|
|
(((ULONG)(SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
|
|
|
/***************************************************************************\
|
|
* InitCreateSharedSection
|
|
*
|
|
* This creates the shared section.
|
|
*
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created comment block.
|
|
\***************************************************************************/
|
|
NTSTATUS InitCreateSharedSection(
|
|
VOID)
|
|
{
|
|
ULONG ulHeapSize;
|
|
ULONG ulHandleTableSize;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER SectionSize;
|
|
SIZE_T ViewSize;
|
|
PVOID pHeapBase;
|
|
|
|
TRACE_INIT(("UserInit: Create Shared Memory Section\n"));
|
|
|
|
UserAssert(ghSectionShared == NULL);
|
|
|
|
ulHeapSize = ROUND_UP_TO_PAGES(USRINIT_SHAREDSECT_SIZE * 1024);
|
|
ulHandleTableSize = ROUND_UP_TO_PAGES(0x10000 * sizeof(HANDLEENTRY));
|
|
|
|
TRACE_INIT(("UserInit: Share: TableSize = %X; HeapSize = %X\n",
|
|
ulHandleTableSize, ulHeapSize));
|
|
|
|
SectionSize.LowPart = ulHeapSize + ulHandleTableSize;
|
|
SectionSize.HighPart = 0;
|
|
|
|
Status = Win32CreateSection(&ghSectionShared,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
&SectionSize,
|
|
PAGE_EXECUTE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL,
|
|
NULL,
|
|
TAG_SECTION_SHARED);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"MmCreateSection failed in InitCreateSharedSection with Status %x",
|
|
Status);
|
|
return Status;
|
|
}
|
|
|
|
ViewSize = 0;
|
|
gpvSharedBase = NULL;
|
|
|
|
Status = Win32MapViewInSessionSpace(ghSectionShared, &gpvSharedBase, &ViewSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"Win32MapViewInSessionSpace failed with Status %x",
|
|
Status);
|
|
Win32DestroySection(ghSectionShared);
|
|
ghSectionShared = NULL;
|
|
return Status;
|
|
}
|
|
|
|
pHeapBase = ((PBYTE)gpvSharedBase + ulHandleTableSize);
|
|
|
|
TRACE_INIT(("UserInit: Share: BaseAddr = %#p; Heap = %#p, ViewSize = %X\n",
|
|
gpvSharedBase, pHeapBase, ViewSize));
|
|
|
|
/*
|
|
* Create shared heap.
|
|
*/
|
|
if ((gpvSharedAlloc = UserCreateHeap(
|
|
ghSectionShared,
|
|
ulHandleTableSize,
|
|
pHeapBase,
|
|
ulHeapSize,
|
|
UserCommitSharedMemory)) == NULL) {
|
|
RIPERR0(ERROR_NOT_ENOUGH_MEMORY,
|
|
RIP_WARNING,
|
|
"Can't create shared memory heap.");
|
|
|
|
Win32UnmapViewInSessionSpace(gpvSharedBase);
|
|
|
|
Win32DestroySection(ghSectionShared);
|
|
gpvSharedAlloc = NULL;
|
|
gpvSharedBase = NULL;
|
|
ghSectionShared = NULL;
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
UserAssert(Win32HeapGetHandle(gpvSharedAlloc) == pHeapBase);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* InitCreateUserCrit
|
|
*
|
|
* Create and initialize the user critical sections needed throughout the
|
|
* system.
|
|
*
|
|
* 23-Jan-1996 ChrisWil Created.
|
|
\**************************************************************************/
|
|
BOOL InitCreateUserCrit(
|
|
VOID)
|
|
{
|
|
TRACE_INIT(("Win32UserInit: InitCreateUserCrit()\n"));
|
|
|
|
/*
|
|
* Initialize a critical section structure that will be used to protect
|
|
* all of the User Server's critical sections (except a few special
|
|
* cases like the RIT -- see below).
|
|
*/
|
|
gpresUser = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(ERESOURCE),
|
|
TAG_ERESOURCE);
|
|
if (!gpresUser) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
|
|
if (!NT_SUCCESS(ExInitializeResourceLite(gpresUser))) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
|
|
/*
|
|
* Initialize a critical section to be used in [Un]QueueMouseEvent
|
|
* to protect the queue of mouse input events that the desktop thread
|
|
* uses to pass input on to the RIT, after having moved the cursor
|
|
* without obtaining gpresUser itself.
|
|
*/
|
|
gpresMouseEventQueue = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(ERESOURCE),
|
|
TAG_ERESOURCE);
|
|
if (!gpresMouseEventQueue) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
if (!NT_SUCCESS(ExInitializeResourceLite(gpresMouseEventQueue))) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
|
|
/*
|
|
* Initialize a critical section to protect the list of DEVICEINFO structs
|
|
* kept under gpDeviceInfoList. This is used by the RIT when reading kbd
|
|
* input, the desktop thread when reading mouse input, and the PnP callback
|
|
* routines DeviceClassNotify() and DeviceNotify() when devices come and go.
|
|
*/
|
|
gpresDeviceInfoList = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(ERESOURCE),
|
|
TAG_ERESOURCE);
|
|
if (!gpresDeviceInfoList) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
if (!NT_SUCCESS(ExInitializeResourceLite(gpresDeviceInfoList))) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
|
|
/*
|
|
* Create the handle flag mutex. We'll need this once we start creating
|
|
* windowstations and desktops.
|
|
*/
|
|
gpHandleFlagsMutex = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(FAST_MUTEX),
|
|
TAG_SYSTEM);
|
|
if (gpHandleFlagsMutex == NULL) {
|
|
goto InitCreateUserCritExit;
|
|
}
|
|
ExInitializeFastMutex(gpHandleFlagsMutex);
|
|
|
|
TRACE_INIT(("Win32UserInit: gpHandleFlagsMutex = %#p\n", gpHandleFlagsMutex));
|
|
TRACE_INIT(("Win32UserInit: gpresDeviceInfoList = %#p\n", gpresDeviceInfoList));
|
|
TRACE_INIT(("Win32UserInit: gpresMouseEventQueue = %#p\n", gpresMouseEventQueue));
|
|
TRACE_INIT(("Win32UserInit: gpresUser = %#p\n", gpresUser));
|
|
|
|
TRACE_INIT(("Win32UserInit: exit InitCreateUserCrit()\n"));
|
|
return TRUE;
|
|
|
|
InitCreateUserCritExit:
|
|
RIPERR0(ERROR_NOT_ENOUGH_MEMORY,
|
|
RIP_WARNING,
|
|
"Win32UserInit: InitCreateUserCrit failed");
|
|
|
|
if (gpresUser) {
|
|
ExFreePool(gpresUser);
|
|
}
|
|
|
|
if (gpresMouseEventQueue) {
|
|
ExFreePool(gpresMouseEventQueue);
|
|
}
|
|
|
|
if (gpresDeviceInfoList) {
|
|
ExFreePool(gpresDeviceInfoList);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* InitCreateObjectDirectory
|
|
*
|
|
* Create and initialize the user critical sections needed throughout the
|
|
* system.
|
|
*
|
|
* 23-Jan-1996 ChrisWil Created.
|
|
\**************************************************************************/
|
|
NTSTATUS InitCreateObjectDirectory(VOID)
|
|
{
|
|
HANDLE hDir;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
ULONG attributes = OBJ_CASE_INSENSITIVE | OBJ_PERMANENT;
|
|
|
|
TRACE_INIT(("UserInit: Create User Object-Directory\n"));
|
|
|
|
RtlInitUnicodeString(&UnicodeString, szWindowStationDirectory);
|
|
|
|
if (gbRemoteSession) {
|
|
/*
|
|
* Remote sessions don't use this flag
|
|
*/
|
|
attributes &= ~OBJ_PERMANENT;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
attributes,
|
|
NULL,
|
|
gpsdInitWinSta);
|
|
|
|
Status = ZwCreateDirectoryObject(&hDir,
|
|
DIRECTORY_CREATE_OBJECT,
|
|
&ObjectAttributes);
|
|
|
|
UserFreePool(gpsdInitWinSta);
|
|
|
|
/*
|
|
* Do not close this handle for remote session because
|
|
* if we do close it then the directory will go away and
|
|
* we don't want that to happen. When CSRSS will go away
|
|
* this handle will be freed also.
|
|
*/
|
|
if (!gbRemoteSession)
|
|
ZwClose(hDir);
|
|
|
|
gpsdInitWinSta = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* InitCreateUserSubsystem
|
|
*
|
|
* Create and initialize the user subsystem stuff.
|
|
* system.
|
|
*
|
|
* 23-Jan-1996 ChrisWil Created.
|
|
\**************************************************************************/
|
|
BOOL
|
|
InitCreateUserSubsystem()
|
|
{
|
|
LPWSTR lpszSubSystem;
|
|
LPWSTR lpszT;
|
|
UNICODE_STRING strSize;
|
|
|
|
TRACE_INIT(("UserInit: Create User SubSystem\n"));
|
|
|
|
/*
|
|
* Initialize the subsystem section. This identifies the default
|
|
* user-heap size.
|
|
*/
|
|
lpszSubSystem = UserAllocPoolWithQuota(USRINIT_SHAREDSECT_BUFF_SIZE * sizeof(WCHAR),
|
|
TAG_SYSTEM);
|
|
|
|
if (lpszSubSystem == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (FastGetProfileStringW(NULL,
|
|
PMAP_SUBSYSTEMS,
|
|
L"Windows",
|
|
L"SharedSection=,3072",
|
|
lpszSubSystem,
|
|
USRINIT_SHAREDSECT_READ_SIZE,
|
|
0) == 0) {
|
|
RIPMSG0(RIP_WARNING,
|
|
"UserInit: Windows subsystem definition not found");
|
|
UserFreePool(lpszSubSystem);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Locate the SharedSection portion of the definition and extract
|
|
* the second value.
|
|
*/
|
|
gdwDesktopSectionSize = USER_WINDOWSECT_SIZE;
|
|
gdwNOIOSectionSize = USER_NOIOSECT_SIZE;
|
|
|
|
if (lpszT = wcsstr(lpszSubSystem, L"SharedSection")) {
|
|
|
|
*(lpszT + 32) = UNICODE_NULL;
|
|
|
|
if (lpszT = wcschr(lpszT, L',')) {
|
|
|
|
RtlInitUnicodeString(&strSize, ++lpszT);
|
|
RtlUnicodeStringToInteger(&strSize, 0, &gdwDesktopSectionSize);
|
|
|
|
/*
|
|
* Assert this logic doesn't need to change.
|
|
*/
|
|
UserAssert(gdwDesktopSectionSize >= USER_WINDOWSECT_SIZE);
|
|
|
|
gdwDesktopSectionSize = max(USER_WINDOWSECT_SIZE, gdwDesktopSectionSize);
|
|
gdwNOIOSectionSize = gdwDesktopSectionSize;
|
|
|
|
/*
|
|
* Now see if the optional non-interactive desktop
|
|
* heap size was specified.
|
|
*/
|
|
if (lpszT = wcschr(lpszT, L',')) {
|
|
|
|
RtlInitUnicodeString(&strSize, ++lpszT);
|
|
RtlUnicodeStringToInteger(&strSize, 0, &gdwNOIOSectionSize);
|
|
|
|
UserAssert(gdwNOIOSectionSize >= USER_NOIOSECT_SIZE);
|
|
gdwNOIOSectionSize = max(USER_NOIOSECT_SIZE, gdwNOIOSectionSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
UserFreePool(lpszSubSystem);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
extern UNICODE_STRING *gpastrSetupExe; // These are used in
|
|
extern int giSetupExe; // SetAppImeCompatFlags in
|
|
// queue.c
|
|
|
|
WCHAR* glpSetupPrograms;
|
|
|
|
/**************************************************************************\
|
|
* CreateSetupNameArray
|
|
*
|
|
* Create and initialize the arrary of setup app names. We inherited this
|
|
* hack From Chicago. See queue.c for more details.
|
|
\**************************************************************************/
|
|
BOOL CreateSetupNameArray(
|
|
VOID)
|
|
{
|
|
DWORD dwProgNames;
|
|
int iSetupProgramCount = 0;
|
|
WCHAR* lpTemp;
|
|
int ic, icnt, icMax;
|
|
|
|
dwProgNames = FastGetProfileValue(NULL,
|
|
PMAP_SETUPPROGRAMNAMES,
|
|
L"SetupProgramNames",
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0);
|
|
|
|
/*
|
|
* This key is a multi-string, so is best to read as a value.
|
|
* First, get the length and create the buffer to hold all of
|
|
* the strings.
|
|
*/
|
|
if (dwProgNames == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
glpSetupPrograms = UserAllocPoolWithQuota(dwProgNames,
|
|
TAG_SYSTEM);
|
|
|
|
if (glpSetupPrograms == NULL) {
|
|
RIPMSG0(RIP_WARNING, "CreateSetupNameArray: Memory allocation failure");
|
|
return FALSE;
|
|
}
|
|
|
|
FastGetProfileValue(NULL,
|
|
PMAP_SETUPPROGRAMNAMES,
|
|
L"SetupProgramNames",
|
|
NULL,
|
|
(PBYTE)glpSetupPrograms,
|
|
dwProgNames,
|
|
0);
|
|
|
|
lpTemp = glpSetupPrograms;
|
|
icMax = dwProgNames/2;
|
|
ic = 0; icnt=0;
|
|
/*
|
|
* Now count the strings.
|
|
*/
|
|
while (ic < icMax) {
|
|
if (*(lpTemp+ic) == 0) {
|
|
ic++;
|
|
continue;
|
|
}
|
|
ic += wcslen(lpTemp+ic)+1;
|
|
icnt++;
|
|
}
|
|
|
|
/*
|
|
* gpastrSetupExe is a pointer to an array of UNICODE_STRING structures.
|
|
* Each structure is the name of one setup program.
|
|
*/
|
|
giSetupExe = icnt;
|
|
gpastrSetupExe = UserAllocPoolWithQuota(giSetupExe * sizeof(UNICODE_STRING),
|
|
TAG_SYSTEM);
|
|
|
|
if (gpastrSetupExe == NULL) {
|
|
RIPMSG0(RIP_WARNING, "CreateSetupNameArray: Memory allocation failure");
|
|
giSetupExe = 0;
|
|
UserFreePool(glpSetupPrograms);
|
|
glpSetupPrograms = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
ic = 0; icnt=0;
|
|
while (ic < icMax) {
|
|
if (*(lpTemp+ic) == 0) {
|
|
ic++;
|
|
continue;
|
|
}
|
|
gpastrSetupExe[icnt].Buffer = lpTemp+ic;
|
|
gpastrSetupExe[icnt].Length = sizeof(WCHAR)*wcslen(lpTemp+ic);
|
|
gpastrSetupExe[icnt].MaximumLength = gpastrSetupExe[icnt].Length + sizeof(WCHAR);
|
|
ic += wcslen(lpTemp+ic)+1;
|
|
icnt++;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define CALC_DELTA(element) \
|
|
(PVOID)((PBYTE)pClientBase + \
|
|
((PBYTE)gSharedInfo.element - \
|
|
(PBYTE)gpvSharedBase))
|
|
|
|
/***************************************************************************\
|
|
* InitMapSharedSection
|
|
*
|
|
* This maps the shared section.
|
|
*
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created comment block.
|
|
\***************************************************************************/
|
|
|
|
NTSTATUS InitMapSharedSection(
|
|
PEPROCESS Process,
|
|
PUSERCONNECT pUserConnect)
|
|
{
|
|
int i;
|
|
PVOID pClientBase = NULL;
|
|
ULONG_PTR ulSharedDelta;
|
|
PW32PROCESS pw32p;
|
|
|
|
TRACE_INIT(("UserInit: Map Shared Memory Section\n"));
|
|
|
|
UserAssert(ghSectionShared != NULL);
|
|
|
|
ValidateProcessSessionId(Process);
|
|
|
|
/*
|
|
* Check to see if we haven't already mapped the section
|
|
* This might happen for multiple LoadLibrary()/FreeLibrary calls
|
|
* in one process. MCostea #56946
|
|
*/
|
|
pw32p = PsGetProcessWin32Process(Process);
|
|
if (pw32p == NULL ||
|
|
((PPROCESSINFO)pw32p)->pClientBase == NULL) {
|
|
|
|
SIZE_T ViewSize;
|
|
LARGE_INTEGER liOffset;
|
|
NTSTATUS Status;
|
|
|
|
ViewSize = 0;
|
|
liOffset.QuadPart = 0;
|
|
|
|
Status = MmMapViewOfSection(ghSectionShared,
|
|
Process,
|
|
&pClientBase,
|
|
0,
|
|
0,
|
|
&liOffset,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
SEC_NO_CHANGE,
|
|
PAGE_EXECUTE_READ);
|
|
if (NT_SUCCESS(Status)) {
|
|
TRACE_INIT(("UserInit: Map: Client SharedInfo Base = %#p\n", pClientBase));
|
|
|
|
UserAssert(gpvSharedBase > pClientBase);
|
|
pw32p = PsGetProcessWin32Process(Process);
|
|
if (pw32p != NULL) {
|
|
((PPROCESSINFO)pw32p)->pClientBase = pClientBase;
|
|
}
|
|
} else {
|
|
return Status;
|
|
}
|
|
|
|
} else {
|
|
pClientBase = ((PPROCESSINFO)PsGetProcessWin32Process(Process))->pClientBase;
|
|
}
|
|
ulSharedDelta = (PBYTE)gpvSharedBase - (PBYTE)pClientBase;
|
|
pUserConnect->siClient.ulSharedDelta = ulSharedDelta;
|
|
|
|
pUserConnect->siClient.psi = CALC_DELTA(psi);
|
|
pUserConnect->siClient.aheList = CALC_DELTA(aheList);
|
|
pUserConnect->siClient.pDispInfo = CALC_DELTA(pDispInfo);
|
|
|
|
|
|
pUserConnect->siClient.DefWindowMsgs.maxMsgs = gSharedInfo.DefWindowMsgs.maxMsgs;
|
|
pUserConnect->siClient.DefWindowMsgs.abMsgs = CALC_DELTA(DefWindowMsgs.abMsgs);
|
|
pUserConnect->siClient.DefWindowSpecMsgs.maxMsgs = gSharedInfo.DefWindowSpecMsgs.maxMsgs;
|
|
pUserConnect->siClient.DefWindowSpecMsgs.abMsgs = CALC_DELTA(DefWindowSpecMsgs.abMsgs);
|
|
|
|
for (i = 0; i < (FNID_END - FNID_START + 1); ++i) {
|
|
|
|
pUserConnect->siClient.awmControl[i].maxMsgs = gSharedInfo.awmControl[i].maxMsgs;
|
|
|
|
if (gSharedInfo.awmControl[i].abMsgs)
|
|
pUserConnect->siClient.awmControl[i].abMsgs = CALC_DELTA(awmControl[i].abMsgs);
|
|
else
|
|
pUserConnect->siClient.awmControl[i].abMsgs = NULL;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/**************************************************************************\
|
|
* InitLoadResources
|
|
*
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created.
|
|
\**************************************************************************/
|
|
|
|
VOID InitLoadResources()
|
|
{
|
|
PRECT prc;
|
|
|
|
DISPLAYRESOURCE dr = {
|
|
17, // Height of vertical thumb
|
|
17, // Width of horizontal thumb
|
|
2, // Icon horiz compression factor
|
|
2, // Icon vert compression factor
|
|
2, // Cursor horz compression factor
|
|
2, // Cursor vert compression factor
|
|
0, // Kanji window height
|
|
1, // cxBorder (thickness of vertical lines)
|
|
1 // cyBorder (thickness of horizontal lines)
|
|
};
|
|
|
|
|
|
TRACE_INIT(("UserInit: Load Display Resources\n"));
|
|
|
|
/*
|
|
* For high-DPI systems, don't compress the cursor as much.
|
|
* This really should be a more configurable method, such as a System
|
|
* Parameter Info setting or something. But for now, we'll hard-code
|
|
* 150dpi to be the threshhold at which we'll double the cursor size.
|
|
*/
|
|
if (gpsi->dmLogPixels >= 150) {
|
|
dr.xCompressCursor = 1;
|
|
dr.yCompressCursor = 1;
|
|
}
|
|
|
|
if (dr.xCompressIcon > 10) {
|
|
|
|
/*
|
|
* If so, the actual dimensions of icons and cursors are
|
|
* kept in OEMBIN.
|
|
*/
|
|
SYSMET(CXICON) = dr.xCompressIcon;
|
|
SYSMET(CYICON) = dr.yCompressIcon;
|
|
SYSMET(CXCURSOR) = dr.xCompressCursor;
|
|
SYSMET(CYCURSOR) = dr.yCompressCursor;
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Else, only the ratio of (64/icon dimensions) is kept there.
|
|
*/
|
|
SYSMET(CXICON) = (64 / dr.xCompressIcon);
|
|
SYSMET(CYICON) = (64 / dr.yCompressIcon);
|
|
SYSMET(CXCURSOR) = (64 / dr.xCompressCursor);
|
|
SYSMET(CYCURSOR) = (64 / dr.yCompressCursor);
|
|
}
|
|
|
|
SYSMET(CXSMICON) = SYSMET(CXICON) / 2;
|
|
SYSMET(CYSMICON) = SYSMET(CYICON) / 2;
|
|
|
|
SYSMET(CYKANJIWINDOW) = dr.yKanji;
|
|
|
|
/*
|
|
* Get border thicknesses.
|
|
*/
|
|
SYSMET(CXBORDER) = dr.cxBorder;
|
|
SYSMET(CYBORDER) = dr.cyBorder;
|
|
|
|
/*
|
|
* Edge is two borders.
|
|
*/
|
|
SYSMET(CXEDGE) = 2 * SYSMET(CXBORDER);
|
|
SYSMET(CYEDGE) = 2 * SYSMET(CYBORDER);
|
|
|
|
/*
|
|
* Fixed frame is outer edge + border.
|
|
*/
|
|
SYSMET(CXDLGFRAME) = SYSMET(CXEDGE) + SYSMET(CXBORDER);
|
|
SYSMET(CYDLGFRAME) = SYSMET(CYEDGE) + SYSMET(CYBORDER);
|
|
|
|
if (gbRemoteSession) {
|
|
return;
|
|
}
|
|
|
|
prc = &GetPrimaryMonitor()->rcMonitor;
|
|
SYSMET(CXFULLSCREEN) = prc->right;
|
|
SYSMET(CYFULLSCREEN) = prc->bottom - SYSMET(CYCAPTION);
|
|
|
|
/*
|
|
* Set the initial cursor position to the center of the primary screen.
|
|
*/
|
|
gpsi->ptCursor.x = prc->right / 2;
|
|
gpsi->ptCursor.y = prc->bottom / 2;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetCharDimensions
|
|
*
|
|
* This function loads the Textmetrics of the font currently selected into
|
|
* the hDC and returns the Average char width of the font; Pl Note that the
|
|
* AveCharWidth value returned by the Text metrics call is wrong for
|
|
* proportional fonts. So, we compute them On return, lpTextMetrics contains
|
|
* the text metrics of the currently selected font.
|
|
*
|
|
* History:
|
|
* 10-Nov-1993 mikeke Created
|
|
\***************************************************************************/
|
|
int GetCharDimensions(
|
|
HDC hdc,
|
|
TEXTMETRIC* lptm,
|
|
LPINT lpcy
|
|
)
|
|
{
|
|
TEXTMETRIC tm;
|
|
|
|
/*
|
|
* Didn't find it in cache, store the font metrics info.
|
|
*/
|
|
if (!_GetTextMetricsW(hdc, &tm)) {
|
|
RIPMSG1(RIP_WARNING, "GetCharDimensions: _GetTextMetricsW failed. hdc %#lx", hdc);
|
|
tm = gpsi->tmSysFont; // damage control
|
|
|
|
if (tm.tmAveCharWidth == 0) {
|
|
RIPMSG0(RIP_WARNING, "GetCharDimensions: _GetTextMetricsW first time failure");
|
|
tm.tmAveCharWidth = 8;
|
|
}
|
|
}
|
|
if (lptm != NULL)
|
|
*lptm = tm;
|
|
if (lpcy != NULL)
|
|
*lpcy = tm.tmHeight;
|
|
|
|
/*
|
|
* If variable_width font
|
|
*/
|
|
if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) {
|
|
SIZE size;
|
|
static CONST WCHAR wszAvgChars[] =
|
|
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
/*
|
|
* Change from tmAveCharWidth. We will calculate a true average
|
|
* as opposed to the one returned by tmAveCharWidth. This works
|
|
* better when dealing with proportional spaced fonts.
|
|
*/
|
|
if (GreGetTextExtentW(
|
|
hdc, (LPWSTR)wszAvgChars,
|
|
(sizeof(wszAvgChars) / sizeof(WCHAR)) - 1,
|
|
&size, GGTE_WIN3_EXTENT)) {
|
|
|
|
UserAssert((((size.cx / 26) + 1) / 2) > 0);
|
|
return ((size.cx / 26) + 1) / 2; // round up
|
|
} else {
|
|
RIPMSG1(RIP_WARNING, "GetCharDimensions: GreGetTextExtentW failed. hdc %#lx", hdc);
|
|
}
|
|
}
|
|
|
|
UserAssert(tm.tmAveCharWidth > 0);
|
|
|
|
return tm.tmAveCharWidth;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* InitVideo
|
|
*
|
|
* Create pmdev.
|
|
*
|
|
* 03-March-1998 CLupu Moved from UserInitialize code
|
|
\**************************************************************************/
|
|
PMDEV InitVideo(
|
|
BOOL bReenumerationNeeded)
|
|
{
|
|
PMDEV pmdev;
|
|
LONG ChangeStatus;
|
|
|
|
/*
|
|
* NOTE: Need to get a status return from this call.
|
|
* DrvInitConsole doesn't return failure, if or when it does we
|
|
* should check for it and return NULL. However there seem to be
|
|
* no known problems related to this.
|
|
*/
|
|
|
|
DrvInitConsole(bReenumerationNeeded);
|
|
|
|
/*
|
|
* BASEVIDEO may be on or off, whether we are in setup or not.
|
|
*/
|
|
|
|
ChangeStatus = DrvChangeDisplaySettings(NULL,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)GW_DESKTOP_ID,
|
|
KernelMode,
|
|
FALSE,
|
|
TRUE,
|
|
NULL,
|
|
&pmdev,
|
|
GRE_DEFAULT,
|
|
TRUE);
|
|
|
|
|
|
if (ChangeStatus != GRE_DISP_CHANGE_SUCCESSFUL) {
|
|
/*
|
|
* If we fail, try BASEVIDEO temporarily.
|
|
*/
|
|
DrvSetBaseVideo(TRUE);
|
|
|
|
ChangeStatus = DrvChangeDisplaySettings(NULL,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)GW_DESKTOP_ID,
|
|
KernelMode,
|
|
FALSE,
|
|
TRUE,
|
|
NULL,
|
|
&pmdev,
|
|
GRE_DEFAULT,
|
|
TRUE);
|
|
|
|
DrvSetBaseVideo(FALSE);
|
|
|
|
/*
|
|
* Give it one last try, not in basevideo, to handle TGA
|
|
* (non-vgacompatible) during GUI-mode setup (BASEVIDEO is on by
|
|
* default)
|
|
*/
|
|
|
|
if (ChangeStatus != GRE_DISP_CHANGE_SUCCESSFUL) {
|
|
ChangeStatus = DrvChangeDisplaySettings(NULL,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)GW_DESKTOP_ID,
|
|
KernelMode,
|
|
FALSE,
|
|
TRUE,
|
|
NULL,
|
|
&pmdev,
|
|
GRE_DEFAULT,
|
|
TRUE);
|
|
|
|
}
|
|
}
|
|
|
|
if (ChangeStatus != GRE_DISP_CHANGE_SUCCESSFUL) {
|
|
RIPMSG0(RIP_WARNING, "InitVideo: No working display driver found");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Remove the basevideo flag. We want it set only on the first modeset.
|
|
*/
|
|
DrvSetBaseVideo(FALSE);
|
|
|
|
gpDispInfo->hDev = pmdev->hdevParent;
|
|
gpDispInfo->pmdev = pmdev;
|
|
|
|
GreUpdateSharedDevCaps(gpDispInfo->hDev);
|
|
|
|
if (!InitUserScreen()) {
|
|
RIPMSG0(RIP_WARNING, "InitUserScreen failed");
|
|
return NULL;
|
|
}
|
|
|
|
HYDRA_HINT(HH_INITVIDEO);
|
|
|
|
return pmdev;
|
|
}
|
|
|
|
VOID DrvDriverFailure(
|
|
VOID)
|
|
{
|
|
KeBugCheckEx(VIDEO_DRIVER_INIT_FAILURE,
|
|
0,
|
|
0,
|
|
0,
|
|
USERCURRENTVERSION);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* BeginBootPhase
|
|
*
|
|
* Let's kernel know of boot progress on the console.
|
|
*
|
|
* 10-Apr-2001 Cenke Created.
|
|
\***************************************************************************/
|
|
NTSTATUS BeginBootPhase(
|
|
PF_BOOT_PHASE_ID Phase)
|
|
{
|
|
PREFETCHER_INFORMATION PrefetcherInformation;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* We should be called only on the console.
|
|
*/
|
|
|
|
UserAssert(gSessionId == 0);
|
|
|
|
/*
|
|
* Setup the structure that will be passed to system call.
|
|
*/
|
|
|
|
PrefetcherInformation.Magic = PF_SYSINFO_MAGIC_NUMBER;
|
|
PrefetcherInformation.Version = PF_CURRENT_VERSION;
|
|
PrefetcherInformation.PrefetcherInformationClass = PrefetcherBootPhase;
|
|
PrefetcherInformation.PrefetcherInformation = &Phase;
|
|
PrefetcherInformation.PrefetcherInformationLength = sizeof(Phase);
|
|
|
|
/*
|
|
* Call system and return status to caller.
|
|
*/
|
|
|
|
Status = ZwSetSystemInformation(SystemPrefetcherInformation,
|
|
&PrefetcherInformation,
|
|
sizeof(PrefetcherInformation));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ReserveUserSessionViews
|
|
*
|
|
* Reserve user needed session views beforhand to prevert GDI from eating
|
|
* uo the session view space when hardware acceleration is turned off.
|
|
*
|
|
* 27-Nov-2001 MSadek Created it
|
|
\**************************************************************************/
|
|
NTSTATUS
|
|
ReserveUserSessionViews(
|
|
PHANDLE phSection,
|
|
PPVOID ppMapBase)
|
|
{
|
|
LARGE_INTEGER SectionSize;
|
|
ULONG ulSectionSize;
|
|
SIZE_T ulViewSize;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* We need to reserve session view space for:
|
|
* - Winlogon desktop heap.
|
|
* - Disconnect desktop heap.
|
|
* - Winlogon desktop heap.
|
|
* - Services desktops heap (how many?, let's have a factor of safety here).
|
|
*/
|
|
|
|
ulSectionSize = GetDesktopHeapSize(DHS_LOGON) +
|
|
GetDesktopHeapSize(DHS_DISCONNECT) +
|
|
GetDesktopHeapSize(0) +
|
|
GetDesktopHeapSize(DHS_NOIO) * NOIO_DESKTOP_NUMBER;
|
|
|
|
SectionSize.QuadPart = ulSectionSize;
|
|
|
|
Status = Win32CreateSection(phSection,
|
|
SECTION_ALL_ACCESS,
|
|
(POBJECT_ATTRIBUTES)NULL,
|
|
&SectionSize,
|
|
PAGE_EXECUTE_READWRITE,
|
|
SEC_RESERVE,
|
|
(HANDLE)NULL,
|
|
NULL,
|
|
TAG_SECTION_DESKTOP);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
RIPNTERR0(Status,
|
|
RIP_WARNING,
|
|
"Can't create section for reserved session views.");
|
|
return Status;
|
|
}
|
|
|
|
ulViewSize = ulSectionSize;
|
|
*ppMapBase = NULL;
|
|
|
|
Status = Win32MapViewInSessionSpace(*phSection, ppMapBase, &ulViewSize);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPNTERR0(Status,
|
|
RIP_WARNING,
|
|
"Can't map section for for reserved session views into session space.");
|
|
Win32DestroySection(&phSection);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserInitialize
|
|
*
|
|
* Worker routine for user initialization.
|
|
*
|
|
* 25-Aug-1995 ChrisWil Created comment block/Multiple desktop support.
|
|
* 15-Dec-1995 BradG Modified to return MediaChangeEvent Handle.
|
|
\**************************************************************************/
|
|
NTSTATUS
|
|
UserInitialize(
|
|
VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD dwData;
|
|
HANDLE hSection;
|
|
PVOID pSectionBase;
|
|
|
|
#if DBG
|
|
/*
|
|
* Allow a trace of all the init stuff going on related to display
|
|
* drivers. Useful to debug boot time problems related to graphics.
|
|
*/
|
|
if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) {
|
|
TraceInitialization = 1;
|
|
}
|
|
#endif
|
|
|
|
TRACE_INIT(("Entering UserInitialize\n"));
|
|
|
|
EnterCrit();
|
|
|
|
HYDRA_HINT(HH_USERINITIALIZE);
|
|
|
|
if (ISTS() && gbRemoteSession) {
|
|
swprintf(szWindowStationDirectory, L"%ws\\%ld%ws",
|
|
SESSION_ROOT, gSessionId, WINSTA_DIR);
|
|
} else {
|
|
wcscpy(szWindowStationDirectory, WINSTA_DIR);
|
|
}
|
|
|
|
/*
|
|
* Create WindowStation object directory.
|
|
*/
|
|
Status = InitCreateObjectDirectory();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "InitCreateObjectDirectory failed with Status %x",
|
|
Status);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Create the event for PnP RequestDeviceChangeSyncronization
|
|
*/
|
|
gpEventPnPWainting = CreateKernelEvent(SynchronizationEvent, TRUE);
|
|
|
|
if (gpEventPnPWainting == NULL) {
|
|
RIPMSG0(RIP_WARNING, "Failed to create gpEventPnPWainting");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Read the registry configuration for the multimon snapsot flag
|
|
*/
|
|
|
|
if (FastGetProfileIntFromID(NULL,PMAP_TS, STR_SNAPSHOTMONITORS, 1, &dwData, 0)) {
|
|
if (dwData != 0) {
|
|
gbSnapShotWindowsAndMonitors = TRUE;
|
|
} else {
|
|
gbSnapShotWindowsAndMonitors = FALSE;
|
|
}
|
|
} else{
|
|
gbSnapShotWindowsAndMonitors = TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Create the event for the diconnect desktop creation
|
|
*/
|
|
gpEventDiconnectDesktop = CreateKernelEvent(SynchronizationEvent, FALSE);
|
|
|
|
if (gpEventDiconnectDesktop == NULL) {
|
|
RIPMSG0(RIP_WARNING, "Failed to create gpEventDiconnectDesktop");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* WinStations get init'ed on the first connect.
|
|
*/
|
|
if (!gbRemoteSession) {
|
|
BeginBootPhase(PfVideoInitPhase);
|
|
|
|
/* If hardware acceleration is turned off, GDI will map huge sections for the panning
|
|
* surfaces. We might end up exceeding the session view size quota before mapping the heap
|
|
* section for critical desktops.
|
|
* Let's pre-reserve approximately what we need now.
|
|
*/
|
|
Status = ReserveUserSessionViews(&hSection, &pSectionBase);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (InitVideo(TRUE) == NULL) {
|
|
DrvDriverFailure();
|
|
}
|
|
|
|
Status = Win32UnmapViewInSessionSpace(pSectionBase);
|
|
Win32DestroySection(hSection);
|
|
|
|
BeginBootPhase(PfPostVideoInitPhase);
|
|
|
|
/*
|
|
* Do this here so power callouts
|
|
* have the pmdev in gpDispInfo set
|
|
*/
|
|
gbVideoInitialized = TRUE;
|
|
}
|
|
|
|
gbUserInitialized = TRUE;
|
|
|
|
/*
|
|
* Now that the system is initialized, allocate a pti for this thread.
|
|
*/
|
|
Status = xxxCreateThreadInfo(PsGetCurrentThread());
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"xxxCreateThreadInfo failed during UserInitialize with Status 0x%x",
|
|
Status);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Initialize Global RIP flags (debug only).
|
|
*/
|
|
InitGlobalRIPFlags();
|
|
|
|
/*
|
|
* WinStations get init'ed on the first connect.
|
|
*/
|
|
if (!gbRemoteSession) {
|
|
UserVerify(LW_BrushInit());
|
|
}
|
|
|
|
InitLoadResources();
|
|
|
|
Exit:
|
|
LeaveCrit();
|
|
|
|
TRACE_INIT(("Leaving UserInitialize\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* IsDBCSEnabledSystem
|
|
*
|
|
* check if the system is configured as FE Enabled
|
|
*
|
|
* 07-Feb-1997 HiroYama Created
|
|
\**************************************************************************/
|
|
__inline BOOL IsDBCSEnabledSystem(
|
|
VOID)
|
|
{
|
|
return !!NLS_MB_CODE_PAGE_TAG;
|
|
}
|
|
|
|
|
|
BOOL IsIMMEnabledSystem(
|
|
VOID)
|
|
{
|
|
DWORD dwRet = 0;
|
|
|
|
/*
|
|
* If the entire system is DBCS enabled, IMM/IME should be activated
|
|
* anyway.
|
|
*/
|
|
if (IsDBCSEnabledSystem()) {
|
|
return TRUE;
|
|
}
|
|
|
|
FastGetProfileDwordW(NULL, PMAP_IMM, TEXT("LoadIMM"), 0, &dwRet, 0);
|
|
return dwRet;
|
|
}
|
|
|
|
#ifdef CUAS_ENABLE
|
|
|
|
BOOL IsCTFIMEEnabledSystem(
|
|
VOID)
|
|
{
|
|
DWORD dwRet = 0;
|
|
|
|
FastGetProfileDwordW(NULL, PMAP_IMM, TEXT("DontLoadCTFIME"), 0, &dwRet, 0);
|
|
if (dwRet)
|
|
return FALSE;
|
|
|
|
return IsIMMEnabledSystem();
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Get ACP and check if the system is configured as ME Enabled.
|
|
*/
|
|
BOOL IsMidEastEnabledSystem(
|
|
VOID)
|
|
{
|
|
extern __declspec(dllimport) USHORT NlsAnsiCodePage;
|
|
/*
|
|
* 1255 == Hebrew and 1256 == Arabic.
|
|
*/
|
|
if (NlsAnsiCodePage == 1255 || NlsAnsiCodePage == 1256) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetupClassAtoms
|
|
*
|
|
* 10/01/1998 clupu moved from Win32UserInitialize
|
|
\***************************************************************************/
|
|
BOOL SetupClassAtoms(
|
|
VOID)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
int ind;
|
|
|
|
/*
|
|
* Set up class atoms.
|
|
*
|
|
* HACK: Controls are registered on the client side so we can't fill in
|
|
* their atomSysClass entry the same way we do for the other classes.
|
|
*/
|
|
for (ind = ICLS_BUTTON; ind < ICLS_CTL_MAX; ind++) {
|
|
gpsi->atomSysClass[ind] = UserAddAtom(lpszControls[ind], TRUE);
|
|
fSuccess &= !!gpsi->atomSysClass[ind];
|
|
}
|
|
|
|
gpsi->atomSysClass[ICLS_DIALOG] = PTR_TO_ID(DIALOGCLASS);
|
|
gpsi->atomSysClass[ICLS_ICONTITLE] = PTR_TO_ID(ICONTITLECLASS);
|
|
gpsi->atomSysClass[ICLS_TOOLTIP] = PTR_TO_ID(TOOLTIPCLASS);
|
|
gpsi->atomSysClass[ICLS_DESKTOP] = PTR_TO_ID(DESKTOPCLASS);
|
|
gpsi->atomSysClass[ICLS_SWITCH] = PTR_TO_ID(SWITCHWNDCLASS);
|
|
gpsi->atomSysClass[ICLS_MENU] = PTR_TO_ID(MENUCLASS);
|
|
|
|
gpsi->atomContextHelpIdProp = UserAddAtom(szCONTEXTHELPIDPROP, TRUE);
|
|
fSuccess &= !!gpsi->atomContextHelpIdProp;
|
|
|
|
gpsi->atomIconSmProp = UserAddAtom(szICONSM_PROP_NAME, TRUE);
|
|
fSuccess &= !!gpsi->atomIconSmProp;
|
|
|
|
gpsi->atomIconProp = UserAddAtom(szICON_PROP_NAME, TRUE);
|
|
fSuccess &= !!gpsi->atomIconProp;
|
|
|
|
gpsi->uiShellMsg = UserAddAtom(szSHELLHOOK, TRUE);
|
|
fSuccess &= !!gpsi->uiShellMsg;
|
|
|
|
/*
|
|
* Initialize the integer atoms for our magic window properties
|
|
*/
|
|
atomCheckpointProp = UserAddAtom(szCHECKPOINT_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomCheckpointProp;
|
|
|
|
atomDDETrack = UserAddAtom(szDDETRACK_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomDDETrack;
|
|
|
|
atomQOS = UserAddAtom(szQOS_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomQOS;
|
|
|
|
atomDDEImp = UserAddAtom(szDDEIMP_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomDDEImp;
|
|
|
|
atomWndObj = UserAddAtom(szWNDOBJ_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomWndObj;
|
|
|
|
atomImeLevel = UserAddAtom(szIMELEVEL_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomImeLevel;
|
|
|
|
atomLayer = UserAddAtom(szLAYER_PROP_NAME, TRUE);
|
|
fSuccess &= !!atomLayer;
|
|
|
|
guiActivateShellWindow = UserAddAtom(szACTIVATESHELLWINDOW, TRUE);
|
|
fSuccess &= !!guiActivateShellWindow;
|
|
|
|
guiOtherWindowCreated = UserAddAtom(szOTHERWINDOWCREATED, TRUE);
|
|
fSuccess &= !!guiOtherWindowCreated;
|
|
|
|
guiOtherWindowDestroyed = UserAddAtom(szOTHERWINDOWDESTROYED, TRUE);
|
|
fSuccess &= !!guiOtherWindowDestroyed;
|
|
|
|
gatomMessage = UserAddAtom(szMESSAGE, TRUE);
|
|
fSuccess &= !!gatomMessage;
|
|
|
|
#ifdef HUNGAPP_GHOSTING
|
|
gatomGhost = UserAddAtom(szGHOST, TRUE);
|
|
fSuccess &= !!gatomGhost;
|
|
#endif
|
|
|
|
gatomShadow = UserAddAtom(szSHADOW, TRUE);
|
|
fSuccess &= !!gatomShadow;
|
|
|
|
gaOleMainThreadWndClass = UserAddAtom(szOLEMAINTHREADWNDCLASS, TRUE);
|
|
fSuccess &= !!gaOleMainThreadWndClass;
|
|
|
|
gaFlashWState = UserAddAtom(szFLASHWSTATE, TRUE);
|
|
fSuccess &= !!gaFlashWState;
|
|
|
|
gatomLastPinned = gaOleMainThreadWndClass;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* IsDesktopHeapLoggingOn
|
|
*
|
|
* Checks the registry to determine if we should write a message to the
|
|
* event log on desktop heap allocation failures.
|
|
*
|
|
* 05-19-2002 JasonSch Created.
|
|
\**************************************************************************/
|
|
BOOL IsDesktopHeapLoggingOn(
|
|
VOID)
|
|
{
|
|
DWORD dwDesktopHeapLogging;
|
|
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_WINDOWSM,
|
|
L"DesktopHeapLogging",
|
|
0,
|
|
&dwDesktopHeapLogging,
|
|
0);
|
|
|
|
return (dwDesktopHeapLogging != 0);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* Win32UserInitialize
|
|
*
|
|
* Worker routine for user initialization called from Win32k's DriverEntry.
|
|
\**************************************************************************/
|
|
NTSTATUS Win32UserInitialize(
|
|
VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
POBJECT_TYPE_INITIALIZER pTypeInfo;
|
|
LONG lTemp;
|
|
|
|
TRACE_INIT(("Entering Win32UserInitialize\n"));
|
|
|
|
/*
|
|
* Create the shared section.
|
|
*/
|
|
Status = InitCreateSharedSection();
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"InitCreateSharedSection failed with Status 0x%x",
|
|
Status);
|
|
return Status;
|
|
}
|
|
|
|
EnterCrit();
|
|
|
|
/*
|
|
* Initialize security stuff.
|
|
*/
|
|
if (!InitSecurity()) {
|
|
RIPMSG0(RIP_WARNING, "InitSecurity failed");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Fill in windowstation and desktop object types
|
|
*/
|
|
pTypeInfo = &(*ExWindowStationObjectType)->TypeInfo;
|
|
pTypeInfo->DefaultNonPagedPoolCharge = sizeof(WINDOWSTATION) + sizeof(KEVENT);
|
|
pTypeInfo->DefaultPagedPoolCharge = 0;
|
|
pTypeInfo->MaintainHandleCount = TRUE;
|
|
pTypeInfo->ValidAccessMask = WinStaMapping.GenericAll;
|
|
pTypeInfo->GenericMapping = WinStaMapping;
|
|
|
|
pTypeInfo = &(*ExDesktopObjectType)->TypeInfo;
|
|
pTypeInfo->DefaultNonPagedPoolCharge = sizeof(DESKTOP);
|
|
pTypeInfo->DefaultPagedPoolCharge = 0;
|
|
pTypeInfo->MaintainHandleCount = TRUE;
|
|
pTypeInfo->ValidAccessMask = DesktopMapping.GenericAll;
|
|
pTypeInfo->GenericMapping = DesktopMapping;
|
|
|
|
/*
|
|
* Get this process so we can use the profiles.
|
|
*/
|
|
gpepInit = PsGetCurrentProcess();
|
|
|
|
Status = InitQEntryLookaside();
|
|
Status |= InitSMSLookaside();
|
|
Status |= UserRtlCreateAtomTable(USRINIT_ATOMBUCKET_SIZE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"Initialization failure (Status = 0x%x)",
|
|
Status);
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
atomUSER32 = UserAddAtom(szUSER32, TRUE);
|
|
|
|
gatomFirstPinned = atomUSER32;
|
|
|
|
if (gatomFirstPinned == 0) {
|
|
RIPMSG0(RIP_WARNING, "Could not create atomUSER32");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Initialize the user subsystem information.
|
|
*/
|
|
if (!InitCreateUserSubsystem()) {
|
|
RIPMSG0(RIP_WARNING, "InitCreateUserSubsystem failed");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Don't bail out if CreateSetupNameArray fails.
|
|
*/
|
|
CreateSetupNameArray();
|
|
|
|
/*
|
|
* Allocated shared SERVERINFO structure.
|
|
*/
|
|
if ((gpsi = (PSERVERINFO)SharedAlloc(sizeof(SERVERINFO))) == NULL) {
|
|
RIPMSG0(RIP_WARNING, "Could not allocate SERVERINFO");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Set the default rip-flags to rip on just about everything. We'll
|
|
* truly set this in the InitGlobalRIPFlags() routine. These are needed
|
|
* so that we can do appropriate ripping during the rest of the init
|
|
* calls.
|
|
*/
|
|
#if DBG
|
|
SET_FLAG(gpsi->dwRIPFlags, RIPF_DEFAULT);
|
|
#endif
|
|
|
|
/*
|
|
* Make sure we will not get a division by zero if the initialization
|
|
* will not complete correctly. Set these to their normal values.
|
|
*/
|
|
gpsi->cxMsgFontChar = 6;
|
|
gpsi->cyMsgFontChar = 13;
|
|
gpsi->cxSysFontChar = 8;
|
|
gpsi->cySysFontChar = 16;
|
|
|
|
/*
|
|
* Initialize the last time we updated system-wide LastSystemRITEventTickCount
|
|
* on system shared page.
|
|
*/
|
|
|
|
gpsi->dwLastSystemRITEventTickCountUpdate = 0;
|
|
|
|
/*
|
|
* Initialize the DISPLAYINFO structure.
|
|
*/
|
|
gpDispInfo = SharedAlloc(sizeof(*gpDispInfo));
|
|
if (!gpDispInfo) {
|
|
RIPMSG0(RIP_WARNING, "Could not allocate gpDispInfo");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
InitDbgTags();
|
|
|
|
SET_OR_CLEAR_SRVIF(SRVIF_LOGDESKTOPHEAPFAILURE, IsDesktopHeapLoggingOn());
|
|
SET_OR_CLEAR_SRVIF(SRVIF_DBCS, IsDBCSEnabledSystem());
|
|
SET_OR_CLEAR_SRVIF(SRVIF_IME, IsIMMEnabledSystem());
|
|
#ifdef CUAS_ENABLE
|
|
SET_OR_CLEAR_SRVIF(SRVIF_CTFIME_ENABLED, IsCTFIMEEnabledSystem());
|
|
#endif // CUAS_ENABLE
|
|
|
|
SET_OR_CLEAR_SRVIF(SRVIF_MIDEAST, IsMidEastEnabledSystem());
|
|
|
|
#if DBG
|
|
SET_SRVIF(SRVIF_CHECKED);
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
RIPMSG3(RIP_WARNING, "*** win32k: DBCS:[%d] IME:[%d] MiddleEast:[%d]",
|
|
IS_DBCS_ENABLED(),
|
|
IS_IME_ENABLED(),
|
|
IS_MIDEAST_ENABLED());
|
|
#else
|
|
RIPMSG4(RIP_WARNING, "*** win32k: DBCS:[%d] IME:[%d] MiddleEast:[%d] CTFIME:[%d]",
|
|
IS_DBCS_ENABLED(),
|
|
IS_IME_ENABLED(),
|
|
IS_MIDEAST_ENABLED(),
|
|
IS_CICERO_ENABLED());
|
|
#endif
|
|
#endif
|
|
|
|
gpsi->dwDefaultHeapSize = gdwDesktopSectionSize * 1024;
|
|
|
|
/*
|
|
* Initialize procedures and message tables.
|
|
* Initialize the class structures for Get/SetClassWord/Long.
|
|
* Initialize message-box strings.
|
|
* Initialize OLE-Formats (performance-hack).
|
|
*/
|
|
InitFunctionTables();
|
|
InitMessageTables();
|
|
#if DBG
|
|
VerifySyncOnlyMessages();
|
|
#endif
|
|
if (!InitOLEFormats()) {
|
|
RIPMSG0(RIP_WARNING, "InitOLEFormats failed");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Set up class atoms
|
|
*/
|
|
if (!SetupClassAtoms()) {
|
|
RIPMSG0(RIP_WARNING, "SetupClassAtoms failed to register atoms");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Initialize the handle manager.
|
|
*/
|
|
if (!HMInitHandleTable(gpvSharedBase)) {
|
|
RIPMSG0(RIP_WARNING, "HMInitHandleTable failed");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
|
|
/*
|
|
* Setup shared info block.
|
|
*/
|
|
gSharedInfo.psi = gpsi;
|
|
gSharedInfo.pDispInfo = gpDispInfo;
|
|
|
|
/*
|
|
* Determine if we have unsigned drivers installed
|
|
* Use 2BD63D28D7BCD0E251195AEB519243C13142EBC3 as current key to check.
|
|
* Old key: 300B971A74F97E098B67A4FCEBBBF6B9AE2F404C
|
|
*/
|
|
if (NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\Root\\Certificates\\2BD63D28D7BCD0E251195AEB519243C13142EBC3")) ||
|
|
NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\SystemCertificates\\Root\\Certificates\\2BD63D28D7BCD0E251195AEB519243C13142EBC3")) ||
|
|
NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_USER, L"\\SOFTWARE\\Microsoft\\SystemCertificates\\Root\\Certificates\\2BD63D28D7BCD0E251195AEB519243C13142EBC3"))) {
|
|
gfUnsignedDrivers = TRUE;
|
|
}
|
|
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_WINDOWSM,
|
|
L"USERProcessHandleQuota",
|
|
DEFAULT_USER_HANDLE_QUOTA,
|
|
&lTemp,
|
|
0);
|
|
gUserProcessHandleQuota = lTemp;
|
|
|
|
/*
|
|
* The maximum number of posted message for a thread.
|
|
*/
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_WINDOWSM,
|
|
L"USERPostMessageLimit",
|
|
DEFAULT_POSTMESSAGE_LIMIT,
|
|
&lTemp,
|
|
0);
|
|
if (lTemp == 0) {
|
|
/*
|
|
* 0 means (virtually) no limit.
|
|
*/
|
|
gUserPostMessageLimit = ~0;
|
|
} else {
|
|
gUserPostMessageLimit = lTemp;
|
|
}
|
|
|
|
if (!gDrawVersionAlways) {
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_WINDOWSM,
|
|
L"DisplayVersion",
|
|
0,
|
|
&gDrawVersionAlways,
|
|
0);
|
|
}
|
|
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_TS_EXCLUDE_DESKTOP_VERSION,
|
|
L"TSExcludeDesktopVersion",
|
|
0,
|
|
&gdwTSExcludeDesktopVersion,
|
|
0);
|
|
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_TABLETPC,
|
|
L"Installed",
|
|
0,
|
|
&SYSMET(TABLETPC),
|
|
0);
|
|
|
|
FastGetProfileDwordW(NULL,
|
|
PMAP_MEDIACENTER,
|
|
L"Installed",
|
|
0,
|
|
&SYSMET(MEDIACENTER),
|
|
0);
|
|
|
|
/*
|
|
* Initialize SMWP structure.
|
|
*/
|
|
if (!AllocateCvr(&gSMWP, 4)) {
|
|
RIPMSG0(RIP_WARNING, "AllocateCvr failed");
|
|
goto ExitWin32UserInitialize;
|
|
}
|
|
LeaveCrit();
|
|
|
|
UserAssert(NT_SUCCESS(Status));
|
|
return Status;
|
|
|
|
ExitWin32UserInitialize:
|
|
LeaveCrit();
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RIPMSG1(RIP_WARNING, "UserInitialize failed with Status = 0x%x", Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserGetDesktopDC
|
|
*
|
|
* 09-Jan-1992 mikeke created
|
|
* Dec-1993 andreva changed to support desktops.
|
|
\**************************************************************************/
|
|
|
|
HDC UserGetDesktopDC(
|
|
ULONG type,
|
|
BOOL bAltType,
|
|
BOOL bValidate)
|
|
{
|
|
PETHREAD Thread;
|
|
HDC hdc;
|
|
PTHREADINFO pti = PtiCurrentShared(); // This is called from outside the crit sec
|
|
HDEV hdev = gpDispInfo->hDev;
|
|
|
|
if (bValidate && type != DCTYPE_INFO &&
|
|
IS_THREAD_RESTRICTED(pti, JOB_OBJECT_UILIMIT_HANDLES)) {
|
|
|
|
UserAssert(pti->rpdesk != NULL);
|
|
|
|
if (!ValidateHwnd(PtoH(pti->rpdesk->pDeskInfo->spwnd))) {
|
|
RIPMSG0(RIP_WARNING,
|
|
"UserGetDesktopDC fails desktop window validation");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NOTE:
|
|
* This is a real nasty trick to get both DCs created on a desktop on
|
|
* a different device to work (for the video applet) and to be able
|
|
* to clip DCs that are actually on the same device ...
|
|
*/
|
|
if (pti && pti->rpdesk)
|
|
hdev = pti->rpdesk->pDispInfo->hDev;
|
|
|
|
/*
|
|
* We want to turn this call that was originally OpenDC("Display", ...)
|
|
* into GetDC null call so this DC will be clipped to the current
|
|
* desktop or else the DC can write to any desktop. Only do this
|
|
* for client apps; let the server do whatever it wants.
|
|
*/
|
|
Thread = PsGetCurrentThread();
|
|
if ((type != DCTYPE_DIRECT) ||
|
|
(hdev != gpDispInfo->hDev) ||
|
|
PsIsSystemThread(Thread) ||
|
|
(PsGetThreadProcess(Thread) == gpepCSRSS)) {
|
|
|
|
hdc = GreCreateDisplayDC(hdev, type, bAltType);
|
|
|
|
} else {
|
|
|
|
PDESKTOP pdesk;
|
|
|
|
EnterCrit();
|
|
|
|
if (pdesk = PtiCurrent()->rpdesk) {
|
|
|
|
hdc = _GetDCEx(pdesk->pDeskInfo->spwnd,
|
|
NULL,
|
|
DCX_WINDOW | DCX_CACHE | DCX_CREATEDC);
|
|
} else {
|
|
hdc = NULL;
|
|
}
|
|
|
|
LeaveCrit();
|
|
}
|
|
|
|
return hdc;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserThreadCallout
|
|
*
|
|
*
|
|
* Called by the kernel when a thread starts or ends.
|
|
*
|
|
* Dec-1993 andreva created.
|
|
\**************************************************************************/
|
|
|
|
NTSTATUS UserThreadCallout(
|
|
IN PETHREAD pEThread,
|
|
IN PSW32THREADCALLOUTTYPE CalloutType)
|
|
{
|
|
PTHREADINFO pti;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
UserAssert(gpresUser != NULL);
|
|
|
|
switch (CalloutType) {
|
|
case PsW32ThreadCalloutInitialize:
|
|
TRACE_INIT(("Entering UserThreadCallout PsW32ThreadCalloutInitialize\n"));
|
|
|
|
if (gbNoMorePowerCallouts) {
|
|
RIPMSG0(RIP_WARNING, "No more GUI threads allowed");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/*
|
|
* Only create a thread info structure if we're initialized.
|
|
*/
|
|
if (gbUserInitialized) {
|
|
EnterCrit();
|
|
UserAssert(gpepCSRSS != NULL);
|
|
|
|
/*
|
|
* Initialize this thread
|
|
*/
|
|
Status = xxxCreateThreadInfo(pEThread);
|
|
|
|
LeaveCrit();
|
|
}
|
|
break;
|
|
|
|
case PsW32ThreadCalloutExit:
|
|
|
|
TRACE_INIT(("Entering UserThreadCallout PsW32ThreadCalloutExit\n"));
|
|
|
|
/*
|
|
* If we aren't already inside the critical section, enter it.
|
|
* Because this is the first pass, we remain in the critical
|
|
* section when we return so that our try/finally handlers
|
|
* are protected by the critical section.
|
|
* EnterCrit here before GreUnlockDisplay() provides a pti which
|
|
* may be required if unlocking the display may release some
|
|
* deferred WinEvents, for which a pti is required.
|
|
*/
|
|
EnterCrit();
|
|
|
|
pti = (PTHREADINFO)PsGetThreadWin32Thread(pEThread);
|
|
|
|
/*
|
|
* Mark this thread as in the middle of cleanup. This is useful for
|
|
* several problems in USER where we need to know this information.
|
|
*/
|
|
pti->TIF_flags |= TIF_INCLEANUP;
|
|
|
|
/*
|
|
* If we died during a full screen switch make sure we cleanup
|
|
* correctly
|
|
*/
|
|
FullScreenCleanup();
|
|
|
|
/*
|
|
* Cleanup gpDispInfo->hdcScreen - if we crashed while using it,
|
|
* it may have owned objects still selected into it. Cleaning
|
|
* it this way will ensure that gdi doesn't try to delete these
|
|
* objects while they are still selected into this public hdc.
|
|
*/
|
|
|
|
/*
|
|
* WinStations that haven't gone through the first connect do not
|
|
* have any of the graphics setup.
|
|
*/
|
|
if (!gbRemoteSession || gbVideoInitialized) {
|
|
GreCleanDC(gpDispInfo->hdcScreen);
|
|
}
|
|
|
|
/*
|
|
* This thread is exiting execution; xxxDestroyThreadInfo cleans
|
|
* up everything that can go now
|
|
*/
|
|
UserAssert(pti == PtiCurrent());
|
|
xxxDestroyThreadInfo();
|
|
LeaveCrit();
|
|
|
|
break;
|
|
}
|
|
|
|
TRACE_INIT(("Leaving UserThreadCallout\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* NtUserInitialize
|
|
*
|
|
* 01-Dec-1993 andreva created.
|
|
* 01-Dec-1995 BradG Modified to return handle to Media Change Event
|
|
\**************************************************************************/
|
|
|
|
BOOL TellGdiToGetReady();
|
|
|
|
NTSTATUS NtUserInitialize(
|
|
IN DWORD dwVersion,
|
|
IN HANDLE hPowerRequestEvent,
|
|
IN HANDLE hMediaRequestEvent)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
TRACE_INIT(("Entering NtUserInitialize\n"));
|
|
|
|
/*
|
|
* Make sure we're not trying to load this twice.
|
|
*/
|
|
if (gpepCSRSS != NULL) {
|
|
RIPMSG0(RIP_WARNING, "Can't initialize more than once");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/*
|
|
* Check version number
|
|
*/
|
|
if (dwVersion != USERCURRENTVERSION) {
|
|
KeBugCheckEx(WIN32K_INIT_OR_RIT_FAILURE,
|
|
0,
|
|
0,
|
|
dwVersion,
|
|
USERCURRENTVERSION);
|
|
}
|
|
|
|
/*
|
|
* Get the session ID from the EPROCESS structure
|
|
*/
|
|
gSessionId = PsGetCurrentProcessSessionId();
|
|
UserAssert(gSessionId == 0 || gbRemoteSession == TRUE);
|
|
|
|
Status = InitializePowerRequestList(hPowerRequestEvent);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = InitializeMediaChange(hMediaRequestEvent);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Save the system process structure.
|
|
*/
|
|
gpepCSRSS = PsGetCurrentProcess();
|
|
ObReferenceObject(gpepCSRSS);
|
|
if (!TellGdiToGetReady()) {
|
|
RIPMSG0(RIP_WARNING, "TellGdiToGetReady failed");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Allow CSR to read the screen
|
|
*/
|
|
((PW32PROCESS)PsGetProcessWin32Process(gpepCSRSS))->W32PF_Flags |= (W32PF_READSCREENACCESSGRANTED|W32PF_IOWINSTA);
|
|
|
|
|
|
Status = UserInitialize();
|
|
|
|
TRACE_INIT(("Leaving NtUserInitialize\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* NtUserProcessConnect
|
|
*
|
|
* 01-Dec-1993 Andreva Created.
|
|
\**************************************************************************/
|
|
|
|
NTSTATUS NtUserProcessConnect(
|
|
IN HANDLE hProcess,
|
|
IN OUT PVOID pConnectInfo,
|
|
IN ULONG cbConnectInfo)
|
|
{
|
|
PEPROCESS Process;
|
|
PUSERCONNECT pucConnect = (PUSERCONNECT)pConnectInfo;
|
|
USERCONNECT ucLocal;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
TRACE_INIT(("Entering NtUserProcessConnect\n"));
|
|
|
|
if (!pucConnect || (cbConnectInfo != sizeof(USERCONNECT))) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
try {
|
|
ProbeForWrite(pucConnect, cbConnectInfo, sizeof(DWORD));
|
|
|
|
ucLocal = *pucConnect;
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
/*
|
|
* Check client/server versions.
|
|
*/
|
|
if (ucLocal.ulVersion != USERCURRENTVERSION) {
|
|
|
|
RIPMSG2(RIP_ERROR,
|
|
"Client version %lx > server version %lx\n",
|
|
ucLocal.ulVersion, USERCURRENTVERSION);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
|
|
if (ucLocal.dwDispatchCount != gDispatchTableValues) {
|
|
RIPMSG2(RIP_ERROR,
|
|
"!!!! Client Dispatch info %lX != Server %lX\n",
|
|
ucLocal.dwDispatchCount, gDispatchTableValues);
|
|
}
|
|
|
|
|
|
/*
|
|
* Reference the process.
|
|
*/
|
|
Status = ObReferenceObjectByHandle(hProcess,
|
|
PROCESS_VM_OPERATION,
|
|
*PsProcessType,
|
|
UserMode,
|
|
&Process,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
/*
|
|
* Return client's view of shared data.
|
|
*/
|
|
EnterCrit();
|
|
Status = InitMapSharedSection(Process, &ucLocal);
|
|
LeaveCrit();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG2(RIP_WARNING,
|
|
"Failed to map shared data into client %x, status = %x\n",
|
|
PsGetCurrentProcessId(), Status);
|
|
}
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
try {
|
|
*pucConnect = ucLocal;
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("Leaving NtUserProcessConnect\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* xxxUserProcessCallout
|
|
*
|
|
* 01-Dec-1993 andreva Created.
|
|
\**************************************************************************/
|
|
|
|
NTSTATUS xxxUserProcessCallout(
|
|
IN PW32PROCESS Process,
|
|
IN BOOLEAN Initialize)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (Initialize) {
|
|
|
|
TRACE_INIT(("Entering xxxUserProcessCallout Initialize\n"));
|
|
|
|
UserAssert(gpresUser != NULL);
|
|
EnterCrit();
|
|
|
|
/*
|
|
* Initialize the important process level stuff.
|
|
*/
|
|
Status = xxxInitProcessInfo(Process);
|
|
|
|
LeaveCrit();
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
PEJOB Job = PsGetProcessJob(Process->Process);
|
|
|
|
if (Job != NULL &&
|
|
PsGetJobUIRestrictionsClass(Job) != 0) {
|
|
|
|
WIN32_JOBCALLOUT_PARAMETERS Parms;
|
|
|
|
/*
|
|
* aquire the job's lock and after that enter the user
|
|
* critical section.
|
|
*/
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(PsGetJobLock(Job), TRUE);
|
|
|
|
Parms.Job = Job;
|
|
Parms.CalloutType = PsW32JobCalloutAddProcess;
|
|
Parms.Data = Process;
|
|
|
|
UserAssert(PsGetJobSessionId(Job) == PsGetProcessSessionId(Process->Process));
|
|
|
|
UserJobCallout(&Parms);
|
|
|
|
ExReleaseResourceLite(PsGetJobLock(Job));
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
}
|
|
} else {
|
|
|
|
int i;
|
|
PHE phe;
|
|
PDCE *ppdce;
|
|
PDCE pdce;
|
|
|
|
TRACE_INIT(("Entering xxxUserProcessCallout Cleanup\n"));
|
|
|
|
UserAssert(gpresUser != NULL);
|
|
|
|
EnterCrit();
|
|
|
|
#if DBG
|
|
if (Process->Process == gpepCSRSS) {
|
|
|
|
/*
|
|
* CSRSS should be the last to go ...
|
|
*/
|
|
UserAssert(gppiList->ppiNextRunning == NULL);
|
|
}
|
|
#endif // DBG
|
|
|
|
if (Process->Process && PsGetProcessJob(Process->Process) != NULL) {
|
|
RemoveProcessFromJob((PPROCESSINFO)Process);
|
|
}
|
|
|
|
/*
|
|
* DestroyProcessInfo will return TRUE if any threads ever
|
|
* connected. If nothing ever connected, we needn't do
|
|
* this cleanup.
|
|
*/
|
|
if (DestroyProcessInfo(Process)) {
|
|
|
|
/*
|
|
* See if we can compact the handle table.
|
|
*/
|
|
i = giheLast;
|
|
phe = &gSharedInfo.aheList[giheLast];
|
|
while ((phe > &gSharedInfo.aheList[0]) && (phe->bType == TYPE_FREE)) {
|
|
phe--;
|
|
giheLast--;
|
|
}
|
|
|
|
/*
|
|
* Scan the DC cache to find any DC's that need to be destroyed.
|
|
*/
|
|
for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) {
|
|
|
|
pdce = *ppdce;
|
|
if (pdce->DCX_flags & DCX_DESTROYTHIS)
|
|
DestroyCacheDC(ppdce, pdce->hdc);
|
|
|
|
/*
|
|
* Step to the next DC. If the DC was deleted, there
|
|
* is no need to calculate the address of the next entry.
|
|
*/
|
|
if (pdce == *ppdce)
|
|
ppdce = &pdce->pdceNext;
|
|
}
|
|
}
|
|
|
|
UserAssert(gpresUser != NULL);
|
|
|
|
LeaveCrit();
|
|
}
|
|
|
|
TRACE_INIT(("Leaving xxxUserProcessCallout\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserGetHDEV
|
|
*
|
|
* Provided as a means for GDI to get a hold of USER's hDev.
|
|
*
|
|
* 01-Jan-1996 ChrisWil Created.
|
|
\**************************************************************************/
|
|
|
|
HDEV UserGetHDEV(VOID)
|
|
{
|
|
|
|
/*
|
|
* NOTE: This is busted.
|
|
* This need to return the device for the current desktop.
|
|
* The graphics device may not be the same for all desktops.
|
|
* -Andre
|
|
*/
|
|
return gpDispInfo->hDev;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* _UserGetGlobalAtomTable
|
|
*
|
|
* This function is called by the kernel mode global atom manager to get the
|
|
* address of the current thread's global atom table.
|
|
*
|
|
* Pointer to the global atom table for the current thread or NULL if unable
|
|
* to access it.
|
|
\**************************************************************************/
|
|
PVOID UserGlobalAtomTableCallout(
|
|
VOID)
|
|
{
|
|
PETHREAD Thread;
|
|
PTHREADINFO pti;
|
|
PWINDOWSTATION pwinsta;
|
|
PW32JOB pW32Job;
|
|
PEJOB Job;
|
|
PVOID GlobalAtomTable = NULL;
|
|
|
|
Thread = PsGetCurrentThread();
|
|
pti = PtiFromThread(Thread);
|
|
|
|
EnterCrit();
|
|
|
|
/*
|
|
* For restricted threads access the atom table off of the job object
|
|
*/
|
|
if (pti != NULL && IS_THREAD_RESTRICTED(pti, JOB_OBJECT_UILIMIT_GLOBALATOMS)) {
|
|
TAGMSG1(DBGTAG_Callout, "Retrieving global atom table for pti 0x%p", pti);
|
|
|
|
pW32Job = pti->ppi->pW32Job;
|
|
|
|
UserAssert(pW32Job->pAtomTable != NULL);
|
|
GlobalAtomTable = pW32Job->pAtomTable;
|
|
|
|
goto End;
|
|
}
|
|
|
|
Job = PsGetProcessJob(PsGetCurrentProcess());
|
|
|
|
/*
|
|
* Now handle the case where this is not a GUI thread/process
|
|
* but it is assigned to a job that has JOB_OBJECT_UILIMIT_GLOBALATOMS
|
|
* restrictions set. There is no easy way to convert this thread
|
|
* to GUI.
|
|
*/
|
|
if (pti == NULL && Job != NULL &&
|
|
(PsGetJobUIRestrictionsClass(Job) & JOB_OBJECT_UILIMIT_GLOBALATOMS)) {
|
|
|
|
/*
|
|
* find the W32JOB in the global list
|
|
*/
|
|
pW32Job = gpJobsList;
|
|
|
|
while (pW32Job) {
|
|
if (pW32Job->Job == Job) {
|
|
break;
|
|
}
|
|
pW32Job = pW32Job->pNext;
|
|
}
|
|
|
|
UserAssert(pW32Job != NULL && pW32Job->pAtomTable != NULL);
|
|
|
|
GlobalAtomTable = pW32Job->pAtomTable;
|
|
|
|
goto End;
|
|
}
|
|
|
|
#if DBG
|
|
pwinsta = NULL;
|
|
#endif
|
|
|
|
if (NT_SUCCESS(ReferenceWindowStation(Thread,
|
|
PsGetCurrentProcessWin32WindowStation(),
|
|
WINSTA_ACCESSGLOBALATOMS,
|
|
&pwinsta,
|
|
TRUE))) {
|
|
UserAssert(pwinsta != NULL);
|
|
|
|
GlobalAtomTable = pwinsta->pGlobalAtomTable;
|
|
}
|
|
|
|
End:
|
|
LeaveCrit();
|
|
|
|
#if DBG
|
|
if (GlobalAtomTable == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"_UserGetGlobalAtomTable: NULL Atom Table for pwinsta=%#p",
|
|
pwinsta);
|
|
}
|
|
#endif
|
|
|
|
return GlobalAtomTable;
|
|
}
|