📄 class.c
字号:
/*
* ReactOS W32 Subsystem
* Copyright (C) 1998 - 2006 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: class.c 27946 2007-07-28 12:22:27Z weiden $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Window classes
* FILE: subsys/win32k/ntuser/class.c
* PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
* REVISION HISTORY:
* 06-06-2001 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
#define TRACE DPRINT
#define WARN DPRINT1
#define ERR DPRINT1
/* WINDOWCLASS ***************************************************************/
static VOID
IntFreeClassMenuName(IN OUT PWINDOWCLASS Class)
{
/* free the menu name, if it was changed and allocated */
if (Class->MenuName != NULL && Class->MenuNameIsString)
{
UserHeapFree(Class->MenuName);
Class->MenuName = NULL;
Class->AnsiMenuName = NULL;
}
}
static VOID
IntDestroyClass(IN OUT PWINDOWCLASS Class)
{
/* there shouldn't be any clones anymore */
ASSERT(Class->Windows == 0);
ASSERT(Class->Clone == NULL);
if (Class->Base == Class)
{
/* destruct resources shared with clones */
if (!Class->System && Class->CallProc != NULL)
{
DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
Class->CallProc);
}
if (Class->CallProc2 != NULL)
{
DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop,
Class->CallProc2);
}
IntFreeClassMenuName(Class);
}
/* free the structure */
if (Class->Desktop != NULL)
{
DesktopHeapFree(Class->Desktop,
Class);
}
else
{
UserHeapFree(Class);
}
}
/* clean all process classes. all process windows must cleaned first!! */
void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
{
PWINDOWCLASS Class;
PW32PROCESSINFO pi = Process->ProcessInfo;
if (pi != NULL)
{
/* free all local classes */
Class = pi->LocalClassList;
while (Class != NULL)
{
pi->LocalClassList = Class->Next;
ASSERT(Class->Base == Class);
IntDestroyClass(Class);
Class = pi->LocalClassList;
}
/* free all global classes */
Class = pi->GlobalClassList;
while (Class != NULL)
{
pi->GlobalClassList = Class->Next;
ASSERT(Class->Base == Class);
IntDestroyClass(Class);
Class = pi->GlobalClassList;
}
/* free all system classes */
Class = pi->SystemClassList;
while (Class != NULL)
{
pi->SystemClassList = Class->Next;
ASSERT(Class->Base == Class);
IntDestroyClass(Class);
Class = pi->SystemClassList;
}
}
}
static BOOL
IntRegisterClassAtom(IN PUNICODE_STRING ClassName,
OUT RTL_ATOM *pAtom)
{
WCHAR szBuf[65];
PWSTR AtomName;
NTSTATUS Status;
if (ClassName->Length != 0)
{
/* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return (RTL_ATOM)0;
}
RtlCopyMemory(szBuf,
ClassName->Buffer,
ClassName->Length);
szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
AtomName = szBuf;
}
else
AtomName = ClassName->Buffer;
Status = RtlAddAtomToAtomTable(gAtomTable,
AtomName,
pAtom);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
}
return TRUE;
}
static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom)
{
return RtlDeleteAtomFromAtomTable(gAtomTable,
Atom);
}
static BOOL
IntSetClassAtom(IN OUT PWINDOWCLASS Class,
IN PUNICODE_STRING ClassName)
{
RTL_ATOM Atom = (RTL_ATOM)0;
/* update the base class first */
Class = Class->Base;
if (!IntRegisterClassAtom(ClassName,
&Atom))
{
return FALSE;
}
IntDeregisterClassAtom(Class->Atom);
Class->Atom = Atom;
/* update the clones */
Class = Class->Clone;
while (Class != NULL)
{
Class->Atom = Atom;
Class = Class->Next;
}
return TRUE;
}
static WNDPROC
IntGetClassWndProc(IN PWINDOWCLASS Class,
IN PW32PROCESSINFO pi,
IN BOOL Ansi,
IN BOOL UseCallProc2)
{
ASSERT(UserIsEnteredExclusive() == TRUE);
if (Class->System)
{
return (Ansi ? Class->WndProcExtra : Class->WndProc);
}
else
{
if (!Ansi == Class->Unicode)
{
return Class->WndProc;
}
else
{
PCALLPROC *CallProcPtr;
PWINDOWCLASS BaseClass;
/* make sure the call procedures are located on the desktop
of the base class! */
BaseClass = Class->Base;
Class = BaseClass;
CallProcPtr = (UseCallProc2 ? &Class->CallProc2 : &Class->CallProc);
if (*CallProcPtr != NULL)
{
return GetCallProcHandle(*CallProcPtr);
}
else
{
PCALLPROC NewCallProc;
if (pi == NULL)
return NULL;
NewCallProc = CreateCallProc(Class->Desktop,
Class->WndProc,
Class->Unicode,
pi);
if (NewCallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
*CallProcPtr = NewCallProc;
if (Class->Desktop == NULL)
{
if (UseCallProc2)
Class->GlobalCallProc2 = TRUE;
else
Class->GlobalCallProc = TRUE;
}
/* update the clones */
Class = Class->Clone;
while (Class != NULL)
{
if (UseCallProc2)
{
Class->CallProc2 = NewCallProc;
Class->GlobalCallProc2 = BaseClass->GlobalCallProc2;
}
else
{
Class->CallProc = NewCallProc;
Class->GlobalCallProc = BaseClass->GlobalCallProc;
}
Class = Class->Next;
}
return GetCallProcHandle(NewCallProc);
}
}
}
}
static WNDPROC
IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
IN WNDPROC WndProc,
IN BOOL Ansi)
{
WNDPROC Ret;
if (Class->System)
{
DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class->Atom);
SetLastWin32Error(ERROR_ACCESS_DENIED);
return NULL;
}
/* update the base class first */
Class = Class->Base;
/* resolve any callproc handle if possible */
if (IsCallProcHandle(WndProc))
{
WNDPROC_INFO wpInfo;
if (UserGetCallProcInfo((HANDLE)WndProc,
&wpInfo))
{
WndProc = wpInfo.WindowProc;
/* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
}
}
Ret = IntGetClassWndProc(Class,
GetW32ProcessInfo(),
Ansi,
TRUE);
if (Ret == NULL)
{
return NULL;
}
/* update the class info */
Class->Unicode = !Ansi;
Class->WndProc = WndProc;
if (Class->CallProc != NULL)
{
Class->CallProc->WndProc = WndProc;
Class->CallProc->Unicode = !Ansi;
}
/* update the clones */
Class = Class->Clone;
while (Class != NULL)
{
Class->Unicode = !Ansi;
Class->WndProc = WndProc;
Class = Class->Next;
}
return Ret;
}
static PWINDOWCLASS
IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
IN OUT PWINDOWCLASS *ClassLink,
IN PDESKTOP Desktop)
{
SIZE_T ClassSize;
PWINDOWCLASS Class;
ASSERT(Desktop != NULL);
ASSERT(BaseClass->Base == BaseClass);
if (BaseClass->Desktop == Desktop)
{
/* it is most likely that a window is created on the same
desktop as the window class. */
return BaseClass;
}
if (BaseClass->Desktop == NULL)
{
ASSERT(BaseClass->Windows == 0);
ASSERT(BaseClass->Clone == NULL);
/* Classes are also located in the shared heap when the class
was created before the thread attached to a desktop. As soon
as a window is created for such a class located on the shared
heap, the class is cloned into the desktop heap on which the
window is created. */
Class = NULL;
}
else
{
/* The user is asking for a class object on a different desktop,
try to find one! */
Class = BaseClass->Clone;
while (Class != NULL)
{
if (Class->Desktop == Desktop)
{
ASSERT(Class->Base == BaseClass);
ASSERT(Class->Clone == NULL);
break;
}
Class = Class->Next;
}
}
if (Class == NULL)
{
/* The window is created on a different desktop, we need to
clone the class object to the desktop heap of the window! */
ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->ClsExtra;
Class = DesktopHeapAlloc(Desktop,
ClassSize);
if (Class != NULL)
{
/* simply clone the class */
RtlCopyMemory(Class,
BaseClass,
ClassSize);
/* update some pointers and link the class */
Class->Desktop = Desktop;
Class->Windows = 0;
if (BaseClass->Desktop == NULL)
{
/* we don't really need the base class on the shared
heap anymore, delete it so the only class left is
the clone we just created, which now serves as the
new base class */
ASSERT(BaseClass->Clone == NULL);
ASSERT(Class->Clone == NULL);
Class->Base = Class;
Class->Next = BaseClass->Next;
if (!BaseClass->System && BaseClass->CallProc != NULL)
Class->GlobalCallProc = TRUE;
if (BaseClass->CallProc2 != NULL)
Class->GlobalCallProc2 = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -