微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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,

#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 }

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...