* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Window classes
- * FILE: subsystems/win32/win32k/ntuser/class.c
+ * FILE: win32ss/user/ntuser/class.c
* PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserClass);
+static PWSTR ControlsList[] =
+{
+ L"Button",
+ L"Edit",
+ L"Static",
+ L"ListBox",
+ L"ScrollBar",
+ L"ComboBox",
+ L"MDIClient",
+ L"ComboLBox",
+ L"DDEMLEvent",
+ L"DDEMLMom",
+ L"DMGClass",
+ L"DDEMLAnsiClient",
+ L"DDEMLUnicodeClient",
+ L"DDEMLAnsiServer",
+ L"DDEMLUnicodeServer",
+ L"IME",
+ L"Ghost",
+};
+
+static NTSTATUS IntDeregisterClassAtom(IN RTL_ATOM Atom);
+
REGISTER_SYSCLASS DefaultServerClasses[] =
{
{ ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
CS_GLOBALCLASS|CS_DBLCLKS,
NULL, // Use User32 procs
sizeof(ULONG)*2,
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
(HBRUSH)(COLOR_BACKGROUND),
FNID_DESKTOP,
ICLS_DESKTOP
CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS,
NULL, // Use User32 procs
sizeof(LONG),
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
NULL,
FNID_SWITCH,
ICLS_SWITCH
CS_DBLCLKS|CS_SAVEBITS,
NULL, // Use User32 procs
sizeof(LONG),
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
(HBRUSH)(COLOR_MENU + 1),
FNID_MENU,
ICLS_MENU
CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW|CS_PARENTDC,
NULL, // Use User32 procs
sizeof(SBWND)-sizeof(WND),
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
NULL,
FNID_SCROLLBAR,
ICLS_SCROLLBAR
CS_PARENTDC|CS_DBLCLKS,
NULL, // Use User32 procs
0,
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
0,
FNID_TOOLTIPS,
ICLS_TOOLTIPS
0,
NULL, // Use User32 procs
0,
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
0,
FNID_ICONTITLE,
ICLS_ICONTITLE
CS_GLOBALCLASS,
NULL, // Use User32 procs
0,
- (HICON)IDC_ARROW,
+ (HICON)OCR_NORMAL,
NULL,
FNID_MESSAGEWND,
ICLS_HWNDMESSAGE
NextCallProc = CallProc->spcpdNext;
CallProc->spcpdNext = NULL;
- DestroyCallProc(NULL,
- CallProc);
+ DestroyCallProc(CallProc);
CallProc = NextCallProc;
}
+ // Fixes running the static test then run class test issue.
+ // Some applications do not use UnregisterClass before exiting.
+ // Keep from reusing the same atom with case insensitive
+ // comparisons, remove registration of the atom if not zeroed.
+ if (Class->atomClassName)
+ IntDeregisterClassAtom(Class->atomClassName);
+
if (Class->pdce)
{
DceFreeClassDCE(((PDCE)Class->pdce)->hDC);
IntFreeClassMenuName(Class);
}
+ if (Class->spicn)
+ UserDereferenceObject(Class->spicn);
+ if (Class->spcur)
+ UserDereferenceObject(Class->spcur);
+ if (Class->spicnSm)
+ {
+ UserDereferenceObject(Class->spicnSm);
+ /* Destroy the icon if we own it */
+ if ((Class->CSF_flags & CSF_CACHEDSMICON)
+ && !(UserObjectInDestroy(UserHMGetHandle(Class->spicnSm))))
+ IntDestroyCurIconObject(Class->spicnSm);
+ }
+
pDesk = Class->rpdeskParent;
Class->rpdeskParent = NULL;
return TRUE;
}
+BOOL FASTCALL
+RegisterControlAtoms(VOID)
+{
+ RTL_ATOM Atom;
+ UNICODE_STRING ClassName;
+ INT i = 0;
+
+ while ( i < ICLS_DESKTOP)
+ {
+ RtlInitUnicodeString(&ClassName, ControlsList[i]);
+ if (IntRegisterClassAtom(&ClassName, &Atom))
+ {
+ gpsi->atomSysClass[i] = Atom;
+ TRACE("Reg Control Atom %ls: 0x%x\n", ControlsList[i], Atom);
+ }
+ i++;
+ }
+ return TRUE;
+}
+
static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom)
{
Class = DesktopHeapAlloc(Desktop,
ClassSize);
+
if (Class != NULL)
{
/* Simply clone the class */
RtlCopyMemory( Class, BaseClass, ClassSize);
+ /* Reference our objects */
+ if (Class->spcur)
+ UserReferenceObject(Class->spcur);
+ if (Class->spicn)
+ UserReferenceObject(Class->spicn);
+ if (Class->spicnSm)
+ UserReferenceObject(Class->spicnSm);
+
TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
/* Restore module address if default user class Ref: Bug 4778 */
NewClass->rpdeskParent = NULL;
NewClass->pclsBase = NewClass;
+ if (NewClass->spcur)
+ UserReferenceObject(NewClass->spcur);
+ if (NewClass->spicn)
+ UserReferenceObject(NewClass->spicn);
+ if (NewClass->spicnSm)
+ UserReferenceObject(NewClass->spicnSm);
+
/* Replace the class in the list */
(void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
NewClass);
/* FIXME: The class was created before being connected
to a desktop. It is possible for the desktop window,
but should it be allowed for any other case? */
+ TRACE("This CLASS has no Desktop to heap from! Atom %u\n",Atom);
Class = UserHeapAlloc(ClassSize);
}
Class->fnid = fnID;
Class->CSF_flags = dwFlags;
- if (LookupFnIdToiCls(Class->fnid, &iCls))
+ if (LookupFnIdToiCls(Class->fnid, &iCls) && gpsi->atomSysClass[iCls] == 0)
{
gpsi->atomSysClass[iCls] = Class->atomClassName;
}
Class->cbclsExtra = lpwcx->cbClsExtra;
Class->cbwndExtra = lpwcx->cbWndExtra;
Class->hModule = lpwcx->hInstance;
- Class->hIcon = lpwcx->hIcon; /* FIXME */
- Class->hIconSm = lpwcx->hIconSm; /* FIXME */
- Class->hCursor = lpwcx->hCursor; /* FIXME */
+ Class->spicn = lpwcx->hIcon ? UserGetCurIconObject(lpwcx->hIcon) : NULL;
+ Class->spcur = lpwcx->hCursor ? UserGetCurIconObject(lpwcx->hCursor) : NULL;
+ Class->spicnSm = lpwcx->hIconSm ? UserGetCurIconObject(lpwcx->hIconSm) : NULL;
+ ////
Class->hbrBackground = lpwcx->hbrBackground;
/* Make a copy of the string */
return Class;
}
+_Success_(return)
BOOL
NTAPI
IntGetAtomFromStringOrAtom(
ASSERT(BaseClass != NULL);
- if (IntGetAtomFromStringOrAtom(ClassName,
- &Atom) &&
+ if (IntGetAtomFromStringOrAtom(ClassName, &Atom) &&
Atom != (RTL_ATOM)0)
{
PCLS Class;
FoundClass:
*BaseClass = Class;
}
+ else
+ {
+ Atom = 0;
+ }
return Atom;
}
{
TRACE("Class 0x%p\n", Class);
TRACE("UserUnregisterClass: Good Exit!\n");
+ Class->atomClassName = 0; // Don't let it linger...
/* Finally free the resources */
IntDestroyClass(Class);
return TRUE;
break;
case GCLP_HCURSOR:
- /* FIXME: Get handle from pointer to CURSOR object */
- Ret = (ULONG_PTR)Class->hCursor;
- Class->hCursor = (HANDLE)NewLong;
+ {
+ PCURICON_OBJECT NewCursor = NULL;
+
+ if (NewLong)
+ {
+ NewCursor = UserGetCurIconObject((HCURSOR)NewLong);
+ if (!NewCursor)
+ {
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return 0;
+ }
+ }
+
+ if (Class->spcur)
+ {
+ Ret = (ULONG_PTR)UserHMGetHandle(Class->spcur);
+ UserDereferenceObject(Class->spcur);
+ }
+ else
+ {
+ Ret = 0;
+ }
+
+ if (Ret == NewLong)
+ {
+ /* It's a nop */
+ return Ret;
+ }
+
+ Class->spcur = NewCursor;
/* Update the clones */
Class = Class->pclsClone;
while (Class != NULL)
{
- Class->hCursor = (HANDLE)NewLong;
+ if (Class->spcur)
+ UserDereferenceObject(Class->spcur);
+ if (NewCursor)
+ UserReferenceObject(NewCursor);
+ Class->spcur = NewCursor;
Class = Class->pclsNext;
}
+
break;
+ }
+ // MSDN:
+ // hIconSm, A handle to a small icon that is associated with the window class.
+ // If this member is NULL, the system searches the icon resource specified by
+ // the hIcon member for an icon of the appropriate size to use as the small icon.
+ //
case GCLP_HICON:
- /* FIXME: Get handle from pointer to ICON object */
- Ret = (ULONG_PTR)Class->hIcon;
- Class->hIcon = (HANDLE)NewLong;
+ {
+ PCURICON_OBJECT NewIcon = NULL;
+ PCURICON_OBJECT NewSmallIcon = NULL;
+
+ if (NewLong)
+ {
+ NewIcon = UserGetCurIconObject((HCURSOR)NewLong);
+ if (!NewIcon)
+ {
+ EngSetLastError(ERROR_INVALID_ICON_HANDLE);
+ return 0;
+ }
+ }
+
+ if (Class->spicn)
+ {
+ Ret = (ULONG_PTR)UserHMGetHandle(Class->spicn);
+ UserDereferenceObject(Class->spicn);
+ }
+ else
+ {
+ Ret = 0;
+ }
+
+ if (Ret == NewLong)
+ {
+ /* It's a nop */
+ return Ret;
+ }
+
+ if (Ret && (Class->CSF_flags & CSF_CACHEDSMICON))
+ {
+ /* We will change the small icon */
+ UserDereferenceObject(Class->spicnSm);
+ IntDestroyCurIconObject(Class->spicnSm);
+ Class->spicnSm = NULL;
+ Class->CSF_flags &= ~CSF_CACHEDSMICON;
+ }
+
+ if (NewLong && !Class->spicnSm)
+ {
+ /* Create the new small icon from the new large(?) one */
+ HICON SmallIconHandle = NULL;
+ if((NewIcon->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
+ == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
+ {
+ SmallIconHandle = co_IntCopyImage(
+ (HICON)NewLong,
+ IMAGE_ICON,
+ UserGetSystemMetrics( SM_CXSMICON ),
+ UserGetSystemMetrics( SM_CYSMICON ),
+ LR_COPYFROMRESOURCE);
+ }
+ if (!SmallIconHandle)
+ {
+ /* Retry without copying from resource */
+ SmallIconHandle = co_IntCopyImage(
+ (HICON)NewLong,
+ IMAGE_ICON,
+ UserGetSystemMetrics( SM_CXSMICON ),
+ UserGetSystemMetrics( SM_CYSMICON ),
+ 0);
+ }
+ if (SmallIconHandle)
+ {
+ /* So use it */
+ NewSmallIcon = Class->spicnSm = UserGetCurIconObject(SmallIconHandle);
+ Class->CSF_flags |= CSF_CACHEDSMICON;
+ }
+ }
+
+ Class->spicn = NewIcon;
/* Update the clones */
Class = Class->pclsClone;
while (Class != NULL)
{
- Class->hIcon = (HANDLE)NewLong;
+ if (Class->spicn)
+ UserDereferenceObject(Class->spicn);
+ if (NewIcon)
+ UserReferenceObject(NewIcon);
+ Class->spicn = NewIcon;
+ if (NewSmallIcon)
+ {
+ if (Class->spicnSm)
+ UserDereferenceObject(Class->spicnSm);
+ UserReferenceObject(NewSmallIcon);
+ Class->spicnSm = NewSmallIcon;
+ Class->CSF_flags |= CSF_CACHEDSMICON;
+ }
Class = Class->pclsNext;
}
break;
+ }
case GCLP_HICONSM:
- /* FIXME: Get handle from pointer to ICON object */
- Ret = (ULONG_PTR)Class->hIconSm;
- Class->hIconSm = (HANDLE)NewLong;
+ {
+ PCURICON_OBJECT NewSmallIcon = NULL;
+ BOOLEAN NewIconFromCache = FALSE;
+
+ if (NewLong)
+ {
+ NewSmallIcon = UserGetCurIconObject((HCURSOR)NewLong);
+ if (!NewSmallIcon)
+ {
+ EngSetLastError(ERROR_INVALID_ICON_HANDLE);
+ return 0;
+ }
+ }
+ else
+ {
+ /* Create the new small icon from the large one */
+ HICON SmallIconHandle = NULL;
+ if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
+ == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
+ {
+ SmallIconHandle = co_IntCopyImage(
+ UserHMGetHandle(Class->spicn),
+ IMAGE_ICON,
+ UserGetSystemMetrics( SM_CXSMICON ),
+ UserGetSystemMetrics( SM_CYSMICON ),
+ LR_COPYFROMRESOURCE);
+ }
+ if (!SmallIconHandle)
+ {
+ /* Retry without copying from resource */
+ SmallIconHandle = co_IntCopyImage(
+ UserHMGetHandle(Class->spicn),
+ IMAGE_ICON,
+ UserGetSystemMetrics( SM_CXSMICON ),
+ UserGetSystemMetrics( SM_CYSMICON ),
+ 0);
+ }
+ if (SmallIconHandle)
+ {
+ /* So use it */
+ NewSmallIcon = UserGetCurIconObject(SmallIconHandle);
+ NewIconFromCache = TRUE;
+ }
+ else
+ {
+ ERR("Failed getting a small icon for the class.\n");
+ }
+ }
+
+ if (Class->spicnSm)
+ {
+ if (Class->CSF_flags & CSF_CACHEDSMICON)
+ {
+ /* We must destroy the icon if we own it */
+ IntDestroyCurIconObject(Class->spicnSm);
+ Ret = 0;
+ }
+ else
+ {
+ Ret = (ULONG_PTR)UserHMGetHandle(Class->spicnSm);
+ }
+ UserDereferenceObject(Class->spicnSm);
+ }
+ else
+ {
+ Ret = 0;
+ }
+
+ if (NewIconFromCache)
+ Class->CSF_flags |= CSF_CACHEDSMICON;
+ else
+ Class->CSF_flags &= ~CSF_CACHEDSMICON;
+ Class->spicnSm = NewSmallIcon;
/* Update the clones */
Class = Class->pclsClone;
while (Class != NULL)
{
- Class->hIconSm = (HANDLE)NewLong;
+ if (Class->spicnSm)
+ UserDereferenceObject(Class->spicnSm);
+ if (NewSmallIcon)
+ UserReferenceObject(NewSmallIcon);
+ if (NewIconFromCache)
+ Class->CSF_flags |= CSF_CACHEDSMICON;
+ else
+ Class->CSF_flags &= ~CSF_CACHEDSMICON;
+ Class->spicnSm = NewSmallIcon;
Class = Class->pclsNext;
}
- break;
+ }
+ break;
case GCLP_HMODULE:
Ret = (ULONG_PTR)Class->hModule;
lpwcx->cbClsExtra = Class->cbclsExtra;
lpwcx->cbWndExtra = Class->cbwndExtra;
- lpwcx->hIcon = Class->hIcon; /* FIXME: Get handle from pointer */
- lpwcx->hCursor = Class->hCursor; /* FIXME: Get handle from pointer */
+ lpwcx->hIcon = Class->spicn ? UserHMGetHandle(Class->spicn) : NULL;
+ lpwcx->hCursor = Class->spcur ? UserHMGetHandle(Class->spcur) : NULL;
+ lpwcx->hIconSm = Class->spicnSm ? UserHMGetHandle(Class->spicnSm) : NULL;
lpwcx->hbrBackground = Class->hbrBackground;
/* Copy non-string to user first. */
/* FIXME: Return the string? Okay! This is performed in User32! */
//lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
- lpwcx->hIconSm = Class->hIconSm; /* FIXME: Get handle from pointer */
-
return TRUE;
}
//
-// ???
+// Register System Classes....
//
BOOL
FASTCALL
wc.cbClsExtra = 0;
wc.cbWndExtra = DefaultServerClasses[i].ExtraBytes;
wc.hIcon = NULL;
- wc.hCursor = DefaultServerClasses[i].hCursor;
+
+ //// System Cursors should be initilized!!!
+ wc.hCursor = NULL;
+ if (DefaultServerClasses[i].hCursor == (HICON)OCR_NORMAL)
+ {
+ if (SYSTEMCUR(ARROW) == NULL)
+ {
+ ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n");
+ }
+ else
+ {
+ wc.hCursor = UserHMGetHandle(SYSTEMCUR(ARROW));
+ }
+ }
+
hBrush = DefaultServerClasses[i].hBrush;
if (hBrush <= (HBRUSH)COLOR_MENUBAR)
{
UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
RTL_ATOM Ret = (RTL_ATOM)0;
PPROCESSINFO ppi = GetW32ProcessInfo();
+ BOOL Exception = FALSE;
if (Flags & ~(CSF_ANSIPROC))
{
}
TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("NtUserRegisterClassExWOW Exception Error!\n");
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Exception = TRUE;
+ }
+ _SEH2_END;
+ if (!Exception)
+ {
/* Register the class */
Ret = UserRegisterClass(&CapturedClassInfo,
&CapturedName,
fnID,
Flags);
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- ERR("NtUserRegisterClassExWOW Exception Error!\n");
- SetLastNtError(_SEH2_GetExceptionCode());
- }
- _SEH2_END;
-/*
+
if (!Ret)
{
- ERR("NtUserRegisterClassExWOW Null Return!\n");
+ TRACE("NtUserRegisterClassExWOW Null Return!\n");
}
- */
+
UserLeave();
return Ret;
Offset,
dwNewLong,
Ansi);
+ switch(Offset)
+ {
+ case GCLP_HICONSM:
+ case GCLP_HICON:
+ {
+ if (Ret && Ret != dwNewLong)
+ UserPaintCaption(Window, DC_ICON);
+ }
+ }
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
// If null instance use client.
if (!hInstance) hInstance = hModClient;
- TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
+ TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName, hInstance);
/* NOTE: Need exclusive lock because getting the wndproc might require the
creation of a call procedure handle */