📄 class.c
字号:
/* make a copy of the string */
if (pszMenuNameBuffer != NULL)
{
Class->MenuNameIsString = TRUE;
Class->MenuName = pszMenuNameBuffer;
RtlCopyMemory(Class->MenuName,
MenuName->Buffer,
MenuName->Length);
Class->MenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
}
else
Class->MenuName = MenuName->Buffer;
/* save an ansi copy of the string */
if (pszMenuNameBuffer != NULL)
{
ANSI_STRING AnsiString;
Class->AnsiMenuName = (PSTR)pszMenuNameBuffer;
AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
AnsiString.Buffer = Class->AnsiMenuName;
Status = RtlUnicodeStringToAnsiString(&AnsiString,
MenuName,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to convert unicode menu name to ansi!\n");
/* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
_SEH_LEAVE;
}
}
else
Class->AnsiMenuName = (PSTR)MenuName->Buffer;
if (!(dwFlags & REGISTERCLASS_ANSI))
Class->Unicode = TRUE;
if (Class->Style & CS_GLOBALCLASS)
Class->Global = TRUE;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed creating the class: 0x%x\n", Status);
SetLastNtError(Status);
if (pszMenuName != NULL)
UserHeapFree(pszMenuName);
DesktopHeapFree(Desktop,
Class);
Class = NULL;
IntDeregisterClassAtom(Atom);
}
}
else
{
NoMem:
DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop);
if (pszMenuName != NULL)
UserHeapFree(pszMenuName);
IntDeregisterClassAtom(Atom);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
}
return Class;
}
static PWINDOWCLASS
IntFindClass(IN RTL_ATOM Atom,
IN HINSTANCE hInstance,
IN PWINDOWCLASS *ClassList,
OUT PWINDOWCLASS **Link OPTIONAL)
{
PWINDOWCLASS Class, *PrevLink = ClassList;
Class = *PrevLink;
while (Class != NULL)
{
if (Class->Atom == Atom &&
(hInstance == NULL || Class->hInstance == hInstance) &&
!Class->Destroying)
{
ASSERT(Class->Base == Class);
if (Link != NULL)
*Link = PrevLink;
break;
}
PrevLink = &Class->Next;
Class = Class->Next;
}
return Class;
}
BOOL
IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
OUT RTL_ATOM *Atom)
{
BOOL Ret = FALSE;
if (ClassName->Length != 0)
{
WCHAR szBuf[65];
PWSTR AtomName;
NTSTATUS Status;
/* NOTE: Caller has to protect the call with SEH! */
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;
}
/* We need to make a local copy of the class name! The caller could
modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
We're protected by SEH, but the ranges that might be accessed were
not probed... */
RtlCopyMemory(szBuf,
ClassName->Buffer,
ClassName->Length);
szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
AtomName = szBuf;
}
else
AtomName = ClassName->Buffer;
/* lookup the atom */
Status = RtlLookupAtomInAtomTable(gAtomTable,
AtomName,
Atom);
if (NT_SUCCESS(Status))
{
Ret = TRUE;
}
else
{
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
}
else
{
SetLastNtError(Status);
}
}
}
else
{
ASSERT(IS_ATOM(ClassName->Buffer));
*Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
Ret = TRUE;
}
return Ret;
}
RTL_ATOM
IntGetClassAtom(IN PUNICODE_STRING ClassName,
IN HINSTANCE hInstance OPTIONAL,
IN PW32PROCESSINFO pi OPTIONAL,
OUT PWINDOWCLASS *BaseClass OPTIONAL,
OUT PWINDOWCLASS **Link OPTIONAL)
{
RTL_ATOM Atom = (RTL_ATOM)0;
if (IntGetAtomFromStringOrAtom(ClassName,
&Atom) &&
BaseClass != NULL && Atom != (RTL_ATOM)0)
{
PWINDOWCLASS Class;
/* attempt to locate the class object */
ASSERT(pi != NULL);
/* Step 1: try to find an exact match of locally registered classes */
Class = IntFindClass(Atom,
hInstance,
&pi->LocalClassList,
Link);
if (Class != NULL)
{
goto FoundClass;
}
/* Step 2: try to find any globally registered class. The hInstance
is not relevant for global classes */
Class = IntFindClass(Atom,
NULL,
&pi->GlobalClassList,
Link);
if (Class != NULL)
{
goto FoundClass;
}
/* Step 3: try to find any local class registered by user32 */
Class = IntFindClass(Atom,
pi->hModUser,
&pi->LocalClassList,
Link);
if (Class != NULL)
{
goto FoundClass;
}
/* Step 4: try to find any global class registered by user32 */
Class = IntFindClass(Atom,
pi->hModUser,
&pi->GlobalClassList,
Link);
if (Class != NULL)
{
goto FoundClass;
}
/* Step 5: try to find a system class */
Class = IntFindClass(Atom,
NULL,
&pi->SystemClassList,
Link);
if (Class == NULL)
{
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
return (RTL_ATOM)0;
}
FoundClass:
*BaseClass = Class;
}
return Atom;
}
RTL_ATOM
UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
IN PUNICODE_STRING ClassName,
IN PUNICODE_STRING MenuName,
IN HANDLE hMenu, /* FIXME */
IN WNDPROC wpExtra,
IN DWORD dwFlags)
{
PW32THREADINFO ti;
PW32PROCESSINFO pi;
PWINDOWCLASS Class;
RTL_ATOM ClassAtom;
RTL_ATOM Ret = (RTL_ATOM)0;
/* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
ti = GetW32ThreadInfo();
if (ti == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return (RTL_ATOM)0;
}
pi = ti->kpi;
/* try to find a previously registered class */
ClassAtom = IntGetClassAtom(ClassName,
lpwcx->hInstance,
pi,
&Class,
NULL);
if (ClassAtom != (RTL_ATOM)0)
{
if (lpwcx->style & CS_GLOBALCLASS)
{
// global classes shall not have same names as system classes
if (Class->Global || Class->System)
{
DPRINT("Class 0x%p does already exist!\n", ClassAtom);
SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
return (RTL_ATOM)0;
}
}
else if ( !Class->Global && !Class->System)
{
// local class already exists
DPRINT("Class 0x%p does already exist!\n", ClassAtom);
SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
return (RTL_ATOM)0;
}
}
Class = IntCreateClass(lpwcx,
ClassName,
MenuName,
wpExtra,
dwFlags,
ti->Desktop,
pi);
if (Class != NULL)
{
PWINDOWCLASS *List;
/* FIXME - pass the PMENU pointer to IntCreateClass instead! */
Class->hMenu = hMenu;
/* Register the class */
if (Class->System)
List = &pi->SystemClassList;
else if (Class->Global)
List = &pi->GlobalClassList;
else
List = &pi->LocalClassList;
Class->Next = *List;
(void)InterlockedExchangePointer(List,
Class);
Ret = Class->Atom;
}
return Ret;
}
BOOL
UserUnregisterClass(IN PUNICODE_STRING ClassName,
IN HINSTANCE hInstance)
{
PWINDOWCLASS *Link;
PW32PROCESSINFO pi;
RTL_ATOM ClassAtom;
PWINDOWCLASS Class;
pi = GetW32ProcessInfo();
if (pi == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/* NOTE: Accessing the buffer in ClassName may raise an exception! */
ClassAtom = IntGetClassAtom(ClassName,
hInstance,
pi,
&Class,
&Link);
if (ClassAtom == (RTL_ATOM)0)
{
return FALSE;
}
ASSERT(Class != NULL);
if (Class->Windows != 0 ||
Class->Clone != NULL)
{
SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
return FALSE;
}
/* must be a base class! */
ASSERT(Class->Base == Class);
/* unlink the class */
*Link = Class->Next;
if (NT_SUCCESS(IntDeregisterClassAtom(Class->Atom)))
{
/* finally free the resources */
IntDestroyClass(Class);
return TRUE;
}
return FALSE;
}
INT
UserGetClassName(IN PWINDOWCLASS Class,
IN OUT PUNICODE_STRING ClassName,
IN BOOL Ansi)
{
NTSTATUS Status = STATUS_SUCCESS;
WCHAR szStaticTemp[32];
PWSTR szTemp = NULL;
ULONG BufLen = sizeof(szStaticTemp);
INT Ret = 0;
/* Note: Accessing the buffer in ClassName may raise an exception! */
_SEH_TRY
{
if (Ansi)
{
PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
UNICODE_STRING UnicodeClassName;
/* limit the size of the static buffer on the stack to the
size of the buffer provided by the caller */
if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
{
BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
}
/* find out how big the buffer needs to be */
Status = RtlQueryAtomInAtomTable(gAtomTable,
Class->Atom,
NULL,
NULL,
szStaticTemp,
&BufLen);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
{
/* the buffer required exceeds the ansi buffer provided,
pretend like we're using the ansi buffer and limit the
size to the buffer size provided */
BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
}
/* allocate a temporary buffer that can hold the unicode class name */
szTemp = ExAllocatePool(PagedPool,
BufLen);
if (szTemp == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
_SEH_LEAVE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -