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 }
通过上面的分析,可以了解到注册一个窗口类,就是分配一个新的窗口类内存结构,然后设置结构的字段,最后把它保存到合适的列表里。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |