[WIN32SS] Implement windows class versioning, by Sylvain Deverre. CORE-11858 #comment Committed, thanks!

svn path=/trunk/; revision=72414
This commit is contained in:
Mark Jansen 2016-08-21 18:28:33 +00:00
parent 7e6c5db9a4
commit 8b95cbf0e2
4 changed files with 117 additions and 23 deletions

View file

@ -255,6 +255,9 @@ IntDestroyClass(IN OUT PCLS Class)
// comparisons, remove registration of the atom if not zeroed. // comparisons, remove registration of the atom if not zeroed.
if (Class->atomClassName) if (Class->atomClassName)
IntDeregisterClassAtom(Class->atomClassName); IntDeregisterClassAtom(Class->atomClassName);
// Dereference non-versioned class name
if (Class->atomNVClassName)
IntDeregisterClassAtom(Class->atomNVClassName);
if (Class->pdce) if (Class->pdce)
{ {
@ -423,22 +426,37 @@ IntSetClassAtom(IN OUT PCLS Class,
/* Update the base class first */ /* Update the base class first */
Class = Class->pclsBase; Class = Class->pclsBase;
if (ClassName->Length > 0)
if (!IntRegisterClassAtom(ClassName,
&Atom))
{ {
return FALSE; if (!IntRegisterClassAtom(ClassName,
&Atom))
{
ERR("RegisterClassAtom failed ! %x\n", EngGetLastError());
return FALSE;
}
}
else
{
if (IS_ATOM(ClassName->Buffer))
{
Atom = (ATOM)((ULONG_PTR)ClassName->Buffer & 0xffff); // XXX: are we missing refcount here ?
}
else
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
} }
IntDeregisterClassAtom(Class->atomClassName); IntDeregisterClassAtom(Class->atomNVClassName);
Class->atomClassName = Atom; Class->atomNVClassName = Atom;
/* Update the clones */ /* Update the clones */
Class = Class->pclsClone; Class = Class->pclsClone;
while (Class != NULL) while (Class != NULL)
{ {
Class->atomClassName = Atom; Class->atomNVClassName = Atom;
Class = Class->pclsNext; Class = Class->pclsNext;
} }
@ -1000,6 +1018,7 @@ PCLS
FASTCALL FASTCALL
IntCreateClass(IN CONST WNDCLASSEXW* lpwcx, IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
IN PUNICODE_STRING ClassName, IN PUNICODE_STRING ClassName,
IN PUNICODE_STRING ClassVersion,
IN PUNICODE_STRING MenuName, IN PUNICODE_STRING MenuName,
IN DWORD fnID, IN DWORD fnID,
IN DWORD dwFlags, IN DWORD dwFlags,
@ -1008,7 +1027,7 @@ IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
{ {
SIZE_T ClassSize; SIZE_T ClassSize;
PCLS Class = NULL; PCLS Class = NULL;
RTL_ATOM Atom; RTL_ATOM Atom, verAtom;
WNDPROC WndProc; WNDPROC WndProc;
PWSTR pszMenuName = NULL; PWSTR pszMenuName = NULL;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
@ -1023,6 +1042,14 @@ IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
return NULL; return NULL;
} }
if (!IntRegisterClassAtom(ClassVersion,
&verAtom))
{
ERR("Failed to register version class atom!\n");
IntDeregisterClassAtom(Atom);
return NULL;
}
ClassSize = sizeof(*Class) + lpwcx->cbClsExtra; ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
if (MenuName->Length != 0) if (MenuName->Length != 0)
{ {
@ -1054,7 +1081,8 @@ IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
Class->rpdeskParent = Desktop; Class->rpdeskParent = Desktop;
Class->pclsBase = Class; Class->pclsBase = Class;
Class->atomClassName = Atom; Class->atomClassName = verAtom;
Class->atomNVClassName = Atom;
Class->fnid = fnID; Class->fnid = fnID;
Class->CSF_flags = dwFlags; Class->CSF_flags = dwFlags;
@ -1181,6 +1209,7 @@ IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
Class); Class);
Class = NULL; Class = NULL;
IntDeregisterClassAtom(verAtom);
IntDeregisterClassAtom(Atom); IntDeregisterClassAtom(Atom);
} }
} }
@ -1193,12 +1222,13 @@ NoMem:
UserHeapFree(pszMenuName); UserHeapFree(pszMenuName);
IntDeregisterClassAtom(Atom); IntDeregisterClassAtom(Atom);
IntDeregisterClassAtom(verAtom);
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
} }
TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n", TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and version atom 0x%x and hInstance 0x%p, global %u\n",
Class, ClassName, Class->lpfnWndProc, Atom, Class->hModule, Class->Global); Class, ClassName, Class->lpfnWndProc, Atom, verAtom, Class->hModule, Class->Global);
return Class; return Class;
} }
@ -1429,6 +1459,7 @@ IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance, BOOL bDe
RTL_ATOM RTL_ATOM
UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx, UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
IN PUNICODE_STRING ClassName, IN PUNICODE_STRING ClassName,
IN PUNICODE_STRING ClassVersion,
IN PUNICODE_STRING MenuName, IN PUNICODE_STRING MenuName,
IN DWORD fnID, IN DWORD fnID,
IN DWORD dwFlags) IN DWORD dwFlags)
@ -1446,7 +1477,7 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
pi = pti->ppi; pi = pti->ppi;
// Need only to test for two conditions not four....... Fix more whine tests.... // Need only to test for two conditions not four....... Fix more whine tests....
if ( IntGetAtomFromStringOrAtom( ClassName, &ClassAtom) && if ( IntGetAtomFromStringOrAtom( ClassVersion, &ClassAtom) &&
ClassAtom != (RTL_ATOM)0 && ClassAtom != (RTL_ATOM)0 &&
!(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
{ {
@ -1481,6 +1512,7 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
Class = IntCreateClass(lpwcx, Class = IntCreateClass(lpwcx,
ClassName, ClassName,
ClassVersion,
MenuName, MenuName,
fnID, fnID,
dwFlags, dwFlags,
@ -1501,7 +1533,7 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
(void)InterlockedExchangePointer((PVOID*)List, (void)InterlockedExchangePointer((PVOID*)List,
Class); Class);
Ret = Class->atomClassName; Ret = Class->atomNVClassName;
} }
else else
{ {
@ -1624,7 +1656,7 @@ UserGetClassName(IN PCLS Class,
/* Query the class name */ /* Query the class name */
Status = RtlQueryAtomInAtomTable(gAtomTable, Status = RtlQueryAtomInAtomTable(gAtomTable,
Atom ? Atom : Class->atomClassName, Atom ? Atom : Class->atomNVClassName,
NULL, NULL,
NULL, NULL,
szTemp, szTemp,
@ -1658,7 +1690,7 @@ UserGetClassName(IN PCLS Class,
/* Query the atom name */ /* Query the atom name */
Status = RtlQueryAtomInAtomTable(gAtomTable, Status = RtlQueryAtomInAtomTable(gAtomTable,
Atom ? Atom : Class->atomClassName, Atom ? Atom : Class->atomNVClassName,
NULL, NULL,
NULL, NULL,
ClassName->Buffer, ClassName->Buffer,
@ -2165,7 +2197,7 @@ UserSetClassLongPtr(IN PCLS Class,
{ {
PUNICODE_STRING Value = (PUNICODE_STRING)NewLong; PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
Ret = (ULONG_PTR)Class->atomClassName; Ret = (ULONG_PTR)Class->atomNVClassName;
if (!IntSetClassAtom(Class, if (!IntSetClassAtom(Class,
Value)) Value))
{ {
@ -2318,6 +2350,7 @@ UserRegisterSystemClasses(VOID)
wc.hIconSm = NULL; wc.hIconSm = NULL;
Class = IntCreateClass( &wc, Class = IntCreateClass( &wc,
&ClassName,
&ClassName, &ClassName,
&MenuName, &MenuName,
DefaultServerClasses[i].fiId, DefaultServerClasses[i].fiId,
@ -2366,7 +2399,7 @@ NtUserRegisterClassExWOW(
*/ */
{ {
WNDCLASSEXW CapturedClassInfo = {0}; WNDCLASSEXW CapturedClassInfo = {0};
UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0}; UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0}, CapturedVersion = {0};
RTL_ATOM Ret = (RTL_ATOM)0; RTL_ATOM Ret = (RTL_ATOM)0;
PPROCESSINFO ppi = GetW32ProcessInfo(); PPROCESSINFO ppi = GetW32ProcessInfo();
BOOL Exception = FALSE; BOOL Exception = FALSE;
@ -2404,6 +2437,7 @@ NtUserRegisterClassExWOW(
sizeof(WNDCLASSEXW)); sizeof(WNDCLASSEXW));
CapturedName = ProbeForReadUnicodeString(ClassName); CapturedName = ProbeForReadUnicodeString(ClassName);
CapturedVersion = ProbeForReadUnicodeString(ClsNVersion);
ProbeForRead(pClassMenuName, ProbeForRead(pClassMenuName,
sizeof(CLSMENUNAME), sizeof(CLSMENUNAME),
@ -2439,6 +2473,21 @@ NtUserRegisterClassExWOW(
} }
} }
if (CapturedVersion.Length != 0)
{
ProbeForRead(CapturedVersion.Buffer,
CapturedVersion.Length,
sizeof(WCHAR));
}
else
{
if (!IS_ATOM(CapturedVersion.Buffer))
{
ERR("NtUserRegisterClassExWOW ClassName Error!\n");
goto InvalidParameter;
}
}
if (CapturedMenuName.Length != 0) if (CapturedMenuName.Length != 0)
{ {
ProbeForRead(CapturedMenuName.Buffer, ProbeForRead(CapturedMenuName.Buffer,
@ -2475,6 +2524,7 @@ InvalidParameter:
/* Register the class */ /* Register the class */
Ret = UserRegisterClass(&CapturedClassInfo, Ret = UserRegisterClass(&CapturedClassInfo,
&CapturedName, &CapturedName,
&CapturedVersion,
&CapturedMenuName, &CapturedMenuName,
fnID, fnID,
Flags); Flags);
@ -2520,7 +2570,18 @@ NtUserSetClassLong(HWND hWnd,
/* Probe the parameters */ /* Probe the parameters */
if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME) if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
{ {
Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong); /* FIXME: Resource ID can be passed directly without UNICODE_STRING ? */
if (IS_ATOM(dwNewLong))
{
Value.MaximumLength = 0;
Value.Length = 0;
Value.Buffer = (PWSTR)dwNewLong;
}
else
{
Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
}
if (Value.Length & 1) if (Value.Length & 1)
{ {
goto InvalidParameter; goto InvalidParameter;

View file

@ -2403,13 +2403,16 @@ NtUserCreateWindowEx(
NTSTATUS Status; NTSTATUS Status;
LARGE_STRING lstrWindowName; LARGE_STRING lstrWindowName;
LARGE_STRING lstrClassName; LARGE_STRING lstrClassName;
LARGE_STRING lstrClsVersion;
UNICODE_STRING ustrClassName; UNICODE_STRING ustrClassName;
UNICODE_STRING ustrClsVersion;
CREATESTRUCTW Cs; CREATESTRUCTW Cs;
HWND hwnd = NULL; HWND hwnd = NULL;
PWND pwnd; PWND pwnd;
lstrWindowName.Buffer = NULL; lstrWindowName.Buffer = NULL;
lstrClassName.Buffer = NULL; lstrClassName.Buffer = NULL;
lstrClsVersion.Buffer = NULL;
ASSERT(plstrWindowName); ASSERT(plstrWindowName);
@ -2461,6 +2464,32 @@ NtUserCreateWindowEx(
ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT); ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
} }
/* Check if the class version is an atom */
if (IS_ATOM(plstrClsVersion))
{
/* It is, pass the atom in the UNICODE_STRING */
ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
ustrClsVersion.Length = 0;
ustrClsVersion.MaximumLength = 0;
}
else
{
/* It's not, capture the class name */
Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
if (!NT_SUCCESS(Status))
{
ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
/* Set last error, cleanup and return */
SetLastNtError(Status);
goto cleanup;
}
/* We pass it on as a UNICODE_STRING */
ustrClsVersion.Buffer = lstrClsVersion.Buffer;
ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
}
/* Fill the CREATESTRUCTW */ /* Fill the CREATESTRUCTW */
/* we will keep here the original parameters */ /* we will keep here the original parameters */
Cs.style = dwStyle; Cs.style = dwStyle;
@ -2479,7 +2508,7 @@ NtUserCreateWindowEx(
UserEnterExclusive(); UserEnterExclusive();
/* Call the internal function */ /* Call the internal function */
pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer); pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer);
if(!pwnd) if(!pwnd)
{ {
@ -2498,6 +2527,10 @@ cleanup:
{ {
ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING); ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
} }
if (lstrClsVersion.Buffer)
{
ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
}
return hwnd; return hwnd;
} }

View file

@ -710,7 +710,7 @@ IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex)
break; break;
case GCW_ATOM: case GCW_ATOM:
Ret = (ULONG_PTR)Class->atomClassName; Ret = (ULONG_PTR)Class->atomNVClassName;
break; break;
case GCLP_HCURSOR: case GCLP_HCURSOR:
@ -784,7 +784,7 @@ IntGetClassLongW (PWND Wnd, PCLS Class, int nIndex)
break; break;
case GCW_ATOM: case GCW_ATOM:
Ret = (ULONG_PTR)Class->atomClassName; Ret = (ULONG_PTR)Class->atomNVClassName;
break; break;
case GCLP_HCURSOR: case GCLP_HCURSOR:
@ -1503,7 +1503,7 @@ RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
{ {
Atom = NtUserRegisterClassExWOW( &WndClass, Atom = NtUserRegisterClassExWOW( &WndClass,
&ClassName, &ClassName,
NULL, //PUNICODE_STRING ClsNVersion, &ClassName, //PUNICODE_STRING ClsNVersion,
&clsMenuName, &clsMenuName,
fnID, fnID,
dwFlags, dwFlags,

View file

@ -267,7 +267,7 @@ User32CreateWindowEx(DWORD dwExStyle,
{ {
Handle = NtUserCreateWindowEx(dwExStyle, Handle = NtUserCreateWindowEx(dwExStyle,
plstrClassName, plstrClassName,
NULL, plstrClassName,
&WindowName, &WindowName,
dwStyle, dwStyle,
x, x,