reactos操作系统实现(158)
在ReactOS的应用程序里,每个有窗口的应用程序都需要注册一个窗口类,然后根据窗口类来创建窗口。注册窗口的调用函数就是RegisterClassW,这个函数是UNICODE的版本,其实还有多节字版本,但代码是差不多的。这里主要分析UNICODE版本的实现,其代码如下: #001 ATOM WINAPI #002 RegisterClassW(CONST WNDCLASSW *lpWndClass) #003 { lpWndClass是应用程序定义窗口类的结构指针。
声明一个扩展窗口类。 #004 WNDCLASSEXW Class; #005
检查窗口类的指针是否为空,如果为空就是非法,直接返回。 #006 if (lpWndClass == NULL) #007 return 0; #008
拷贝老版本的窗口类结构到扩展窗口类结构里。 #009 RtlCopyMemory(&Class.style,lpWndClass,sizeof(WNDCLASSW)); #010 Class.cbSize = sizeof(WNDCLASSEXW); #011 Class.hIconSm = NULL; #012
调用函数RegisterClassExW来注册窗口类。 #013 return RegisterClassExW(&Class); #014 }
接着来分析函数RegisterClassExW的实现,它的代码如下: #001 ATOM WINAPI #002 RegisterClassExW(CONST WNDCLASSEXW *lpwcx) #003 { #004 ATOM Atom; #005 WNDCLASSEXW WndClass; #006 UNICODE_STRING ClassName; #007 UNICODE_STRING MenuName = {0}; #008 HMENU hMenu = NULL; #009
判断输入的结构是否有效。 #010 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) || #011 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 || #012 lpwcx->lpszClassName == NULL) #013 { #014 SetLastError(ERROR_INVALID_PARAMETER); #015 return 0; #016 } #017 #018 /* #019 * On real Windows this looks more like: #020 * if (lpwcx->hInstance == User32Instance && #021 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400) #022 * But since I have no idea what the magic field in the #023 * TEB structure means,I rather decided to omit that. #024 * -- Filip Navara #025 */
如果窗口的实例句柄是用户的句柄,就退出。 #026 if (lpwcx->hInstance == User32Instance) #027 { #028 SetLastError(ERROR_INVALID_PARAMETER); #029 return 0; #030 } #031
如果实例句柄为空,就使用函数GetModuleHandleW获取当前模板的句柄。 #032 /* Yes,this is correct. We should modify the passed structure. */ #033 if (lpwcx->hInstance == NULL) #034 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL); #035
拷贝窗口类的结构。 #036 RtlCopyMemory(&WndClass,lpwcx,sizeof(WNDCLASSEXW)); #037
如果应用程序没有创建小图标,那么这里就创建一个默认的小图标。 #038 if (NULL == WndClass.hIconSm) #039 { #040 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon); #041 } #042
如果有系统菜单,就需要加载系统菜单。 #043 if (WndClass.lpszMenuName != NULL) #044 {
转换菜单的名称。 #045 if (!IS_INTRESOURCE(WndClass.lpszMenuName)) #046 { #047 if (WndClass.lpszMenuName[0]) #048 { #049 RtlInitUnicodeString(&MenuName,WndClass.lpszMenuName); #050 } #051 } #052 else #053 { #054 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName; #055 } #056
从资源里加载菜单。 #057 if (MenuName.Buffer != NULL) #058 hMenu = LoadMenuW(WndClass.hInstance,WndClass.lpszMenuName); #059 } #060
转换窗口类的名称。 #061 if (IS_ATOM(WndClass.lpszClassName)) #062 { #063 ClassName.Length = #064 ClassName.MaximumLength = 0; #065 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName; #066 } #067 else #068 { #069 RtlInitUnicodeString(&ClassName,WndClass.lpszClassName); #070 } #071
通过系统中断调用内核函数NtUserRegisterClassEx。 #072 Atom = (ATOM)NtUserRegisterClassEx(&WndClass, #073 &ClassName, #074 &MenuName, #075 NULL, #076 0, #077 hMenu); #078 #079 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p/n", #080 Atom,lpwcx->lpfnWndProc,lpwcx->hInstance,lpwcx->hbrBackground, #081 lpwcx->style,lpwcx->cbClsExtra,lpwcx->cbWndExtra,WndClass); #082 #083 return Atom; #084 }
从前面的分析可以知道,函数NtUserRegisterClassEx调用,也是通过系统中断来调用内核函数,也就是调用Win32k.sys文件里的函数。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |