reactos操作系统实现(162)
co_IntCreateWindowEx函数主要用创建一个显示的窗口,具体实现代码如下:
#001 HWND APIENTRY
#002 co_IntCreateWindowEx(DWORD dwExStyle,
#003 PUNICODE_STRING ClassName,
#004 PUNICODE_STRING WindowName,
#005 DWORD dwStyle,
#006 LONG x,
#007 LONG y,
#008 LONG nWidth,
#009 LONG nHeight,
#010 HWND hWndParent,
#011 HMENU hMenu,
#012 HINSTANCE hInstance,
#013 LPVOID lpParam,
#014 DWORD dwShowMode,
#015 BOOL bUnicodeWindow)
#016 {
#017 PWINSTATION_OBJECT WinSta;
#018 PWINDOW Wnd = NULL;
#019 PWINDOWCLASS *ClassLink, Class = NULL;
#020 RTL_ATOM ClassAtom;
#021 PWINDOW_OBJECT Window = NULL;
#022 PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
#023 HWND ParentWindowHandle;
#024 HWND OwnerWindowHandle;
#025 PMENU_OBJECT SystemMenu;
#026 HWND hWnd;
#027 POINT Pos;
#028 SIZE Size;
#029 PW32THREADINFO ti = NULL;
#030 #if 0
#031
#032 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
#033 #else
#034
#035 POINT MaxPos;
#036 #endif
#037 CREATESTRUCTW Cs;
#038 CBT_CREATEWNDW CbtCreate;
#039 LRESULT Result;
#040 BOOL MenuChanged;
#041 DECLARE_RETURN(HWND);
#042 BOOL HasOwner;
#043 USER_REFERENCE_ENTRY ParentRef, Ref;
#044 PTHREADINFO pti;
#045
获取当前运行的线程。
#046 pti = PsGetCurrentThreadWin32Thread();
获取桌面窗口作为父窗口。
#047 ParentWindowHandle = pti->Desktop->DesktopWindow;
#048 OwnerWindowHandle = NULL;
#049
是否为创建消息窗口。
#050 if (hWndParent == HWND_MESSAGE)
#051 {
#052 /*
#053 * native ole32.OleInitialize uses HWND_MESSAGE to create the
#054 * message window (style: WS_POPUP|WS_DISABLED)
#055 */
#056 DPRINT1("FIXME - Parent is HWND_MESSAGE/n");
#057 // ParentWindowHandle set already.
#058 }
是否已经父窗口。
#059 else if (hWndParent)
#060 {
#061 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
#062 { //temp hack
#063 PWINDOW_OBJECT Par = UserGetWindowObject(hWndParent), Root;
#064 if (Par && (Root = UserGetAncestor(Par, GA_ROOT)))
#065 OwnerWindowHandle = Root->hSelf;
#066 }
#067 else
#068 ParentWindowHandle = hWndParent;
#069 }
如果又设置为子窗口属性,但又没有父窗口,就提示出错返回。
#070 else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
#071 {
#072 SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
#073 RETURN( (HWND)0); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
#074 }
#075
获取父窗口对象。
#076 // if (NULL != ParentWindowHandle)
#077 // {
#078 ParentWindow = UserGetWindowObject(ParentWindowHandle);
#079
#080 if (ParentWindow) UserRefObjectCo(ParentWindow, &ParentRef);
#081 // }
#082 // else
#083 // {
#084 // ParentWindow = NULL;
#085 // }
#086
#087 /* FIXME: parent must belong to the current process */
#088
检查WINDOWS的线程信息。
#089 /* Check the window station. */
#090 ti = GetW32ThreadInfo();
#091 if (ti == NULL || pti->Desktop == NULL)
#092 {
#093 DPRINT1("Thread is not attached to a desktop! Cannot create window!/n");
#094 RETURN( (HWND)0);
#095 }
#096
#097 /* Check the class. */
#098
检查要创建的窗口类是否已经注册好。
#099 ClassAtom = IntGetClassAtom(ClassName,
#100 hInstance,
#101 ti->kpi,
#102 &Class,
#103 &ClassLink);
#104
#105 if (ClassAtom == (RTL_ATOM)0)
#106 {
#107 if (IS_ATOM(ClassName->Buffer))
#108 {
#109 DPRINT1("Class 0x%p not found/n", (DWORD_PTR) ClassName->Buffer);
#110 }
#111 else
#112 {
#113 DPRINT1("Class /"%wZ/" not found/n", ClassName);
#114 }
#115
#116 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
#117 RETURN((HWND)0);
#118 }
#119
增加已经注册好的窗口类引用计数。
#120 Class = IntReferenceClass(Class,
#121 ClassLink,
#122 pti->Desktop);
#123 if (Class == NULL)
#124 {
#125 DPRINT1("Failed to reference window class!/n");
#126 RETURN(NULL);
#127 }
#128
获取桌面工作站。
#129 WinSta = pti->Desktop->WindowStation;
#130
#131 //FIXME: Reference thread/desktop instead
#132 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
#133
调用函数UserCreateObject创建窗口对象。
#134 /* Create the window object. */
#135 Window = (PWINDOW_OBJECT)
#136 UserCreateObject(gHandleTable, (PHANDLE)&hWnd,
#137 otWindow, sizeof(WINDOW_OBJECT));
#138 if (Window)
#139 {
分配窗口所占用的堆空间。
#140 Window->Wnd = DesktopHeapAlloc(pti->Desktop,
#141 sizeof(WINDOW) + Class->WndExtra);
#142 if (!Window->Wnd)
#143 goto AllocErr;
#144 RtlZeroMemory(Window->Wnd,
#145 sizeof(WINDOW) + Class->WndExtra);
#146 Window->Wnd->hdr.Handle = hWnd; /* FIXME: Remove hack */
#147 Wnd = Window->Wnd;
#148
#149 Wnd->ti = ti;
#150 Wnd->pi = ti->kpi;
#151 Wnd->pdesktop = pti->Desktop;
#152 Wnd->hWndLastActive = hWnd;
#153 }
#154
检查是否创建窗口对象成功。
#155 DPRINT("Created object with handle %X/n", hWnd);
#156 if (!Window)
#157 {
#158 AllocErr:
#159 ObDereferenceObject(WinSta);
#160 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
#161 RETURN( (HWND)0);
#162 }
#163
增加引用窗口计数。
#164 UserRefObjectCo(Window, &Ref);
#165
#166 ObDereferenceObject(WinSta);
#167
如果还没有桌面窗口,说明当前创建的窗口就是桌面窗口。
#168 if (NULL == pti->Desktop->DesktopWindow)
#169 {
#170 /* If there is no desktop window yet, we must be creating it */
#171 pti->Desktop->DesktopWindow = hWnd;
#172 pti->Desktop->DesktopInfo->Wnd = Wnd;
#173 }
#174
填写窗口描述结构。
#175 /*
#176 * Fill out the structure describing it.
#177 */
#178 Window->ti = ti;
#179 Wnd->Class = Class;
#180 Class = NULL;
#181
#182 Window->SystemMenu = (HMENU)0;
#183 Wnd->ContextHelpId = 0;
#184 Wnd->IDMenu = 0;
#185 Wnd->Instance = hInstance;
#186 Window->hSelf = hWnd;
#187
设置窗口消息队列。
#188 Window->MessageQueue = pti->MessageQueue;
#189 IntReferenceMessageQueue(Window->MessageQueue);
#190 Window->Parent = ParentWindow;
#191 Wnd->Parent = ParentWindow ? ParentWindow->Wnd : NULL;
#192 if (Wnd->Parent != NULL && hWndParent != 0)
#193 {
#194 Wnd->HideFocus = Wnd->Parent->HideFocus;
#195 Wnd->HideAccel = Wnd->Parent->HideAccel;
#196 }
#197
设置属于那一个窗口。
#198 if((OwnerWindow = UserGetWindowObject(OwnerWindowHandle)))
#199 {
#200 Window->hOwner = OwnerWindowHandle;
#201 Wnd->Owner = OwnerWindow->Wnd;
#202 HasOwner = TRUE;
#203 }
#204 else
#205 {
#206 Window->hOwner = NULL;
#207 Wnd->Owner = NULL;
#208 HasOwner = FALSE;
#209 }
#210
窗口用户数据设置为0.
#211 Wnd->UserData = 0;
#212
#213 Wnd->IsSystem = Wnd->Class->System;
#214
#215 /* BugBoy Comments: Comment below say that System classes are always created as UNICODE.
#216 In windows, creating a window with the ANSI version of CreateWindow sets the window
#217 to ansi as verified by testing with IsUnicodeWindow API.
#218
#219 No where can I see in code or through testing does the window change back to ANSI
#220 after being created as UNICODE in ROS. I didnt do more testing to see what problems this would cause.*/
#221 // See NtUserDefSetText! We convert to Unicode all the time and never use Mix. (jt)
根据是否系统里定义的窗口类来选择是否使用UNICODE的窗口。
#222 if (Wnd->Class->System)
#223 {
#224 /* NOTE: Always create a unicode window for system classes! */
#225 Wnd->Unicode = TRUE;
#226 Wnd->WndProc = Wnd->Class->WndProc;
#227 Wnd->WndProcExtra = Wnd->Class->WndProcExtra;
#228 }
#229 else
#230 {
#231 Wnd->Unicode = Wnd->Class->Unicode;
#232 Wnd->WndProc = Wnd->Class->WndProc;
#233 Wnd->CallProc = NULL;
#234 }
#235
设置当前窗口的线程。
#236 Window->OwnerThread = PsGetCurrentThread();
#237 Window->FirstChild = NULL;
#238 Window->LastChild = NULL;
#239 Window->PrevSibling = NULL;
#240 Window->NextSibling = NULL;
#241 Wnd->ExtraDataSize = Wnd->Class->WndExtra;
#242
#243 InitializeListHead(&Wnd->PropListHead);
#244 InitializeListHead(&Window->WndObjListHead);
#245
设置窗口的名称。
#246 if (NULL != WindowName->Buffer && WindowName->Length > 0)
#247 {
#248 Wnd->WindowName.Buffer = DesktopHeapAlloc(Wnd->pdesktop,
#249 WindowName->Length + sizeof(UNICODE_NULL));
#250 if (Wnd->WindowName.Buffer == NULL)
#251 {
#252 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
#253 RETURN( (HWND)0);
#254 }
#255
#256 Wnd->WindowName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'/0';
#257 _SEH2_TRY
#258 {
#259 RtlCopyMemory(Wnd->WindowName.Buffer,
#260 WindowName->Buffer,
#261 WindowName->Length);
#262 Wnd->WindowName.Length = WindowName->Length;
#263 }
#264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
#265 {
#266 WindowName->Length = 0;
#267 Wnd->WindowName.Buffer[0] = L'/0';
#268 }
#269 _SEH2_END;
#270 }
#271
检查是否创建对话框窗口。
#272 /*
#273 * This has been tested for WS_CHILD | WS_VISIBLE. It has not been
#274 * tested for WS_POPUP
#275 */
#276 if ((dwExStyle & WS_EX_DLGMODALFRAME) ||
#277 ((!(dwExStyle & WS_EX_STATICEDGE)) &&
#278 (dwStyle & (WS_DLGFRAME | WS_THICKFRAME))))
#279 dwExStyle |= WS_EX_WINDOWEDGE;
#280 else
#281 dwExStyle &= ~WS_EX_WINDOWEDGE;
#282
检查不是子窗口的属性是否对。
#283 /* Correct the window style. */
#284 if (!(dwStyle & WS_CHILD))
#285 {
#286 dwStyle |= WS_CLIPSIBLINGS;
#287 DPRINT("3: Style is now %lx/n", dwStyle);
#288 if (!(dwStyle & WS_POPUP))
#289 {
#290 dwStyle |= WS_CAPTION;
#291 Window->Flags |= WINDOWOBJECT_NEED_SIZE;
#292 DPRINT("4: Style is now %lx/n", dwStyle);
#293 }
#294 }
#295
创建窗口系统菜单。
#296 /* create system menu */
#297 if((dwStyle & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
#298 {
#299 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
#300 if(SystemMenu)
#301 {
#302 Window->SystemMenu = SystemMenu->MenuInfo.Self;
#303 IntReleaseMenuObject(SystemMenu);
#304 }
#305 }
#306
设置窗口菜单。
#307 /* Set the window menu */
#308 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
#309 {
#310 if (hMenu)
#311 IntSetMenu(Window, hMenu, &MenuChanged);
#312 else
#313 {
#314 hMenu = Wnd->Class->hMenu;
#315 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
#316 }
#317 }
#318 else
#319 Wnd->IDMenu = (UINT) hMenu;
#320
把窗口添加到线程队列里。
#321 /* Insert the window into the thread's window list. */
#322 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
#323
为窗口分配设备DC,可以分配窗口类的DC,也可以是窗口的DC。这里调用驱动程序来创建一个设备。
#324 /* Handle "CS_CLASSDC", it is tested first. */
#325 if ((Wnd->Class->Style & CS_CLASSDC) && !(Wnd->Class->Dce)) // One DCE per class to have CLASS.
#326 Wnd->Class->Dce = DceAllocDCE(Window, DCE_CLASS_DC);
#327 /* Allocate a DCE for this window. */
#328 else if ( Wnd->Class->Style & CS_OWNDC)
#329 Window->Dce = DceAllocDCE(Window, DCE_WINDOW_DC);
#330
设置窗口的位置和大小。
#331 Pos.x = x;
#332 Pos.y = y;
#333 Size.cx = nWidth;
#334 Size.cy = nHeight;
#335
#336 Wnd->ExStyle = dwExStyle;
#337 Wnd->Style = dwStyle & ~WS_VISIBLE;
#338
设置窗口HOOK。
#339 /* call hook */
#340 Cs.lpCreateParams = lpParam;
#341 Cs.hInstance = hInstance;
#342 Cs.hMenu = hMenu;
#343 Cs.hwndParent = hWndParent; //Pass the original Parent handle!
#344 Cs.cx = Size.cx;
#345 Cs.cy = Size.cy;
#346 Cs.x = Pos.x;
#347 Cs.y = Pos.y;
#348 Cs.style = Wnd->Style;
#349 Cs.lpszName = (LPCWSTR) WindowName;
#350 Cs.lpszClass = (LPCWSTR) ClassName;
#351 Cs.dwExStyle = dwExStyle;
#352 CbtCreate.lpcs = &Cs;
#353 CbtCreate.hwndInsertAfter = HWND_TOP;
#354 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
#355 {
#356 /* FIXME - Delete window object and remove it from the thread windows list */
#357 /* FIXME - delete allocated DCE */
#358 DPRINT1("CBT-hook returned !0/n");
#359 RETURN( (HWND) NULL);
#360 }
#361
#362 x = Cs.x;
#363 y = Cs.y;
#364 nWidth = Cs.cx;
#365 nHeight = Cs.cy;
#366
计算重叠窗口位置和大小。
#367 /* default positioning for overlapped windows */
#368 if(!(Wnd->Style & (WS_POPUP | WS_CHILD)))
#369 {
#370 RECT rc, WorkArea;
#371 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
#372 BOOL CalculatedDefPosSize = FALSE;
#373
#374 IntGetDesktopWorkArea(((PTHREADINFO)Window->OwnerThread->Tcb.Win32Thread)->Desktop, &WorkArea);
#375
#376 rc = WorkArea;
#377 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
#378
#379 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
#380 {
#381 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, Window, &rc, TRUE);
#382
#383 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
#384 {
#385 ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
#386 Pos.x = WorkArea.left + ProcessParams->StartingX;
#387 Pos.y = WorkArea.top + ProcessParams->StartingY;
#388 }
#389 else
#390 {
#391 Pos.x = rc.left;
#392 Pos.y = rc.top;
#393 }
#394
#395 /*
#396 According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
#397 y is something else. and Quote!
#398 */
#399
#400 /* Never believe Microsoft's documentation... CreateWindowEx doc says
#401 * that if an overlapped window is created with WS_VISIBLE style bit
#402 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
#403 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
#404 * reveals that
#405 *
#406 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
#407 * 2) it does not ignore the y parameter as the docs claim; instead, it
#408 * uses it as second parameter to ShowWindow() unless y is either
#409 * CW_USEDEFAULT or CW_USEDEFAULT16.
#410 *
#411 * The fact that we didn't do 2) caused bogus windows pop up when wine
#412 * was running apps that were using this obscure feature. Example -
#413 * calc.exe that comes with Win98 (only Win98, it's different from
#414 * the one that comes with Win95 and NT)
#415 */
#416 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
#417 {
#418 dwShowMode = y;
#419 }
#420 }
#421 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
#422 {
#423 if(!CalculatedDefPosSize)
#424 {
#425 IntCalcDefPosSize(ParentWindow, Window, &rc, FALSE);
#426 }
#427 if(ProcessParams->WindowFlags & STARTF_USESIZE)
#428 {
#429 ProcessParams->WindowFlags &= ~STARTF_USESIZE;
#430 Size.cx = ProcessParams->CountX;
#431 Size.cy = ProcessParams->CountY;
#432 }
#433 else
#434 {
#435 Size.cx = rc.right - rc.left;
#436 Size.cy = rc.bottom - rc.top;
#437 }
#438
#439 /* move the window if necessary */
#440 if(Pos.x > rc.left)
#441 Pos.x = max(rc.left, 0);
#442 if(Pos.y > rc.top)
#443 Pos.y = max(rc.top, 0);
#444 }
#445 }
#446 else
#447 {
#448 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
#449 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
#450 {
#451 Pos.x = 0;
#452 Pos.y = 0;
#453 }
#454 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
#455 {
#456 Size.cx = 0;
#457 Size.cy = 0;
#458 }
#459 }
#460
初始化窗口显示的大小。
#461 /* Initialize the window dimensions. */
#462 Wnd->WindowRect.left = Pos.x;
#463 Wnd->WindowRect.top = Pos.y;
#464 Wnd->WindowRect.right = Pos.x + Size.cx;
#465 Wnd->WindowRect.bottom = Pos.y + Size.cy;
#466 if (0 != (Wnd->Style & WS_CHILD) && ParentWindow)
#467 {
#468 IntGdiOffsetRect(&(Wnd->WindowRect), ParentWindow->Wnd->ClientRect.left,
#469 ParentWindow->Wnd->ClientRect.top);
#470 }
#471 Wnd->ClientRect = Wnd->WindowRect;
#472
#473 /*
#474 * Get the size and position of the window.
#475 */
#476 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
#477 {
#478 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
#479
#480 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
#481 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
#482 &MaxTrack);
#483 if (MaxSize.x < Size.cx)
#484 Size.cx = MaxSize.x;
#485 if (MaxSize.y < Size.cy)
#486 Size.cy = MaxSize.y;
#487 if (Size.cx < MinTrack.x )
#488 Size.cx = MinTrack.x;
#489 if (Size.cy < MinTrack.y )
#490 Size.cy = MinTrack.y;
#491 if (Size.cx < 0)
#492 Size.cx = 0;
#493 if (Size.cy < 0)
#494 Size.cy = 0;
#495 }
#496
#497 Wnd->WindowRect.left = Pos.x;
#498 Wnd->WindowRect.top = Pos.y;
#499 Wnd->WindowRect.right = Pos.x + Size.cx;
#500 Wnd->WindowRect.bottom = Pos.y + Size.cy;
#501 if (0 != (Wnd->Style & WS_CHILD) && ParentWindow)
#502 {
#503 IntGdiOffsetRect(&(Wnd->WindowRect), ParentWindow->Wnd->ClientRect.left,
#504 ParentWindow->Wnd->ClientRect.top);
#505 }
窗口客户区的大小。
#506 Wnd->ClientRect = Wnd->WindowRect;
#507
#508 /* FIXME: Initialize the window menu. */
#509
#510 /* Send a NCCREATE message. */
#511 Cs.cx = Size.cx;
#512 Cs.cy = Size.cy;
#513 Cs.x = Pos.x;
#514 Cs.y = Pos.y;
#515
#516 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d/n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
#517 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)/n", x, y, Size.cx, Size.cy);
#518 DPRINT("IntCreateWindowEx(): About to send NCCREATE message./n");
发送创建窗口的WM_NCCREATE消息。
#519 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
#520 if (!Result)
#521 {
#522 /* FIXME: Cleanup. */
#523 DPRINT1("IntCreateWindowEx(): NCCREATE message failed. No cleanup performed!/n");
#524 RETURN((HWND)0);
#525 }
#526
计算非窗户客户端的大小。
#527 /* Calculate the non-client size. */
#528 MaxPos.x = Window->Wnd->WindowRect.left;
#529 MaxPos.y = Window->Wnd->WindowRect.top;
#530
#531
#532 DPRINT("IntCreateWindowEx(): About to get non-client size./n");
#533 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
#534 Result = co_WinPosGetNonClientSize(Window,
#535 &Window->Wnd->WindowRect,
#536 &Window->Wnd->ClientRect);
#537
#538 IntGdiOffsetRect(&Window->Wnd->WindowRect,
#539 MaxPos.x - Window->Wnd->WindowRect.left,
#540 MaxPos.y - Window->Wnd->WindowRect.top);
#541
#542
如果父窗口不为空,说明本窗口是子窗口。
#543 if (NULL != ParentWindow)
#544 {
把本窗口连接到父窗口列表里。
#545 /* link the window into the parent's child list */
#546 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
#547 {
#548 PWINDOW_OBJECT PrevSibling;
#549
#550 PrevSibling = ParentWindow->LastChild;
#551
#552 /* link window as bottom sibling */
#553 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
#554 }
#555 else
#556 {
#557 /* link window as top sibling (but after topmost siblings) */
#558 PWINDOW_OBJECT InsertAfter, Sibling;
#559 if (!(dwExStyle & WS_EX_TOPMOST))
#560 {
#561 InsertAfter = NULL;
#562 Sibling = ParentWindow->FirstChild;
#563 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
#564 {
#565 InsertAfter = Sibling;
#566 Sibling = Sibling->NextSibling;
#567 }
#568 }
#569 else
#570 {
#571 InsertAfter = NULL;
#572 }
#573
#574 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
#575
#576 }
#577 }
#578
发送创建窗口的WM_CREATE消息。
#579 /* Send the WM_CREATE message. */
#580 DPRINT("IntCreateWindowEx(): about to send CREATE message./n");
#581 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
#582
#583 if (Result == (LRESULT)-1)
#584 {
#585 /* FIXME: Cleanup. */
#586 DPRINT1("IntCreateWindowEx(): send CREATE message failed. No cleanup performed!/n");
#587 IntUnlinkWindow(Window);
#588 RETURN((HWND)0);
#589 }
#590 #if 0
#591 Result = IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, 0);
#592
#593 if (Result == (LRESULT)-1)
#594 {
#595 /* FIXME: Cleanup. */
#596 DPRINT1("IntCreateWindowEx(): event CREATE hook failed. No cleanup performed!/n");
#597 IntUnlinkWindow(Window);
#598 RETURN((HWND)0);
#599 }
#600 #endif
发送窗口设置大小的WM_SIZE消息。
#601 /* Send move and size messages. */
#602 if (!(Window->Flags & WINDOWOBJECT_NEED_SIZE))
#603 {
#604 LONG lParam;
#605
#606 DPRINT("IntCreateWindow(): About to send WM_SIZE/n");
#607
#608 if ((Window->Wnd->ClientRect.right - Window->Wnd->ClientRect.left) < 0 ||
#609 (Window->Wnd->ClientRect.bottom - Window->Wnd->ClientRect.top) < 0)
#610 {
#611 DPRINT("Sending bogus WM_SIZE/n");
#612 }
#613
#614 lParam = MAKE_LONG(Window->Wnd->ClientRect.right -
#615 Window->Wnd->ClientRect.left,
#616 Window->Wnd->ClientRect.bottom -
#617 Window->Wnd->ClientRect.top);
#618 co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
#619 lParam);
#620
#621 DPRINT("IntCreateWindow(): About to send WM_MOVE/n");
#622
发送窗口移动到某位置的WM_MOVE消息。
#623 if (0 != (Wnd->Style & WS_CHILD) && ParentWindow)
#624 {
#625 lParam = MAKE_LONG(Wnd->ClientRect.left - ParentWindow->Wnd->ClientRect.left,
#626 Wnd->ClientRect.top - ParentWindow->Wnd->ClientRect.top);
#627 }
#628 else
#629 {
#630 lParam = MAKE_LONG(Wnd->ClientRect.left,
#631 Wnd->ClientRect.top);
#632 }
#633
#634 co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
#635
#636 /* Call WNDOBJ change procs */
#637 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
#638 }
#639
设置窗口最大化或最小化显示。
#640 /* Show or maybe minimize or maximize the window. */
#641 if (Wnd->Style & (WS_MINIMIZE | WS_MAXIMIZE))
#642 {
#643 RECT NewPos;
#644 UINT16 SwFlag;
#645
#646 SwFlag = (Wnd->Style & WS_MINIMIZE) ? SW_MINIMIZE :
#647 SW_MAXIMIZE;
#648
#649 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
#650
#651 SwFlag = ((Wnd->Style & WS_CHILD) || UserGetActiveWindow()) ?
#652 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
#653 SWP_NOZORDER | SWP_FRAMECHANGED;
#654
#655 DPRINT("IntCreateWindow(): About to minimize/maximize/n");
#656 DPRINT("%d,%d %dx%d/n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
#657 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
#658 NewPos.right, NewPos.bottom, SwFlag);
#659 }
#660
如果是创建子窗口,通知父窗口已经创建了一个子窗口。
#661 /* Notify the parent window of a new child. */
#662 if ((Wnd->Style & WS_CHILD) &&
#663 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
#664 {
#665 DPRINT("IntCreateWindow(): About to notify parent/n");
#666 co_IntSendMessage(ParentWindow->hSelf,
#667 WM_PARENTNOTIFY,
#668 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
#669 (LPARAM)Window->hSelf);
#670 }
#671
#672 if ((!hWndParent) && (!HasOwner))
#673 {
#674 DPRINT("Sending CREATED notify/n");
#675 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
#676 }
#677 else
#678 {
#679 DPRINT("Not sending CREATED notify, %x %d/n", ParentWindow, HasOwner);
#680 }
#681
设置窗口的滚动条。
#682 /* Initialize and show the window's scrollbars */
#683 if (Wnd->Style & WS_VSCROLL)
#684 {
#685 co_UserShowScrollBar(Window, SB_VERT, TRUE);
#686 }
#687 if (Wnd->Style & WS_HSCROLL)
#688 {
#689 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
#690 }
#691
设置窗口显示方式。
#692 if (dwStyle & WS_VISIBLE)
#693 {
#694 if (Wnd->Style & WS_MAXIMIZE)
#695 dwShowMode = SW_SHOW;
#696 else if (Wnd->Style & WS_MINIMIZE)
#697 dwShowMode = SW_SHOWMINIMIZED;
#698
#699 DPRINT("IntCreateWindow(): About to show window/n");
#700 co_WinPosShowWindow(Window, dwShowMode);
#701
#702 if (Wnd->ExStyle & WS_EX_MDICHILD)
#703 {
#704 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
#705 /* ShowWindow won't activate child windows */
#706 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
#707 }
#708 }
#709
#710 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xC007,
#711 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
#712 Dont understand why it does this. */
#713 if (ClassAtom == 0XC007)
#714 {
#715 PCALLPROC CallProc;
#716 //CallProc = CreateCallProc(NULL, Wnd->WndProc, bUnicodeWindow, Wnd->ti->kpi);
#717 CallProc = CreateCallProc(NULL, Wnd->WndProc, Wnd->Unicode , Wnd->ti->kpi);
#718
#719 if (!CallProc)
#720 {
#721 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
#722 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x/n",hWnd);
#723 }
#724 else
#725 {
#726 UserAddCallProcToClass(Wnd->Class, CallProc);
#727 Wnd->CallProc = CallProc;
#728 Wnd->IsSystem = FALSE;
#729 }
#730 }
#731
返回创建窗口的句柄。
#732 DPRINT("IntCreateWindow(): = %X/n", hWnd);
#733 DPRINT("WindowObject->SystemMenu = 0x%x/n", Window->SystemMenu);
#734 RETURN(hWnd);
#735
下面是清除失败时分配的资源。
#736 CLEANUP:
#737 if (!_ret_ && Window && Window->Wnd && ti)
#738 UserFreeWindowInfo(ti, Window);
#739 if (Window)
#740 {
#741 UserDerefObjectCo(Window);
#742 UserDereferenceObject(Window);
#743 }
#744 if (ParentWindow) UserDerefObjectCo(ParentWindow);
#745 if (!_ret_ && ti != NULL)
#746 {
#747 if (Class != NULL)
#748 {
#749 IntDereferenceClass(Class,
#750 ti->Desktop,
#751 ti->kpi);
#752 }
#753 }
#754 END_CLEANUP;
#755 }
#756