Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2351 lines
64 KiB

/**************************************************************************\
* Module Name: server.c
*
* Server support routines for the CSR stuff. This basically performs the
* startup/initialization for USER.
*
* Copyright (c) Microsoft Corp. 1990-1996 All Rights Reserved
*
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Initialization Routines (external).
*/
NTSTATUS InitQEntryLookaside(VOID);
NTSTATUS InitKeyStateLookaside(VOID);
NTSTATUS InitSMSLookaside(VOID);
BOOL xxxClientLoadDisplayResource(PUNICODE_STRING, PDISPLAYRESOURCE);
FARPROC gpfnDebugAttachRoutine;
LONG xxxDesktopWndProc(PWND pwnd, UINT message, DWORD wParam, LPARAM lParam);
/*
* 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)
LPCWSTR szEDITCLASS = TEXT("Edit");
LPCWSTR szBUTTONCLASS = TEXT("Button");
LPCWSTR szSTATICCLASS = TEXT("Static");
LPCWSTR szLISTBOXCLASS = TEXT("ListBox");
LPCWSTR szSCROLLBARCLASS = TEXT("ScrollBar");
LPCWSTR szCOMBOLISTBOXCLASS = TEXT("ComboLBox");
LPCWSTR szCOMBOBOXCLASS = TEXT("ComboBox");
LPCWSTR szMDICLIENTCLASS = TEXT("MDIClient");
LPCWSTR szDDEMLEVENTCLASS = TEXT("DDEMLEvent");
LPCWSTR szDDEMLMOTHERCLASS = TEXT("DDEMLMom");
LPCWSTR szDDEML16BITCLASS = TEXT("DMGClass");
LPCWSTR szDDEMLCLIENTCLASSW = L"DDEMLUnicodeClient";
LPCWSTR szDDEMLSERVERCLASSW = L"DDEMLUnicodeServer";
LPCWSTR szDDEMLCLIENTCLASSA = L"DDEMLAnsiClient";
LPCWSTR szDDEMLSERVERCLASSA = L"DDEMLAnsiServer";
#ifdef FE_IME
LPCWSTR szIMECLASS = TEXT("IME");
#endif
/***************************************************************************\
* Message Tables
*
* DefDlgProc
* MenuWndProc
* ScrollBarWndProc
* StaticWndProc
* ButtonWndProc
* ListboxWndProc
* ComboWndProc
* EditWndProc
* DefWindowMsgs
* DefWindowSpecMsgs
*
*
* 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_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,
0
};
CONST WORD gawMenuWndProc[] = {
WM_CREATE,
WM_FINALDESTROY,
WM_PAINT,
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,
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,
WM_PRINTCLIENT,
0
};
CONST WORD gawStaticWndProc[] = {
STM_GETICON,
STM_GETIMAGE,
STM_SETICON,
STM_SETIMAGE,
WM_ERASEBKGND,
WM_PAINT,
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,
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,
0
};
CONST WORD gawListboxWndProc[] = {
LB_GETTOPINDEX,
LB_SETTOPINDEX,
WM_SIZE,
WM_ERASEBKGND,
LB_RESETCONTENT,
WM_TIMER,
WM_MOUSEMOVE,
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,
WM_NCCREATE,
WM_WINDOWPOSCHANGED,
WM_MOUSEWHEEL,
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,
WM_MEASUREITEM,
WM_DELETEITEM,
WM_DRAWITEM,
WM_COMPAREITEM,
WM_NCCREATE,
WM_HELP,
WM_MOUSEWHEEL,
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_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_INPUTLANGCHANGE,
WM_KEYDOWN,
WM_KILLFOCUS,
WM_LBUTTONDBLCLK,
WM_LBUTTONDOWN,
WM_LBUTTONUP,
WM_MOUSEMOVE,
WM_NCCREATE,
WM_NCDESTROY,
WM_RBUTTONDOWN,
WM_RBUTTONUP,
WM_FINALDESTROY,
#if 0
WM_NCPAINT,
#endif
WM_PAINT,
WM_PASTE,
WM_PRINTCLIENT,
WM_SETFOCUS,
WM_SETFONT,
WM_SETREDRAW,
WM_SETTEXT,
WM_SIZE,
WM_SYSCHAR,
WM_SYSKEYDOWN,
WM_SYSTIMER,
WM_UNDO,
WM_VSCROLL,
WM_MOUSEWHEEL,
0
};
#ifdef FE_IME
CONST WORD gawImeWndProc[] = {
WM_ERASEBKGND,
WM_PAINT,
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,
0
};
#endif
/*
* 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_QUERYDRAGICON,
WM_NCCREATE,
WM_SETICON,
WM_NCCALCSIZE,
WM_NCPAINT,
WM_NCACTIVATE,
WM_NCMOUSEMOVE,
WM_NCRBUTTONDOWN,
WM_NCLBUTTONDOWN,
WM_NCLBUTTONUP,
WM_NCLBUTTONDBLCLK,
WM_KEYUP,
WM_SYSKEYUP,
WM_SYSCHAR,
WM_SYSCOMMAND,
WM_QUERYDROPOBJECT,
WM_CLIENTSHUTDOWN,
WM_SYNCPAINT,
WM_PRINT,
WM_GETICON,
WM_QUERYDRAGICON,
WM_CONTEXTMENU,
WM_SYSMENU,
WM_INPUTLANGCHANGEREQUEST,
WM_INPUTLANGCHANGE,
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,
WM_SYSKEYDOWN,
WM_DROPOBJECT,
WM_WINDOWPOSCHANGING,
WM_WINDOWPOSCHANGED,
WM_KLUDGEMINRECT,
WM_CTLCOLOR,
WM_CTLCOLORMSGBOX,
WM_CTLCOLOREDIT,
WM_CTLCOLORLISTBOX,
WM_CTLCOLORBTN,
WM_CTLCOLORDLG,
WM_CTLCOLORSCROLLBAR,
WM_NCHITTEST,
WM_CTLCOLORSTATIC,
WM_NOTIFYFORMAT,
WM_DEVICECHANGE,
WM_POWERBROADCAST,
WM_MOUSEWHEEL,
#ifdef FE_IME
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,
#endif
0
};
/***************************************************************************\
* DispatchServerMessage
*
*
* 19-Aug-1992 MikeKe Created
\***************************************************************************/
#define WRAPPFN(pfn, type) \
LONG xxxWrap ## pfn( \
PWND pwnd, \
UINT message, \
DWORD wParam, \
LONG lParam, \
DWORD xParam) \
{ \
return xxx ## pfn((type)pwnd, message, wParam, lParam); \
}
WRAPPFN(SBWndProc, PSBWND)
WRAPPFN(MenuWindowProc, PWND)
WRAPPFN(DesktopWndProc, PWND);
WRAPPFN(DefWindowProc, PWND)
DWORD xxxWrapCallNextHookEx(
PWND pwnd,
UINT message,
DWORD wParam,
LONG lParam,
DWORD xParam)
{
return xxxCallNextHookEx((int)pwnd, message, wParam);
}
DWORD xxxWrapSendMessage(
PWND pwnd,
UINT message,
DWORD wParam,
LONG lParam,
DWORD xParam)
{
return xxxSendMessageTimeout(pwnd,
message,
wParam,
lParam,
SMTO_NORMAL,
0,
NULL);
}
/***************************************************************************\
* xxxUnusedFunctionId
*
* This function is catches attempts to access invalid entries in the server
* size function dispatch table.
*
\***************************************************************************/
DWORD xxxUnusedFunctionId(
PWND pwnd,
UINT message,
DWORD wParam,
LONG lParam,
DWORD 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
\***************************************************************************/
DWORD xxxWrapCallWindowProc(
PWND pwnd,
UINT message,
DWORD wParam,
LONG lParam,
DWORD xParam)
{
PCALLPROCDATA pCPD;
DWORD dwRet = 0;
if (pCPD = HMValidateHandleNoRip((PVOID)xParam, TYPE_CALLPROC)) {
dwRet = 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
*/
dwRet = ScSendMessage(pwnd,
message,
wParam,
lParam,
xParam,
gpsi->apfnClientA.pfnDispatchMessage,
(xParam == (DWORD)gpsi->apfnClientA.pfnEditWndProc) ?
SCMS_FLAGS_ANSI : 0);
}
return dwRet;
}
/***************************************************************************\
* InitSyncOnlyMessages
*
* This routine generates a bit array of those messages that can't be posted
* because they hold pointers or handles or other values that imply
* synchronous-only messages (for SendMessage). PostMessage and
* SendNotifyMessage checks this array before continuing. This routine is
* called during initialization.
*
* 20-May-1992 ScottLu Created.
\***************************************************************************/
VOID InitSyncOnlyMessages(VOID)
{
CONST SHORT *ps;
static CONST SHORT amsgsSyncOnly[] = {
WM_CREATE,
WM_SETTEXT,
WM_GETTEXT,
WM_GETTEXTLENGTH,
WM_ERASEBKGND,
WM_WININICHANGE,
WM_DEVMODECHANGE,
WM_GETMINMAXINFO,
WM_ICONERASEBKGND,
WM_DRAWITEM,
WM_MEASUREITEM,
WM_DELETEITEM,
WM_GETFONT,
WM_WINHELP,
WM_COMPAREITEM,
WM_WINDOWPOSCHANGING,
WM_WINDOWPOSCHANGED,
WM_HELP,
WM_STYLECHANGING,
WM_STYLECHANGED,
WM_NCCREATE,
WM_NCCALCSIZE,
WM_NCPAINT,
WM_KLUDGEMINRECT,
WM_GETDLGCODE,
WM_HOOKMSG,
EM_GETSEL,
EM_GETRECT,
EM_REPLACESEL,
EM_GETLINE,
EM_SETTABSTOPS,
EM_SETRECT,
EM_SETRECTNP,
WM_CTLCOLORMSGBOX,
WM_CTLCOLOREDIT,
WM_CTLCOLORLISTBOX,
WM_CTLCOLORBTN,
WM_CTLCOLORDLG,
WM_CTLCOLORSCROLLBAR,
WM_CTLCOLORSTATIC,
CB_GETEDITSEL,
CB_DIR,
CB_ADDSTRING,
CB_GETLBTEXT,
CB_GETLBTEXTLEN,
CB_INSERTSTRING,
CB_FINDSTRING,
CB_SELECTSTRING,
CB_GETDROPPEDCONTROLRECT,
CB_FINDSTRINGEXACT,
LB_ADDSTRING,
LB_ADDSTRINGUPPER,
LB_ADDSTRINGLOWER,
LB_INSERTSTRING,
LB_FINDSTRINGEXACT,
LB_INSERTSTRINGUPPER,
LB_INSERTSTRINGLOWER,
LB_GETTEXT,
LB_GETTEXTLEN,
LB_DIR,
LB_SELECTSTRING,
LB_FINDSTRING,
LB_GETSELITEMS,
LB_SETTABSTOPS,
LB_ADDFILE,
LB_GETITEMRECT,
MN_FINDMENUWINDOWFROMPOINT,
WM_PARENTNOTIFY,
WM_NEXTMENU,
WM_SIZING,
WM_MOVING,
// WM_DEVICECHANGE, -- depends on wParam value.
WM_MDICREATE,
WM_MDIGETACTIVE,
WM_DROPOBJECT,
WM_QUERYDROPOBJECT,
WM_DRAGLOOP,
WM_DRAGSELECT,
WM_DRAGMOVE,
WM_PAINTCLIPBOARD,
WM_SIZECLIPBOARD,
WM_ASKCBFORMATNAME,
WM_COPYGLOBALDATA,
WM_COPYDATA,
SBM_GETRANGE,
SBM_SETSCROLLINFO,
SBM_GETSCROLLINFO,
#ifdef FE_IME // amsgsSyncOnly[]
WM_CONVERTREQUESTEX,
WM_WNT_CONVERTREQUESTEX,
WM_CONVERTREQUEST,
WM_IME_SETCONTEXT,
WM_IME_CONTROL,
#endif
-1
};
TRACE_INIT(("UserInit: Initialize Sync Only Messages\n"));
for (ps = amsgsSyncOnly; *ps != -1; ps++)
SETSYNCONLYMESSAGE(*ps);
#ifdef DEBUG
{
int i;
/*
* 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
*/
for (i=0; i<WM_USER; i++)
if ((gapfnScSendMessage[i] != SfnDWORD)
&& (gapfnScSendMessage[i] != SfnINWPARAMCHAR)
#ifdef FE_SB
&& (gapfnScSendMessage[i] != SfnINWPARAMDBCSCHAR)
#endif
&& (gapfnScSendMessage[i] != SfnPAINT)
&& (gapfnScSendMessage[i] != SfnSENTDDEMSG)
&& (gapfnScSendMessage[i] != 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 // DEBUG
}
/***************************************************************************\
* 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);
RtlZeroMemory(*ppbyte, cbTable);
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"));
#ifdef DEBUG
RtlZeroMemory(&STOCID(FNID_START), sizeof(gpsi->aStoCidPfn));
RtlZeroMemory(&FNID(FNID_START), sizeof(gpsi->mpFnidPfn));
TEBOffsetCheck();
UserAssert(sizeof(CLIENTINFO) <= WIN32_CLIENT_INFO_LENGTH * sizeof(ULONG));
#endif
/*
* 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;
/*
* 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).
*/
FNID(FNID_SCROLLBAR) = xxxWrapSBWndProc;
FNID(FNID_ICONTITLE) = xxxWrapDefWindowProc;
FNID(FNID_MENU) = xxxWrapMenuWindowProc;
FNID(FNID_DESKTOP) = xxxWrapDesktopWndProc;
FNID(FNID_DEFWINDOWPROC) = xxxWrapDefWindowProc;
FNID(FNID_SENDMESSAGE) = xxxWrapSendMessage;
FNID(FNID_HKINLPCWPEXSTRUCT) = fnHkINLPCWPEXSTRUCT;
FNID(FNID_HKINLPCWPRETEXSTRUCT) = fnHkINLPCWPRETEXSTRUCT;
FNID(FNID_CALLNEXTHOOKPROC) = xxxWrapCallNextHookEx;
FNID(FNID_SENDMESSAGEFF) = xxxSendMessageFF;
FNID(FNID_SENDMESSAGEEX) = xxxSendMessageEx;
FNID(FNID_CALLWINDOWPROC) = xxxWrapCallWindowProc;
FNID(FNID_SENDMESSAGEBSM) = xxxSendMessageBSM;
/*
* Initialize all unused entries in the api function table.
*/
FNID(FNID_BUTTON) = xxxUnusedFunctionId;
FNID(FNID_COMBOBOX) = xxxUnusedFunctionId;
FNID(FNID_COMBOLISTBOX) = xxxUnusedFunctionId;
FNID(FNID_DEFFRAMEPROC) = xxxUnusedFunctionId;
FNID(FNID_DEFMDICHILDPROC) = xxxUnusedFunctionId;
FNID(FNID_DIALOG) = xxxUnusedFunctionId;
FNID(FNID_EDIT) = xxxUnusedFunctionId;
FNID(FNID_LISTBOX) = xxxUnusedFunctionId;
FNID(FNID_MB_DLGPROC) = xxxUnusedFunctionId;
FNID(FNID_MDIACTIVATEDLGPROC) = xxxUnusedFunctionId;
FNID(FNID_MDICLIENT) = xxxUnusedFunctionId;
FNID(FNID_STATIC) = xxxUnusedFunctionId;
#ifdef FE_IME
FNID(FNID_IME) = xxxUnusedFunctionId;
#else
FNID(FNID_UNUSED) = xxxUnusedFunctionId;
#endif
/*
* Finish initializing the array.
*/
for (i = (FNID_END - FNID_START); i < FNID_ARRAY_SIZE; i++) {
FNID((i + FNID_START)) = xxxUnusedFunctionId;
}
#ifdef DEBUG
{
PDWORD pdw;
/*
* Make sure that everyone got initialized.
*/
for (pdw=(PDWORD)&STOCID(FNID_START);
(DWORD)pdw<(DWORD)(&STOCID(FNID_WNDPROCEND)); pdw++) {
UserAssert(*pdw);
}
for (pdw=(PDWORD)&FNID(FNID_START);
(DWORD)pdw<(DWORD)(&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);
#ifdef FE_IME
INITMSGTABLE(awmControl[FNID_IME - FNID_START], ImeWndProc);
#endif
}
/**************************************************************************\
* InitMBStringsArray
*
* 18-Oct-1995 GerardoB Created.
\**************************************************************************/
VOID InitMBStringArrays(VOID)
{
DWORD *plpdw;
/*
* String IDs
*/
plpdw = gpsi->mpAllMBbtnStringsToSTR;
*plpdw++ = STR_OK;
*plpdw++ = STR_CANCEL;
*plpdw++ = STR_YES;
*plpdw++ = STR_NO;
*plpdw++ = STR_RETRY;
*plpdw++ = STR_ABORT;
*plpdw++ = STR_IGNORE;
*plpdw++ = STR_CLOSE;
*plpdw++ = STR_HELP;
/*
* String Buffer offsets
*/
plpdw = gpsi->AllMBbtnStrings;
*plpdw++ = FIELDOFFSET(SERVERINFO, szOK) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szCANCEL) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szYES) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szNO) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szRETRY) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szABORT) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szIGNORE) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szCLOSE) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
*plpdw++ = FIELDOFFSET(SERVERINFO, szHELP) - FIELDOFFSET(SERVERINFO, AllMBbtnStrings);
}
/***************************************************************************\
* 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.
\***************************************************************************/
VOID InitOLEFormats(VOID)
{
UINT idx;
UINT nCount;
ATOM a1;
ATOM a2;
static LPCWSTR lpszOLEFormats[] = {
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"
};
TRACE_INIT(("UserInit: Initialize OLE Formats\n"));
nCount = sizeof(lpszOLEFormats) / sizeof(lpszOLEFormats[0]);
a1 = UserAddAtom(L"ObjectLink", TRUE);
for (idx=0; idx < nCount; idx++) {
a2 = UserAddAtom(lpszOLEFormats[idx], TRUE);
UserAssert(((a1 + 1) == a2) && (a1 = a2));
}
}
/***************************************************************************\
* InitGlobalRIPFlags (debug only)
*
* This initializes the global RIP flags from the registry.
*
*
* 25-Aug-1995 ChrisWil Created.
\***************************************************************************/
VOID InitGlobalRIPFlags(VOID)
{
#ifdef DEBUG
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 = sizeof(aRIPFlags) / sizeof(aRIPFlags[0]);
/*
* 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_RIP_FLAG(RIPF_PROMPTONWARNING);
CLEAR_RIP_FLAG(RIPF_PRINTONWARNING);
for (idx=0; idx < nCount; idx++) {
dwFlag = FastGetProfileDwordW(PMAP_WINDOWSM,
aRIPFlags[idx].lpszKey,
aRIPFlags[idx].dwDef);
if (dwFlag) {
SET_RIP_FLAG(aRIPFlags[idx].dwFlag);
} else {
CLEAR_RIP_FLAG(aRIPFlags[idx].dwFlag);
}
}
#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);
}
/***************************************************************************\
* InitCreateSharedSection
*
* This creates the shared section.
*
*
* 25-Aug-1995 ChrisWil Created comment block.
\***************************************************************************/
#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif
#define ROUND_UP_TO_PAGES(SIZE) \
(((ULONG)(SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
NTSTATUS InitCreateSharedSection(
ULONG ulHeapSize)
{
ULONG ulHandleTableSize;
NTSTATUS Status;
LARGE_INTEGER SectionSize;
ULONG ViewSize;
TRACE_INIT(("UserInit: Create Shared Memory Section\n"));
UserAssert(ghReadOnlySharedSection == NULL);
ulHeapSize = ROUND_UP_TO_PAGES(ulHeapSize * 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 = MmCreateSection(&ghReadOnlySharedSection,
SECTION_ALL_ACCESS,
(POBJECT_ATTRIBUTES)NULL,
&SectionSize,
PAGE_EXECUTE_READWRITE,
SEC_RESERVE,
(HANDLE)NULL,
NULL);
if (!NT_SUCCESS(Status)) {
return Status;
}
ViewSize = 0;
gpReadOnlySharedSectionBase = NULL;
Status = MmMapViewInSystemSpace(ghReadOnlySharedSection,
&gpReadOnlySharedSectionBase,
&ViewSize);
if (!NT_SUCCESS(Status)) {
ObDereferenceObject(ghReadOnlySharedSection);
return Status;
}
ghheapSharedRO = (PBYTE)gpReadOnlySharedSectionBase + ulHandleTableSize;
TRACE_INIT(("UserInit: Share: BaseAddr = %X; Heap = %X, ViewSize = %X\n",
gpReadOnlySharedSectionBase, ghheapSharedRO, ViewSize));
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(("UserInit: Create User Critical-Sections\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(NonPagedPoolMustSucceed,
sizeof(ERESOURCE),
TAG_SYSTEM);
gpresMouseEventQueue = ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
sizeof(ERESOURCE),
TAG_SYSTEM);
if (!gpresUser || !gpresMouseEventQueue)
return FALSE;
ExInitializeResourceLite(gpresUser);
ExInitializeResourceLite(gpresMouseEventQueue);
return TRUE;
}
/**************************************************************************\
* InitCreateObjectDirectory
*
* Create and initialize the user critical sections needed throughout the
* system.
*
* 23-Jan-1996 ChrisWil Created.
\**************************************************************************/
BOOL InitCreateObjectDirectory(VOID)
{
HANDLE hDir;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
TRACE_INIT(("UserInit: Create User Object-Directory\n"));
RtlInitUnicodeString(&UnicodeString, szWindowStationDirectory);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
gpsdInitWinSta);
Status = ZwCreateDirectoryObject(&hDir,
DIRECTORY_CREATE_OBJECT,
&ObjectAttributes);
UserFreePool(gpsdInitWinSta);
ZwClose(hDir);
gpsdInitWinSta = NULL;
if (!NT_SUCCESS(Status)) {
UserAssert(NT_SUCCESS(Status));
return FALSE;
}
return TRUE;
}
/**************************************************************************\
* InitCreateUserSubsystem
*
* Create and initialize the user subsystem stuff.
* system.
*
* 23-Jan-1996 ChrisWil Created.
\**************************************************************************/
BOOL InitCreateUserSubsystem(VOID)
{
LPWSTR lpszSubSystem;
LPWSTR lpszT;
UNICODE_STRING strSize;
BOOL bSuccess = FALSE;
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) {
if (FastGetProfileStringW(PMAP_SUBSYSTEMS,
L"Windows",
L"SharedSection=,3072",
lpszSubSystem,
USRINIT_SHAREDSECT_READ_SIZE)) {
bSuccess = TRUE;
/*
* Locate the SharedSection portion of the definition and extract
* the second value.
*/
gdwDesktopSectionSize = USRINIT_WINDOWSECT_SIZE;
gdwNOIOSectionSize = USRINIT_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 >= USRINIT_WINDOWSECT_SIZE);
gdwDesktopSectionSize = max(USRINIT_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 >= USRINIT_NOIOSECT_SIZE);
gdwNOIOSectionSize = max(USRINIT_NOIOSECT_SIZE, gdwNOIOSectionSize);
}
}
}
} else {
RIPMSG0(RIP_WARNING,
"UserInit: Windows subsystem definition not found");
}
UserFreePool(lpszSubSystem);
}
return bSuccess;
}
/***************************************************************************\
* InitMapSharedSection
*
* This maps the shared section.
*
*
* 25-Aug-1995 ChrisWil Created comment block.
\***************************************************************************/
#define CALC_DELTA(element) \
(PVOID)((PBYTE)pClientBase + \
((PBYTE)gSharedInfo.element - \
(PBYTE)gpReadOnlySharedSectionBase))
NTSTATUS InitMapSharedSection(
PEPROCESS Process,
PUSERCONNECT pUserConnect)
{
NTSTATUS Status;
ULONG ViewSize;
LARGE_INTEGER liOffset;
int i;
PVOID pClientBase = NULL;
TRACE_INIT(("UserInit: Map Shared Memory Section\n"));
ViewSize = 0;
liOffset.QuadPart = 0;
Status = MmMapViewOfSection(ghReadOnlySharedSection,
Process,
&pClientBase,
0,
0,
&liOffset,
&ViewSize,
ViewUnmap,
SEC_NO_CHANGE,
PAGE_EXECUTE_READ);
if (NT_SUCCESS(Status)) {
TRACE_INIT(("UserInit: Map: Client SharedInfo Base = %x\n", pClientBase));
pUserConnect->siClient.psi = CALC_DELTA(psi);
pUserConnect->siClient.aheList = CALC_DELTA(aheList);
if (gSharedInfo.pszDllList)
pUserConnect->siClient.pszDllList = CALC_DELTA(pszDllList);
else
pUserConnect->siClient.pszDllList = NULL;
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;
}
/**************************************************************************\
* InitLoadResources
*
*
* 25-Aug-1995 ChrisWil Created.
\**************************************************************************/
VOID InitLoadResources(VOID)
{
DISPLAYRESOURCE dr;
TRACE_INIT(("UserInit: Load Display Resources\n"));
xxxClientLoadDisplayResource(&strDisplayDriver, &dr);
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) = (32 / dr.xCompressCursor);
SYSMET(CYCURSOR) = (32 / 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);
SYSMET(CXFULLSCREEN) = gpDispInfo->rcPrimaryScreen.right;
SYSMET(CYFULLSCREEN) = gpDispInfo->rcPrimaryScreen.bottom - SYSMET(CYCAPTION);
/*
* Set the initial cursor position to the center of the primary screen.
*/
ptCursor.x = gpDispInfo->rcPrimaryScreen.right / 2;
ptCursor.y = gpDispInfo->rcPrimaryScreen.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_ERROR, "GetCharDimensions: _GetTextMetricsW failed. hdc %#lx", hdc);
tm = gpsi->tmSysFont; // damage control
}
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_ERROR, "GetCharDimensions: GreGetTextExtentW failed. hdc %#lx", hdc);
}
}
UserAssert(tm.tmAveCharWidth > 0);
return tm.tmAveCharWidth;
}
/**************************************************************************\
* 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;
POBJECT_TYPE_INITIALIZER pTypeInfo;
/*
* Allow a trace of all the init stuff going on related to display drivers.
* Usefull to debug boot time problems related to graphics.
*/
if (*(PULONG)NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
TraceDisplayDriverLoad = 1;
#ifdef ANDREVA_DBG
TraceDisplayDriverLoad = 1;
#endif
/*
* Create the shared section and user-crit's. Enter the
* user-crit if successful, then proceed with the rest
* of the initialization.
*/
Status = InitCreateSharedSection(USRINIT_SHAREDSECT_SIZE);
if (!NT_SUCCESS(Status))
return Status;
if (!InitCreateUserCrit())
return STATUS_NO_MEMORY;
EnterCrit();
/*
* Initialize security stuff.
*/
InitSecurity();
/*
* Fill in windowstation and desktop object types
*/
pTypeInfo = &(*ExWindowStationObjectType)->TypeInfo;
pTypeInfo->DefaultNonPagedPoolCharge = sizeof(WINDOWSTATION) + sizeof(KEVENT);
pTypeInfo->DefaultPagedPoolCharge = 0;
pTypeInfo->MaintainHandleCount = TRUE;
pTypeInfo->CloseProcedure = DestroyWindowStation;
pTypeInfo->DeleteProcedure = FreeWindowStation;
pTypeInfo->ParseProcedure = ParseWindowStation;
pTypeInfo->ValidAccessMask = WinStaMapping.GenericAll;
pTypeInfo->GenericMapping = WinStaMapping;
pTypeInfo = &(*ExDesktopObjectType)->TypeInfo;
pTypeInfo->DefaultNonPagedPoolCharge = sizeof(DESKTOP);
pTypeInfo->DefaultPagedPoolCharge = 0;
pTypeInfo->MaintainHandleCount = TRUE;
pTypeInfo->OpenProcedure = MapDesktop;
pTypeInfo->CloseProcedure = UnmapDesktop;
pTypeInfo->DeleteProcedure = FreeDesktop;
pTypeInfo->ParseProcedure = ParseDesktop;
pTypeInfo->ValidAccessMask = DesktopMapping.GenericAll;
pTypeInfo->GenericMapping = DesktopMapping;
/*
* Create object directory.
*/
if (!InitCreateObjectDirectory())
goto LeaveCritExit;
/*
* Initialize the caption cache.
*/
RtlZeroMemory(&cachedCaptions, sizeof(cachedCaptions));
/*
* Open the profile for fast mapping, while we
* call routines to read from the registry.
*/
FastOpenProfileUserMapping();
/*
* Initialize the lookaside stuff.
*/
if (!NT_SUCCESS(InitQEntryLookaside()))
goto LeaveCritExit;
if (!NT_SUCCESS(InitKeyStateLookaside()))
goto LeaveCritExit;
if (!NT_SUCCESS(InitSMSLookaside()))
goto LeaveCritExit;
/*
* Create the atom table.
*/
UserRtlCreateAtomTable(USRINIT_ATOMBUCKET_SIZE);
atomUSER32 = UserAddAtom(szUSER32, TRUE);
gatomFirstPinned = atomUSER32;
/*
* Initialize the user subsystem information.
*/
if (!InitCreateUserSubsystem())
goto LeaveCritExit;
/*
* Allocated shared SERVERINFO structure.
*/
if ((gpsi = (PSERVERINFO)SharedAlloc(sizeof(SERVERINFO))) == NULL)
goto LeaveCritExit;
/*
* Initialize the DISPLAYINFO structure.
*/
if ((gpDispInfo = SharedAlloc(sizeof(DISPLAYINFO))) == NULL) {
UserFreePool(gpsi);
goto LeaveCritExit;
}
RtlZeroMemory(gpsi, sizeof(*gpsi));
RtlZeroMemory(gpDispInfo, sizeof(*gpDispInfo));
/*
* 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.
*/
gpsi->RipFlags = RIPF_PROMPTONERROR |
RIPF_PRINTONERROR |
RIPF_PRINTONWARNING |
RIPF_KERNEL;
gpsi->dwDefaultHeapSize = gdwDesktopSectionSize * 1024;
#ifdef DEBUG
gpsi->RipFlags |= RIPF_CHECKED;
#endif
/*
* Initialize procedures and message tables.
* Initialize the class structures for Get/SetClassWord/Long.
* Initialize message-box strings.
* Initialize OLE-Formats (performance-hack).
*/
InitFunctionTables();
InitMessageTables();
InitSyncOnlyMessages();
InitClassOffsets();
InitMBStringArrays();
InitOLEFormats();
/*
* 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.
*/
gpsi->atomSysClass[ICLS_BUTTON] = UserAddAtom(szBUTTONCLASS, TRUE);
gpsi->atomSysClass[ICLS_COMBOBOX] = UserAddAtom(szCOMBOBOXCLASS, TRUE);
gpsi->atomSysClass[ICLS_COMBOLISTBOX] = UserAddAtom(szCOMBOLISTBOXCLASS, TRUE);
gpsi->atomSysClass[ICLS_DIALOG] = (ATOM)DIALOGCLASS;
gpsi->atomSysClass[ICLS_EDIT] = UserAddAtom(szEDITCLASS, TRUE);
gpsi->atomSysClass[ICLS_LISTBOX] = UserAddAtom(szLISTBOXCLASS, TRUE);
gpsi->atomSysClass[ICLS_MDICLIENT] = UserAddAtom(szMDICLIENTCLASS, TRUE);
gpsi->atomSysClass[ICLS_STATIC] = UserAddAtom(szSTATICCLASS, TRUE);
gpsi->atomSysClass[ICLS_DDEMLMOTHER] = UserAddAtom(szDDEMLMOTHERCLASS, TRUE);
gpsi->atomSysClass[ICLS_DDEML16BIT] = UserAddAtom(szDDEML16BITCLASS, TRUE);
gpsi->atomSysClass[ICLS_DDEMLCLIENTA] = UserAddAtom(szDDEMLCLIENTCLASSA, TRUE);
gpsi->atomSysClass[ICLS_DDEMLCLIENTW] = UserAddAtom(szDDEMLCLIENTCLASSW, TRUE);
gpsi->atomSysClass[ICLS_DDEMLSERVERA] = UserAddAtom(szDDEMLSERVERCLASSA, TRUE);
gpsi->atomSysClass[ICLS_DDEMLSERVERW] = UserAddAtom(szDDEMLSERVERCLASSW, TRUE);
#ifdef FE_IME
gpsi->atomSysClass[ICLS_IME] = UserAddAtom(szIMECLASS, TRUE);
#endif
gpsi->atomSysClass[ICLS_DESKTOP] = (ATOM)DESKTOPCLASS;
gpsi->atomSysClass[ICLS_SWITCH] = (ATOM)SWITCHWNDCLASS;
gpsi->atomSysClass[ICLS_MENU] = (ATOM)MENUCLASS;
gpsi->atomSysClass[ICLS_SCROLLBAR] = UserAddAtom(szSCROLLBARCLASS, TRUE);
gpsi->atomSysClass[ICLS_ICONTITLE] = (ATOM)ICONTITLECLASS;
gpsi->atomSysClass[ICLS_DDEMLEVENT] = UserAddAtom(szDDEMLEVENTCLASS, TRUE);
/*
* Initialize the integer atoms for our magic window properties
*/
atomCheckpointProp = UserAddAtom(CHECKPOINT_PROP_NAME, TRUE);
atomDDETrack = UserAddAtom(DDETRACK_PROP_NAME, TRUE);
atomQOS = UserAddAtom(QOS_PROP_NAME, TRUE);
atomDDEImp = UserAddAtom(DDEIMP_PROP_NAME, TRUE);
gpsi->atomContextHelpIdProp = UserAddAtom(szCONTEXTHELPIDPROP, TRUE);
gpsi->atomIconSmProp = UserAddAtom(ICONSM_PROP_NAME, TRUE);
gpsi->atomIconProp = UserAddAtom(ICON_PROP_NAME, TRUE);
gpsi->uiShellMsg = UserAddAtom(L"SHELLHOOK", TRUE);
guiActivateShellWindow = UserAddAtom(L"ACTIVATESHELLWINDOW", TRUE);
guiOtherWindowCreated = UserAddAtom(L"OTHERWINDOWCREATED", TRUE);
guiOtherWindowDestroyed = UserAddAtom(L"OTHERWINDOWDESTROYED", TRUE);
gatomLastPinned = guiOtherWindowDestroyed;
/*
* Do init-loading. These calls will setup parts of the gpDispInfo.
*/
LW_LoadSomeStrings();
LW_LoadDllList();
/*
* Initialize the handle manager.
*/
HMInitHandleTable(gpReadOnlySharedSectionBase);
/*
* Setup shared info block.
*/
gSharedInfo.psi = gpsi;
/*
* Perform driver-loading sequence. If this is successful, the
* gpDispInfo->hDev and pdevlock should be initialized.
*/
if (!NT_SUCCESS(InitLoadDriver()))
goto LeaveCritExit;
/*
* Now that the system is initialized, allocate
* a pti for this thread.
*/
Status = xxxCreateThreadInfo(W32GetCurrentThread());
/*
* Initialize Global RIP flags (debug only).
*/
InitGlobalRIPFlags();
LW_BrushInit();
InitLoadResources();
LeaveCritExit:
FastCloseProfileUserMapping();
LeaveCrit();
return Status;
}
/**************************************************************************\
* UserGetDesktopDC
*
* 09-Jan-1992 mikeke created
* Dec-1993 andreva changed to support desktops.
\**************************************************************************/
HDC UserGetDesktopDC(
ULONG type,
BOOL bAltType)
{
PETHREAD Thread;
HDC hdc;
PTHREADINFO pti = PtiCurrentShared(); // This is called from outside the crit sec
HDEV hdev = gpDispInfo->hDev;
/*
* !!! BUGBUG
* 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) ||
IS_SYSTEM_THREAD(Thread) ||
(Thread->ThreadsProcess == 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
*
* Dec-1993 andreva created.
\**************************************************************************/
NTSTATUS UserThreadCallout(
IN PW32THREAD Thread,
IN PSW32THREADCALLOUTTYPE CalloutType)
{
PTHREADINFO pti;
NTSTATUS Status = STATUS_SUCCESS;
BOOL fCritIn;
switch (CalloutType) {
case PsW32ThreadCalloutInitialize:
/*
* Only create a thread info structure if we're initialized.
*/
if (gpresUser) {
EnterCrit();
Status = xxxCreateThreadInfo(Thread);
LeaveCrit();
}
break;
case PsW32ThreadCalloutExit:
/*
* First call the DCI release code to synchronize with DCI when
* releasing the DEV lock
*/
GreLockDisplay(gpDispInfo->pDevLock);
GreUnlockDisplay(gpDispInfo->pDevLock);
/*
* 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();
/*
* 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 = (PTHREADINFO)Thread;
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.
*/
GreCleanDC(gpDispInfo->hdcScreen);
/*
* This thread is exiting execution; xxxDestroyThreadInfo cleans
* up everything that can go now
*/
UserAssert(pti == PtiCurrent());
xxxDestroyThreadInfo();
LeaveCrit();
break;
case PsW32ThreadCalloutDelete:
/*
* The object is going away for good, do the final cleanup
*/
fCritIn = ExIsResourceAcquiredExclusiveLite(gpresUser);
if (!fCritIn) {
EnterCrit();
}
DeleteThreadInfo ((PTHREADINFO)Thread);
if (!fCritIn) {
LeaveCrit();
}
break;
}
return Status;
}
/**************************************************************************\
* NtUserInitialize
*
* 01-Dec-1993 andreva created.
* 01-Dec-1995 BradG Modified to return handle to Media Change Event
\**************************************************************************/
NTSTATUS NtUserInitialize(
DWORD dwVersion,
FARPROC pfnDebugAttachRoutine)
{
/*
* Make sure we're not trying to load this twice.
*/
if (gpepCSRSS != NULL) {
RIPMSG0(RIP_ERROR, "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);
}
/*
* Save debug attach routine.
*/
gpfnDebugAttachRoutine = pfnDebugAttachRoutine;
/*
* Save the system process structure.
*/
gpepCSRSS = PsGetCurrentProcess();
/*
* Allow CSR to read the screen
*/
((PW32PROCESS)gpepCSRSS->Win32Process)->W32PF_Flags |= (W32PF_READSCREENACCESSGRANTED|W32PF_IOWINSTA);
/*
* Remember WIN32K.SYS's hmodule so we can grab resources from it later.
*/
hModuleWin = Win32KBaseAddress;
return UserInitialize();
}
/**************************************************************************\
* 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;
if (!pucConnect || (cbConnectInfo != sizeof(USERCONNECT))) {
return STATUS_UNSUCCESSFUL;
}
try {
ProbeForWrite(pucConnect, cbConnectInfo, sizeof(DWORD));
ucLocal = *pucConnect;
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
/*
* Check client/server versions.
*/
if ((ucLocal.ulVersion > USERCURRENTVERSION) ||
(ucLocal.ulVersion < USERCURRENTVERSION)) {
RIPMSG2(RIP_ERROR,
"Client version %lx > server version %lx\n",
ucLocal.ulVersion, USERCURRENTVERSION);
return STATUS_UNSUCCESSFUL;
} else {
ucLocal.ulCurrentVersion = USERCURRENTVERSION;
}
/*
* Reference the process.
*/
Status = ObReferenceObjectByHandle(hProcess,
PROCESS_VM_OPERATION,
NULL,
UserMode,
&Process,
NULL);
if (!NT_SUCCESS(Status))
return Status;
/*
* Return client's view of shared data.
*/
Status = InitMapSharedSection(Process, &ucLocal);
if (!NT_SUCCESS(Status) &&
(Status != STATUS_NO_MEMORY) &&
(Status != STATUS_PROCESS_IS_TERMINATING) &&
(Status != STATUS_QUOTA_EXCEEDED) &&
(Status != STATUS_COMMITMENT_LIMIT)) {
RIPMSG2(RIP_ERROR,
"Failed to map shared data into client %x, status = %x\n",
GetCurrentProcessId(), Status);
}
ObDereferenceObject(Process);
if (NT_SUCCESS(Status)) {
try {
*pucConnect = ucLocal;
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
}
return Status;
}
/**************************************************************************\
* UserProcessCallout
*
* 01-Dec-1993 andreva Created.
\**************************************************************************/
NTSTATUS UserProcessCallout(
IN PW32PROCESS Process,
IN BOOLEAN Initialize)
{
NTSTATUS Status = STATUS_SUCCESS;
if (Initialize) {
if (gpresUser)
EnterCrit();
/*
* Initialize the important process level stuff.
*/
if (!InitProcessInfo(Process)) {
Status = STATUS_NO_MEMORY;
}
if (gpresUser)
LeaveCrit();
} else {
int i;
PHE phe;
PDCE *ppdce;
PDCE pdce;
EnterCrit();
/*
* 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->flags & DCX_DESTROYTHIS)
DestroyCacheDC(ppdce, pdce->hdc);
/*
* Step to the next DC. If the DC was deleted, there
* is no need to calculate address of the next entry.
*/
if (pdce == *ppdce)
ppdce = &pdce->pdceNext;
}
}
LeaveCrit();
}
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)
{
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.
*
*
\**************************************************************************/
NTSTATUS _UserGetGlobalAtomTable(
PETHREAD Thread,
HWINSTA hwinsta,
PVOID *ppGlobalAtomTable);
NTSTATUS _UserSetGlobalAtomTable(
PETHREAD Thread,
HWINSTA hwinsta,
PVOID pGlobalAtomTable);
PVOID UserGlobalAtomTableCallout(VOID)
{
NTSTATUS Status;
PVOID GlobalAtomTable;
Status = _UserGetGlobalAtomTable(PsGetCurrentThread(),
NULL,
&GlobalAtomTable);
if (NT_SUCCESS(Status)) {
return GlobalAtomTable;
} else {
return NULL;
}
}