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文件里的函数。

你可能感兴趣的:(react)