reactos操作系统实现(159)

NtUserRegisterClassEx函数是Win32k.sys里实现窗口类的注册,那么窗口类的注册是什么意思呢?到底注册是为了什么样的目的呢?下面就通过实现代码的分析来解决这些问题,代码如下:

#001  RTL_ATOM APIENTRY

#002  NtUserRegisterClassEx(IN CONST WNDCLASSEXW* lpwcx,

#003                        IN PUNICODE_STRING ClassName,

#004                        IN PUNICODE_STRING MenuName,

#005                        IN WNDPROC wpExtra,

#006                        IN DWORD Flags,

#007                        IN HMENU hMenu)

#008 

#009  /*

#010   * FUNCTION:

#011   *   Registers a new class with the window manager

#012   * ARGUMENTS:

#013   *   lpwcx          = Win32 extended window class structure

#014   *   bUnicodeClass = Whether to send ANSI or unicode strings

#015   *                   to window procedures

#016   *   wpExtra       = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.

#017   * RETURNS:

#018   *   Atom identifying the new class

#019   */

#020  {

#021      WNDCLASSEXW CapturedClassInfo = {0};

#022      UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};

#023      RTL_ATOM Ret = (RTL_ATOM)0;

#024 

 

如果注册标志有问题,就直接返回出错。

#025      if (Flags & ~REGISTERCLASS_ALL)

#026      {

#027          SetLastWin32Error(ERROR_INVALID_FLAGS);

#028          return Ret;

#029      }

#030 

 

增加用户进入锁,以便后面的代码进行临界区访问。

#031      UserEnterExclusive();

#032 

 

使用异常机制处理用户输入来的参数。

#033      _SEH2_TRY

#034      {

 

查注册类的结构大小是否符合内核的注册类的结构大小,如果不符合就返回出错。

#035          /* Probe the parameters and basic parameter checks */

#036          if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))

#037          {

#038              goto InvalidParameter;

#039          }

#040 

 

检查读取是否出错。

#041          ProbeForRead(lpwcx,

#042                       sizeof(WNDCLASSEXW),

#043                       sizeof(ULONG));

 

拷贝用户空间的注册类信息。

#044          RtlCopyMemory(&CapturedClassInfo,

#045                        lpwcx,

#046                        sizeof(WNDCLASSEXW));

#047 

 

读取注册窗口类的名称。

#048          CapturedName = ProbeForReadUnicodeString(ClassName);

 

读取注册窗口类的菜单名称。

#049          CapturedMenuName = ProbeForReadUnicodeString(MenuName);

#050 

 

窗口类的非法参数检查。

#051          if (CapturedName.Length & 1 || CapturedMenuName.Length & 1 ||

#052              CapturedClassInfo.cbClsExtra < 0 ||

#053              CapturedClassInfo.cbClsExtra + CapturedName.Length +

#054                  CapturedMenuName.Length + sizeof(WINDOWCLASS) < CapturedClassInfo.cbClsExtra ||

#055              CapturedClassInfo.cbWndExtra < 0 ||

#056              CapturedClassInfo.hInstance == NULL)

#057          {

#058              goto InvalidParameter;

#059          }

#060 

#061          if (CapturedName.Length != 0)

#062          {

#063              ProbeForRead(CapturedName.Buffer,

#064                           CapturedName.Length,

#065                           sizeof(WCHAR));

#066          }

#067          else

#068          {

#069              if (!IS_ATOM(CapturedName.Buffer))

#070              {

#071                  goto InvalidParameter;

#072              }

#073          }

#074 

#075          if (CapturedMenuName.Length != 0)

#076          {

#077              ProbeForRead(CapturedMenuName.Buffer,

#078                           CapturedMenuName.Length,

#079                           sizeof(WCHAR));

#080          }

#081          else if (CapturedMenuName.Buffer != NULL &&

#082                   !IS_INTRESOURCE(CapturedMenuName.Buffer))

#083          {

#084  InvalidParameter:

#085              SetLastWin32Error(ERROR_INVALID_PARAMETER);

#086              _SEH2_LEAVE;

#087          }

#088 

 

调用函数UserRegisterClass来更进一步处理注册过程。

#089          /* Register the class */

#090          Ret = UserRegisterClass(&CapturedClassInfo,

#091                                  &CapturedName,

#092                                  &CapturedMenuName,

#093                                  hMenu, /* FIXME - pass pointer */

#094                                  wpExtra,

#095                                  Flags);

#096 

#097      }

#098      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#099      {

#100          SetLastNtError(_SEH2_GetExceptionCode());

#101      }

#102      _SEH2_END;

#103 

 

退出临界区。

#104      UserLeave();

#105 

#106      return Ret;

#107  }

#108 

 

上面调用函数UserRegisterClass来更进一步处理,因而再接着分析这个函数的实现,它的代码如下:

#001  RTL_ATOM

#002  UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,

#003                    IN PUNICODE_STRING ClassName,

#004                    IN PUNICODE_STRING MenuName,

#005                    IN HANDLE hMenu, /* FIXME */

#006                    IN WNDPROC wpExtra,

#007                    IN DWORD dwFlags)

#008  {

#009      PTHREADINFO pti;

#010      PW32THREADINFO ti;

#011      PW32PROCESSINFO pi;

#012      PWINDOWCLASS Class;

#013      RTL_ATOM ClassAtom;

#014      RTL_ATOM Ret = (RTL_ATOM)0;

#015 

#016      /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */

#017 

 

获取当前线程信息。

#018      pti = PsGetCurrentThreadWin32Thread();

#019      ti = GetW32ThreadInfo();

#020      if (ti == NULL || !ti->kpi->RegisteredSysClasses)

#021      {

#022          SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);

#023          return (RTL_ATOM)0;

#024      }

#025 

#026      pi = ti->kpi;

#027 

 

查找以前是否注册过相同名称的窗口类。

#028      /* try to find a previously registered class */

#029      ClassAtom = IntGetClassAtom(ClassName,

#030                                  lpwcx->hInstance,

#031                                  pi,

#032                                  &Class,

#033                                  NULL);

#034      if (ClassAtom != (RTL_ATOM)0)

#035      {

 

如果窗口类已经注册过,就返回相应的出错信息。

#036          if (lpwcx->style & CS_GLOBALCLASS)

#037          {

#038              // global classes shall not have same names as system classes

#039              if (Class->Global || Class->System)

#040              {

#041                  DPRINT("Class 0x%p does already exist!/n", ClassAtom);

#042                  SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);

#043                  return (RTL_ATOM)0;

#044              }

#045          }

#046          else if ( !Class->Global && !Class->System)

#047          {

#048              // local class already exists

#049              DPRINT("Class 0x%p does already exist!/n", ClassAtom);

#050              SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);

#051              return (RTL_ATOM)0;

#052          }

#053      }

#054 

 

调用函数IntCreateClass来创建一个窗口类。

#055      Class = IntCreateClass(lpwcx,

#056                             ClassName,

#057                             MenuName,

#058                             wpExtra,

#059                             dwFlags,

#060                             pti->Desktop,

#061                             pi);

#062 

 

如果创建注册类成功,就把这个窗口类保存到系统相应的列表里。

#063      if (Class != NULL)

#064      {

#065          PWINDOWCLASS *List;

#066 

 

保存菜单句柄。

#067          /* FIXME - pass the PMENU pointer to IntCreateClass instead! */

#068          Class->hMenu = hMenu;

#069 

 

根据注册类的使用范围来保存不同的系统列表里。

#070          /* Register the class */

#071          if (Class->System)

#072              List = &pi->SystemClassList;

#073          else if (Class->Global)

#074              List = &pi->GlobalClassList;

#075          else

#076              List = &pi->LocalClassList;

#077 

 

列表插入操作。

#078          Class->Next = *List;

#079          (void)InterlockedExchangePointer((PVOID*)List,

#080                                           Class);

#081 

#082          Ret = Class->Atom;

#083      }

#084 

#085      return Ret;

#086  }

 

通过上面的分析,可以了解到注册一个窗口类,就是分配一个新的窗口类内存结构,然后设置结构的字段,最后把它保存到合适的列表里。

posted @ 2009-12-14 22:04  ajuanabc  阅读(159)  评论(0编辑  收藏  举报