📄 window.c
字号:
// if (NULL != ParentWindowHandle)
// {
ParentWindow = UserGetWindowObject(ParentWindowHandle);
if (ParentWindow) UserRefObjectCo(ParentWindow, &ParentRef);
// }
// else
// {
// ParentWindow = NULL;
// }
/* FIXME: parent must belong to the current process */
/* Check the window station. */
ti = GetW32ThreadInfo();
if (ti == NULL || PsGetCurrentThreadWin32Thread()->Desktop == NULL)
{
DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
RETURN( (HWND)0);
}
/* Check the class. */
ClassAtom = IntGetClassAtom(ClassName,
hInstance,
ti->kpi,
&Class,
&ClassLink);
if (ClassAtom == (RTL_ATOM)0)
{
if (IS_ATOM(ClassName->Buffer))
{
DPRINT1("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
}
else
{
DPRINT1("Class \"%wZ\" not found\n", ClassName);
}
SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
RETURN((HWND)0);
}
Class = IntReferenceClass(Class,
ClassLink,
ti->Desktop);
if (Class == NULL)
{
DPRINT1("Failed to reference window class!\n");
RETURN(NULL);
}
WinSta = PsGetCurrentThreadWin32Thread()->Desktop->WindowStation;
//FIXME: Reference thread/desktop instead
ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
/* Create the window object. */
Window = (PWINDOW_OBJECT)
ObmCreateObject(gHandleTable, (PHANDLE)&hWnd,
otWindow, sizeof(WINDOW_OBJECT) + Class->WndExtra
);
DPRINT("Created object with handle %X\n", hWnd);
if (!Window)
{
ObDereferenceObject(WinSta);
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
RETURN( (HWND)0);
}
UserRefObjectCo(Window, &Ref);
ObDereferenceObject(WinSta);
if (NULL == PsGetCurrentThreadWin32Thread()->Desktop->DesktopWindow)
{
/* If there is no desktop window yet, we must be creating it */
PsGetCurrentThreadWin32Thread()->Desktop->DesktopWindow = hWnd;
}
/*
* Fill out the structure describing it.
*/
Window->ti = ti;
Window->Class = Class;
Class = NULL;
Window->SystemMenu = (HMENU)0;
Window->ContextHelpId = 0;
Window->IDMenu = 0;
Window->Instance = hInstance;
Window->hSelf = hWnd;
if (!hMenu)
hMenu = Window->Class->hMenu;
if (0 != (dwStyle & WS_CHILD))
{
Window->IDMenu = (UINT) hMenu;
}
else
{
IntSetMenu(Window, hMenu, &MenuChanged);
}
Window->MessageQueue = PsGetCurrentThreadWin32Thread()->MessageQueue;
IntReferenceMessageQueue(Window->MessageQueue);
Window->Parent = ParentWindow;
if((OwnerWindow = UserGetWindowObject(OwnerWindowHandle)))
{
Window->hOwner = OwnerWindowHandle;
HasOwner = TRUE;
}
else
{
Window->hOwner = NULL;
HasOwner = FALSE;
}
Window->UserData = 0;
Window->IsSystem = Window->Class->System;
if (Window->Class->System)
{
/* NOTE: Always create a unicode window for system classes! */
Window->Unicode = TRUE;
Window->WndProc = Window->Class->WndProc;
Window->WndProcExtra = Window->Class->WndProcExtra;
}
else
{
Window->Unicode = Window->Class->Unicode;
Window->WndProc = Window->Class->WndProc;
Window->CallProc = NULL;
}
Window->OwnerThread = PsGetCurrentThread();
Window->FirstChild = NULL;
Window->LastChild = NULL;
Window->PrevSibling = NULL;
Window->NextSibling = NULL;
Window->ExtraDataSize = Window->Class->WndExtra;
/* extra window data */
if (Window->Class->WndExtra)
Window->ExtraData = (PCHAR)(Window + 1);
InitializeListHead(&Window->PropListHead);
InitializeListHead(&Window->WndObjListHead);
if (NULL != WindowName->Buffer)
{
Window->WindowName.MaximumLength = WindowName->MaximumLength;
Window->WindowName.Length = WindowName->Length;
Window->WindowName.Buffer = ExAllocatePoolWithTag(PagedPool, WindowName->MaximumLength,
TAG_STRING);
if (NULL == Window->WindowName.Buffer)
{
DPRINT1("Failed to allocate mem for window name\n");
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
RETURN( NULL);
}
RtlCopyMemory(Window->WindowName.Buffer, WindowName->Buffer, WindowName->MaximumLength);
}
else
{
RtlInitUnicodeString(&Window->WindowName, NULL);
}
/*
* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
* tested for WS_POPUP
*/
if ((dwExStyle & WS_EX_DLGMODALFRAME) ||
((!(dwExStyle & WS_EX_STATICEDGE)) &&
(dwStyle & (WS_DLGFRAME | WS_THICKFRAME))))
dwExStyle |= WS_EX_WINDOWEDGE;
else
dwExStyle &= ~WS_EX_WINDOWEDGE;
/* Correct the window style. */
if (!(dwStyle & WS_CHILD))
{
dwStyle |= WS_CLIPSIBLINGS;
DPRINT("3: Style is now %lx\n", dwStyle);
if (!(dwStyle & WS_POPUP))
{
dwStyle |= WS_CAPTION;
Window->Flags |= WINDOWOBJECT_NEED_SIZE;
DPRINT("4: Style is now %lx\n", dwStyle);
}
}
/* create system menu */
if((dwStyle & WS_SYSMENU) &&
(dwStyle & WS_CAPTION) == WS_CAPTION)
{
SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
if(SystemMenu)
{
Window->SystemMenu = SystemMenu->MenuInfo.Self;
IntReleaseMenuObject(SystemMenu);
}
}
/* Insert the window into the thread's window list. */
InsertTailList (&PsGetCurrentThreadWin32Thread()->WindowListHead, &Window->ThreadListEntry);
/* Allocate a DCE for this window. */
if (dwStyle & CS_OWNDC)
{
Window->Dce = DceAllocDCE(Window, DCE_WINDOW_DC);
}
/* FIXME: Handle "CS_CLASSDC" */
Pos.x = x;
Pos.y = y;
Size.cx = nWidth;
Size.cy = nHeight;
Window->ExStyle = dwExStyle;
Window->Style = dwStyle & ~WS_VISIBLE;
/* call hook */
Cs.lpCreateParams = lpParam;
Cs.hInstance = hInstance;
Cs.hMenu = hMenu;
Cs.hwndParent = hWndParent; //Pass the original Parent handle!
Cs.cx = Size.cx;
Cs.cy = Size.cy;
Cs.x = Pos.x;
Cs.y = Pos.y;
Cs.style = Window->Style;
Cs.lpszName = (LPCWSTR) WindowName;
Cs.lpszClass = (LPCWSTR) ClassName;
Cs.dwExStyle = dwExStyle;
CbtCreate.lpcs = &Cs;
CbtCreate.hwndInsertAfter = HWND_TOP;
if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
{
/* FIXME - Delete window object and remove it from the thread windows list */
/* FIXME - delete allocated DCE */
DPRINT1("CBT-hook returned !0\n");
RETURN( (HWND) NULL);
}
x = Cs.x;
y = Cs.y;
nWidth = Cs.cx;
nHeight = Cs.cy;
/* default positioning for overlapped windows */
if(!(Window->Style & (WS_POPUP | WS_CHILD)))
{
RECT rc, WorkArea;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
BOOL CalculatedDefPosSize = FALSE;
IntGetDesktopWorkArea(((PW32THREAD)Window->OwnerThread->Tcb.Win32Thread)->Desktop, &WorkArea);
rc = WorkArea;
ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, Window, &rc, TRUE);
if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
{
ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
Pos.x = WorkArea.left + ProcessParams->StartingX;
Pos.y = WorkArea.top + ProcessParams->StartingY;
}
else
{
Pos.x = rc.left;
Pos.y = rc.top;
}
/*
According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
y is something else. and Quote!
*/
/* Never believe Microsoft's documentation... CreateWindowEx doc says
* that if an overlapped window is created with WS_VISIBLE style bit
* set and the x parameter is set to CW_USEDEFAULT, the system ignores
* the y parameter. However, disassembling NT implementation (WIN32K.SYS)
* reveals that
*
* 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
* 2) it does not ignore the y parameter as the docs claim; instead, it
* uses it as second parameter to ShowWindow() unless y is either
* CW_USEDEFAULT or CW_USEDEFAULT16.
*
* The fact that we didn't do 2) caused bogus windows pop up when wine
* was running apps that were using this obscure feature. Example -
* calc.exe that comes with Win98 (only Win98, it's different from
* the one that comes with Win95 and NT)
*/
if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
{
dwShowMode = y;
}
}
if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
{
if(!CalculatedDefPosSize)
{
IntCalcDefPosSize(ParentWindow, Window, &rc, FALSE);
}
if(ProcessParams->WindowFlags & STARTF_USESIZE)
{
ProcessParams->WindowFlags &= ~STARTF_USESIZE;
Size.cx = ProcessParams->CountX;
Size.cy = ProcessParams->CountY;
}
else
{
Size.cx = rc.right - rc.left;
Size.cy = rc.bottom - rc.top;
}
/* move the window if necessary */
if(Pos.x > rc.left)
Pos.x = max(rc.left, 0);
if(Pos.y > rc.top)
Pos.y = max(rc.top, 0);
}
}
else
{
/* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
Pos.x = 0;
Pos.y = 0;
}
if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
{
Size.cx = 0;
Size.cy = 0;
}
}
/* Initialize the window dimensions. */
Window->WindowRect.left = Pos.x;
Window->WindowRect.top = Pos.y;
Window->WindowRect.right = Pos.x + Size.cx;
Window->WindowRect.bottom = Pos.y + Size.cy;
if (0 != (Window->Style & WS_CHILD) && ParentWindow)
{
IntGdiOffsetRect(&(Window->WindowRect), ParentWindow->ClientRect.left,
ParentWindow->ClientRect.top);
}
Window->ClientRect = Window->WindowRect;
/*
* Get the size and position of the window.
*/
if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
{
POINT MaxSize, MaxPos, MinTrack, MaxTrack;
/* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
&MaxTrack);
if (MaxSize.x < Size.cx)
Size.cx = MaxSize.x;
if (MaxSize.y < Size.cy)
Size.cy = MaxSize.y;
if (Size.cx < MinTrack.x )
Size.cx = MinTrack.x;
if (Size.cy < MinTrack.y )
Size.cy = MinTrack.y;
if (Size.cx < 0)
Size.cx = 0;
if (Size.cy < 0)
Size.cy = 0;
}
Window->WindowRect.left = Pos.x;
Window->WindowRect.top = Pos.y;
Window->WindowRect.right = Pos.x + Size.cx;
Window->WindowRect.bottom = Pos.y + Size.cy;
if (0 != (Window->Style & WS_CHILD) && ParentWindow)
{
IntGdiOffsetRect(&(Window->WindowRect), ParentWindow->ClientRect.left,
ParentWindow->ClientRect.top);
}
Window->ClientRect = Window->WindowRect;
/* FIXME: Initialize the window menu. */
/* Send a NCCREATE message. */
Cs.cx = Size.cx;
Cs.cy = Size.cy;
Cs.x = Pos.x;
Cs.y = Pos.y;
DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
if (!Result)
{
/* FIXME: Cleanup. */
DPRINT("IntCreateWindowEx(): NCCREATE message failed.\n");
RETURN((HWND)0);
}
/* Calculate the non-client size. */
MaxPos.x = Window->WindowRect.left;
MaxPos.y = Window->WindowRect.top;
DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
/* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
Result = co_WinPosGetNonClientSize(Window,
&Window->WindowRect,
&Window->ClientRect);
IntGdiOffsetRect(&Window->WindowRect,
MaxPos.x - Window->WindowRect.left,
MaxPos.y - Window->WindowRect.top);
if (NULL != ParentWindow)
{
/* link the window into the parent's child list */
if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
{
PWINDOW_OBJECT PrevSibling;
PrevSibling = ParentWindow->LastChild;
/* link window as bottom sibling */
IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
}
else
{
/* link window as top sibling (but after topmost siblings) */
PWINDOW_OBJECT InsertAfter, Sibling;
if (!(dwExStyle & WS_EX_TOPMOST))
{
InsertAfter = NULL;
Sibling = ParentWindow->FirstChild;
while (Sibling && (Sibling->ExStyle & WS_EX_TOPMOST))
{
InsertAfter = Sibling;
Sibling = Sibling->NextSibling;
}
}
else
{
InsertAfter = NULL;
}
IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
}
}
/* Send the WM_CREATE message. */
DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
if (Result == (LRESULT)-1)
{
/* FIXME: Cleanup. */
DPRINT("IntCreateWindowEx(): send CREATE message failed.\n");
RETURN((HWND)0);
}
/* Send move and size messages. */
if (!(Window->Flags & WINDOWOBJECT_NEED_SIZE))
{
LONG lParam;
DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
if ((Window->ClientRect.right - Window->ClientRect.left) < 0 ||
(Window->ClientRect.bottom - Window->ClientRect.top) < 0)
{
DPRINT("Sending bogus WM_SIZE\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -