reactos操作系统实现(162)_co_intcreatewindowex-程序员宅基地

技术标签: reference  REACTOS  null  testing  thread  class  object  

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  

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/caimouse/article/details/5028150

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签