zl程序教程

您现在的位置是:首页 >  系统

当前栏目

reactos操作系统实现(160)

操作系统 实现 160 reactos
2023-09-14 09:10:39 时间

CreateWindowExW函数主要用来根据已经注册窗口类来创建一个窗口。它在User32.dll实现代码如下:

#001  HWND WINAPI

#002  CreateWindowExW(DWORD dwExStyle,

#003                  LPCWSTR lpClassName,

#004                  LPCWSTR lpWindowName,

#005                  DWORD dwStyle,

#006                  int x,

#007                  int y,

#008                  int nWidth,

#009                  int nHeight,

#010                  HWND hWndParent,

#011                  HMENU hMenu,

#012                  HINSTANCE hInstance,

#013                  LPVOID lpParam)

#014  {

#015      MDICREATESTRUCTW mdi;

#016      HWND hwnd;

#017 

 

如果创建的窗口是MDI的子窗口,就需要进入下面处理。

#018      if (dwExStyle & WS_EX_MDICHILD)

#019      {

#020          POINT mPos[2];

#021          UINT id = 0;

#022          HWND top_child;

#023 

 

设置MDI窗口的属性。

#024          /* lpParams of WM_[NC]CREATE is different for MDI children.

#025          * MDICREATESTRUCT members have the originally passed values.

#026          */

#027          mdi.szClass = lpClassName;

#028          mdi.szTitle = lpWindowName;

#029          mdi.hOwner = hInstance;

#030          mdi.x = x;

#031          mdi.y = y;

#032          mdi.cx = nWidth;

#033          mdi.cy = nHeight;

#034          mdi.style = dwStyle;

#035          mdi.lParam = (LPARAM)lpParam;

#036 

#037          lpParam = (LPVOID)&mdi;

#038 

 

检查MDI的子窗口是否有不允许出现的窗口显示类型。

#039          if (GetWindowLongW(hWndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)

#040          {

#041              if (dwStyle & WS_POPUP)

#042              {

#043                  WARN("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed/n");

#044                  return(0);

#045              }

#046              dwStyle |= (WS_CHILD | WS_CLIPSIBLINGS);

#047          }

#048          else

#049          {

#050              dwStyle &= ~WS_POPUP;

#051              dwStyle |= (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |

#052                  WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);

#053          }

#054 

 

获取父窗口的子窗口。

#055          top_child = GetWindow(hWndParent, GW_CHILD);

#056 

 

恢复当前显示的子窗口。

#057          if (top_child)

#058          {

#059              /* Restore current maximized child */

#060              if((dwStyle & WS_VISIBLE) && IsZoomed(top_child))

#061              {

#062                  TRACE("Restoring current maximized child %p/n", top_child);

#063                  SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );

#064                  ShowWindow(top_child, SW_RESTORE);

#065                  SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );

#066              }

#067          }

#068 

 

计算子窗口要显示的位置。

#069          MDI_CalcDefaultChildPos(hWndParent, -1, mPos, 0, &id);

#070 

 

如果不是弹出的窗口类型,窗口有菜单。

#071          if (!(dwStyle & WS_POPUP)) hMenu = (HMENU)id;

#072 

 

计算窗口的位置和窗口的大小。

#073          if (dwStyle & (WS_CHILD | WS_POPUP))

#074          {

#075              if (x == CW_USEDEFAULT || x == CW_USEDEFAULT16)

#076              {

#077                  x = mPos[0].x;

#078                  y = mPos[0].y;

#079              }

#080              if (nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16 || !nWidth)

#081                  nWidth = mPos[1].x;

#082              if (nHeight == CW_USEDEFAULT || nHeight == CW_USEDEFAULT16 || !nHeight)

#083                  nHeight = mPos[1].y;

#084          }

#085      }

#086 

 

调用函数User32CreateWindowEx来更进一步窗口管理。

#087      hwnd = User32CreateWindowEx(dwExStyle,

#088                                  (LPCSTR) lpClassName,

#089                                  (LPCSTR) lpWindowName,

#090                                  dwStyle,

#091                                  x,

#092                                  y,

#093                                  nWidth,

#094                                  nHeight,

#095                                  hWndParent,

#096                                  hMenu,

#097                                  hInstance,

#098                                  lpParam,

#099                                  TRUE);

#100      return hwnd;

#101  }

 

接着再来分析函数User32CreateWindowEx的实现,代码如下:

#001  HWND WINAPI

#002  User32CreateWindowEx(DWORD dwExStyle,

#003                       LPCSTR lpClassName,

#004                       LPCSTR lpWindowName,

#005                       DWORD dwStyle,

#006                       int x,

#007                       int y,

#008                       int nWidth,

#009                       int nHeight,

#010                       HWND hWndParent,

#011                       HMENU hMenu,

#012                       HINSTANCE hInstance,

#013                       LPVOID lpParam,

#014                       BOOL Unicode)

#015  {

#016      UNICODE_STRING WindowName;

#017      UNICODE_STRING ClassName;

#018      WNDCLASSEXA wceA;

#019      WNDCLASSEXW wceW;

#020      HWND Handle;

#021 

#022  #if 0

#023      DbgPrint("[window] User32CreateWindowEx style %d, exstyle %d, parent %d/n", dwStyle, dwExStyle, hWndParent);

#024  #endif

#025 

 

检查和转换窗口类的名称。

#026      if (IS_ATOM(lpClassName))

#027      {

#028          RtlInitUnicodeString(&ClassName, NULL);

#029          ClassName.Buffer = (LPWSTR)lpClassName;

#030      }

#031      else

#032      {

#033          if(Unicode)

#034              RtlInitUnicodeString(&ClassName, (PCWSTR)lpClassName);

#035          else

#036          {

#037              if (!RtlCreateUnicodeStringFromAsciiz(&(ClassName), (PCSZ)lpClassName))

#038              {

#039                  SetLastError(ERROR_OUTOFMEMORY);

#040                  return (HWND)0;

#041              }

#042          }

#043      }

#044 

 

检查和处理窗口的名称。

#045      if (Unicode)

#046          RtlInitUnicodeString(&WindowName, (PCWSTR)lpWindowName);

#047      else

#048      {

#049          if (!RtlCreateUnicodeStringFromAsciiz(&WindowName, (PCSZ)lpWindowName))

#050          {

#051              if (!IS_ATOM(lpClassName))

#052              {

#053                  RtlFreeUnicodeString(&ClassName);

#054              }

#055              SetLastError(ERROR_OUTOFMEMORY);

#056              return (HWND)0;

#057          }

#058      }

#059 

 

从窗口类里获取菜单并加载。

#060      if(!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))

#061      {

#062          if(Unicode)

#063          {

#064              wceW.cbSize = sizeof(WNDCLASSEXW);

#065              if(GetClassInfoExW(hInstance, (LPCWSTR)lpClassName, &wceW) && wceW.lpszMenuName)

#066              {

#067                  hMenu = LoadMenuW(hInstance, wceW.lpszMenuName);

#068              }

#069          }

#070          else

#071          {

#072              wceA.cbSize = sizeof(WNDCLASSEXA);

#073              if(GetClassInfoExA(hInstance, lpClassName, &wceA) && wceA.lpszMenuName)

#074              {

#075                  hMenu = LoadMenuA(hInstance, wceA.lpszMenuName);

#076              }

#077          }

#078      }

#079 

 

下面调用内核函数NtUserCreateWindowEx来创建窗口。

#080      Handle = NtUserCreateWindowEx(dwExStyle,

#081                                    &ClassName,

#082                                    &WindowName,

#083                                    dwStyle,

#084                                    x,

#085                                    y,

#086                                    nWidth,

#087                                    nHeight,

#088                                    hWndParent,

#089                                    hMenu,

#090                                    hInstance,

#091                                    lpParam,

#092                                    SW_SHOW,

#093                                    FALSE,

#094                                    0);

#095 

#096  #if 0

#097      DbgPrint("[window] NtUserCreateWindowEx() == %d/n", Handle);

#098  #endif

#099 

 

删除UNICODE占用的空间。

#100      if(!Unicode)

#101      {

#102          RtlFreeUnicodeString(&WindowName);

#103 

#104          if (!IS_ATOM(lpClassName))

#105          {

#106              RtlFreeUnicodeString(&ClassName);

#107          }

#108      }

 

返回创建成功的窗口句柄。

#109      return Handle;

#110  }