- Implement CaptureUnicodeStringOrAtom, which handles user mode class names or atoms, and use it in some places.
- Fix a number of format strings

svn path=/trunk/; revision=57023
This commit is contained in:
Timo Kreuzer 2012-08-01 23:52:43 +00:00
parent 6010f994bb
commit 8bfdfddcc7
2 changed files with 233 additions and 250 deletions

View file

@ -110,6 +110,72 @@ LookupFnIdToiCls(int FnId, int *iCls )
return FALSE;
}
_Must_inspect_result_
NTSTATUS
NTAPI
CaptureUnicodeStringOrAtom(
_Out_ PUNICODE_STRING pustrOut,
__in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe)
{
NTSTATUS Status = STATUS_SUCCESS;
/* Default to NULL */
pustrOut->Buffer = NULL;
_SEH2_TRY
{
ProbeForRead(pustrUnsafe, sizeof(UNICODE_STRING), 1);
/* Validate the string */
if ((pustrUnsafe->Length & 1) || (pustrUnsafe->Buffer == NULL))
{
/* This is not legal */
_SEH2_YIELD(return STATUS_INVALID_PARAMETER);
}
/* Check if this is an atom */
if (IS_ATOM(pustrUnsafe->Buffer))
{
/* Copy the atom, length is 0 */
pustrOut->MaximumLength = pustrOut->Length = 0;
pustrOut->Buffer = pustrUnsafe->Buffer;
}
else
{
/* Get the length, maximum length includes zero termination */
pustrOut->Length = pustrUnsafe->Length;
pustrOut->MaximumLength = pustrOut->Length + sizeof(WCHAR);
/* Allocate a buffer */
pustrOut->Buffer = ExAllocatePoolWithTag(PagedPool,
pustrOut->MaximumLength,
TAG_STRING);
if (!pustrOut->Buffer)
{
_SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
}
/* Copy the string and zero terminate it */
ProbeForRead(pustrUnsafe->Buffer, pustrOut->Length, 1);
RtlCopyMemory(pustrOut->Buffer, pustrUnsafe->Buffer, pustrOut->Length);
pustrOut->Buffer[pustrOut->Length / sizeof(WCHAR)] = L'\0';
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Check if we already allocated a buffer */
if (pustrOut->Buffer)
{
/* Free the buffer */
ExFreePoolWithTag(pustrOut->Buffer, TAG_STRING);
Status = _SEH2_GetExceptionCode();
}
}
_SEH2_END;
return Status;
}
/* WINDOWCLASS ***************************************************************/
static VOID
@ -503,7 +569,7 @@ IntGetClassForDesktop(IN OUT PCLS BaseClass,
/* Simply clone the class */
RtlCopyMemory( Class, BaseClass, ClassSize);
TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
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 */
if ( Class->hModule != hModClient &&
@ -511,7 +577,7 @@ IntGetClassForDesktop(IN OUT PCLS BaseClass,
Class->fnid >= FNID_BUTTON )
{
Class->hModule = hModClient;
TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class, Class->hModule);
TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class, Class->hModule);
}
/* Update some pointers and link the class */
@ -631,7 +697,7 @@ IntDereferenceClass(IN OUT PCLS Class,
{
ASSERT(Class->pclsBase == Class);
TRACE("IntDereferenceClass 0x%x\n", Class);
TRACE("IntDereferenceClass 0x%p\n", Class);
/* Check if there are clones of the class on other desktops,
link the first clone in if possible. If there are no clones
then leave the class on the desktop heap. It will get moved
@ -669,7 +735,7 @@ IntDereferenceClass(IN OUT PCLS Class,
}
else
{
TRACE("IntDereferenceClass1 0x%x\n", Class);
TRACE("IntDereferenceClass1 0x%p\n", Class);
/* Locate the cloned class and unlink it */
PrevLink = &BaseClass->pclsClone;
@ -1032,7 +1098,7 @@ NoMem:
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
Class, ClassName, Class->lpfnWndProc, Atom, Class->hModule, Class->Global);
return Class;
@ -1068,8 +1134,10 @@ IntFindClass(IN RTL_ATOM Atom,
}
BOOL
IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
OUT RTL_ATOM *Atom)
NTAPI
IntGetAtomFromStringOrAtom(
_In_ PUNICODE_STRING ClassName,
_Out_ RTL_ATOM *Atom)
{
BOOL Ret = FALSE;
@ -1079,6 +1147,8 @@ IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
PWSTR AtomName;
NTSTATUS Status;
*Atom = 0;
/* NOTE: Caller has to protect the call with SEH! */
if (ClassName->Length != 0)
@ -1134,11 +1204,12 @@ IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
}
RTL_ATOM
IntGetClassAtom(IN PUNICODE_STRING ClassName,
IN HINSTANCE hInstance OPTIONAL,
IN PPROCESSINFO pi OPTIONAL,
OUT PCLS *BaseClass OPTIONAL,
OUT PCLS **Link OPTIONAL)
IntGetClassAtom(
_In_ PUNICODE_STRING ClassName,
IN HINSTANCE hInstance OPTIONAL,
IN PPROCESSINFO pi OPTIONAL,
OUT PCLS *BaseClass OPTIONAL,
OUT PCLS **Link OPTIONAL)
{
RTL_ATOM Atom = (RTL_ATOM)0;
@ -1160,7 +1231,7 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
&pi->pclsPrivateList,
Link);
if (Class != NULL)
{ TRACE("Step 1: 0x%x\n",Class );
{ TRACE("Step 1: 0x%p\n",Class );
goto FoundClass;
}
@ -1171,7 +1242,7 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
&pi->pclsPublicList,
Link);
if (Class != NULL)
{ TRACE("Step 2: 0x%x 0x%x\n",Class, Class->hModule);
{ TRACE("Step 2: 0x%p 0x%p\n",Class, Class->hModule);
goto FoundClass;
}
@ -1181,7 +1252,7 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
&pi->pclsPrivateList,
Link);
if (Class != NULL)
{ TRACE("Step 3: 0x%x\n",Class );
{ TRACE("Step 3: 0x%p\n",Class );
goto FoundClass;
}
@ -1194,7 +1265,7 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
return (RTL_ATOM)0;
}else{TRACE("Step 4: 0x%x\n",Class );}
}else{TRACE("Step 4: 0x%p\n",Class );}
FoundClass:
*BaseClass = Class;
@ -1219,7 +1290,7 @@ IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance)
/* Check the class. */
TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName, hInstance);
TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName, hInstance);
ClassAtom = IntGetClassAtom(ClassName,
hInstance,
@ -1231,7 +1302,7 @@ IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance)
{
if (IS_ATOM(ClassName->Buffer))
{
ERR("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
ERR("Class 0x%p not found\n", ClassName->Buffer);
}
else
{
@ -1242,7 +1313,7 @@ IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance)
return NULL;
}
TRACE("Referencing Class 0x%x with atom 0x%x\n", Class, ClassAtom);
TRACE("Referencing Class 0x%p with atom 0x%x\n", Class, ClassAtom);
Class = IntReferenceClass(Class,
ClassLink,
pti->rpdesk);
@ -1287,7 +1358,7 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
if (Class != NULL && !Class->Global)
{
// Local class already exists
TRACE("Local Class 0x%p does already exist!\n", ClassAtom);
TRACE("Local Class 0x%x does already exist!\n", ClassAtom);
EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
return (RTL_ATOM)0;
}
@ -1301,7 +1372,7 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
if (Class != NULL && Class->Global)
{
TRACE("Global Class 0x%p does already exist!\n", ClassAtom);
TRACE("Global Class 0x%x does already exist!\n", ClassAtom);
EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
return (RTL_ATOM)0;
}
@ -1352,7 +1423,7 @@ UserUnregisterClass(IN PUNICODE_STRING ClassName,
pi = GetW32ProcessInfo();
TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName, hInstance);
TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName, hInstance);
/* NOTE: Accessing the buffer in ClassName may raise an exception! */
ClassAtom = IntGetClassAtom(ClassName,
@ -1371,7 +1442,7 @@ UserUnregisterClass(IN PUNICODE_STRING ClassName,
if (Class->cWndReferenceCount != 0 ||
Class->pclsClone != NULL)
{
TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class->cWndReferenceCount, Class->pclsClone);
TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class->cWndReferenceCount, Class->pclsClone);
EngSetLastError(ERROR_CLASS_HAS_WINDOWS);
return FALSE;
}
@ -1384,7 +1455,7 @@ UserUnregisterClass(IN PUNICODE_STRING ClassName,
if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
{
TRACE("Class 0x%x\n", Class);
TRACE("Class 0x%p\n", Class);
TRACE("UserUnregisterClass: Good Exit!\n");
/* Finally free the resources */
IntDestroyClass(Class);
@ -2184,196 +2255,135 @@ NtUserSetClassWord(
return(0);
}
BOOL APIENTRY
NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
IN HINSTANCE hInstance,
OUT PCLSMENUNAME pClassMenuName)
BOOL
APIENTRY
NtUserUnregisterClass(
IN PUNICODE_STRING ClassNameOrAtom,
IN HINSTANCE hInstance,
OUT PCLSMENUNAME pClassMenuName)
{
UNICODE_STRING CapturedClassName;
BOOL Ret = FALSE;
UNICODE_STRING SafeClassName;
NTSTATUS Status;
BOOL Ret;
Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom);
if (!NT_SUCCESS(Status))
{
ERR("Error capturing the class name\n");
SetLastNtError(Status);
return FALSE;
}
UserEnterExclusive();
_SEH2_TRY
{
/* Probe the paramters */
CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
if (CapturedClassName.Length & 1)
{
goto InvalidParameter;
}
if (CapturedClassName.Length != 0)
{
ProbeForRead(CapturedClassName.Buffer,
CapturedClassName.Length,
sizeof(WCHAR));
}
else
{
if (!IS_ATOM(CapturedClassName.Buffer))
{
InvalidParameter:
EngSetLastError(ERROR_INVALID_PARAMETER);
_SEH2_LEAVE;
}
}
/* Unregister the class */
Ret = UserUnregisterClass(&CapturedClassName,
hInstance,
NULL); // Null for now~
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
}
_SEH2_END;
/* Unregister the class */
Ret = UserUnregisterClass(&SafeClassName, hInstance, NULL); // Null for now~
UserLeave();
if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
return Ret;
}
/* NOTE: For system classes hInstance is not NULL here, but User32Instance */
BOOL APIENTRY
BOOL
APIENTRY
NtUserGetClassInfo(
HINSTANCE hInstance,
PUNICODE_STRING ClassName,
LPWNDCLASSEXW lpWndClassEx,
LPWSTR *ppszMenuName,
BOOL Ansi)
BOOL bAnsi)
{
UNICODE_STRING CapturedClassName, SafeClassName;
WNDCLASSEXW Safewcexw;
PCLS Class;
RTL_ATOM ClassAtom = 0;
PPROCESSINFO ppi;
BOOL Ret = TRUE;
UNICODE_STRING SafeClassName;
WNDCLASSEXW Safewcexw;
PCLS Class;
RTL_ATOM ClassAtom = 0;
PPROCESSINFO ppi;
BOOL Ret = TRUE;
NTSTATUS Status;
/* NOTE: Need exclusive lock because getting the wndproc might require the
creation of a call procedure handle */
UserEnterExclusive();
_SEH2_TRY
{
ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
ppi = GetW32ProcessInfo();
Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
if (!NT_SUCCESS(Status))
{
ERR("Error capturing the class name\n");
SetLastNtError(Status);
return FALSE;
}
if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
{
UserRegisterSystemClasses();
}
// If null instance use client.
if (!hInstance) hInstance = hModClient;
_SEH2_TRY
{
/* Probe the paramters */
CapturedClassName = ProbeForReadUnicodeString(ClassName);
TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
if (CapturedClassName.Length == 0)
{
TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
}
else
{
TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
}
/* NOTE: Need exclusive lock because getting the wndproc might require the
creation of a call procedure handle */
UserEnterExclusive();
if (CapturedClassName.Length & 1)
{
EngSetLastError(ERROR_INVALID_PARAMETER);
Ret = FALSE;
_SEH2_LEAVE;
}
ppi = GetW32ProcessInfo();
if (!(ppi->W32PF_flags & W32PF_CLASSESREGISTERED))
{
UserRegisterSystemClasses();
}
if (CapturedClassName.Length != 0)
{
ProbeForRead( CapturedClassName.Buffer,
CapturedClassName.Length,
sizeof(WCHAR));
ClassAtom = IntGetClassAtom(&SafeClassName,
hInstance,
ppi,
&Class,
NULL);
if (ClassAtom != (RTL_ATOM)0)
{
Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance);
}
else
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
Ret = FALSE;
}
RtlInitUnicodeString( &SafeClassName, CapturedClassName.Buffer);
UserLeave();
SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
SafeClassName.MaximumLength,
TAG_STRING);
RtlCopyMemory( SafeClassName.Buffer,
CapturedClassName.Buffer,
SafeClassName.MaximumLength);
}
else
{
if (!IS_ATOM(CapturedClassName.Buffer))
{
ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
EngSetLastError(ERROR_INVALID_PARAMETER);
if (Ret)
{
_SEH2_TRY
{
/* Emulate Function. */
if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
// From Wine:
/* We must return the atom of the class here instead of just TRUE. */
/* Undocumented behavior! Return the class atom as a BOOL! */
Ret = (BOOL)ClassAtom;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
Ret = FALSE;
_SEH2_LEAVE;
}
}
_SEH2_END;
}
SafeClassName.Buffer = CapturedClassName.Buffer;
SafeClassName.Length = 0;
SafeClassName.MaximumLength = 0;
}
if (!IS_ATOM(SafeClassName.Buffer))
ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
Ret = FALSE;
}
_SEH2_END;
// If null instance use client.
if (!hInstance) hInstance = hModClient;
if (Ret)
{
TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
ClassAtom = IntGetClassAtom( &SafeClassName,
hInstance,
ppi,
&Class,
NULL);
if (ClassAtom != (RTL_ATOM)0)
{
if (hInstance == NULL) hInstance = hModClient;
Ret = UserGetClassInfo( Class,
&Safewcexw,
Ansi,
hInstance);
}
else
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
Ret = FALSE;
}
}
_SEH2_TRY
{
if (Ret)
{
/* Emulate Function. */
if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
// From Wine:
/* We must return the atom of the class here instead of just TRUE. */
/* Undocumented behavior! Return the class atom as a BOOL! */
Ret = (BOOL)ClassAtom;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
Ret = FALSE;
}
_SEH2_END;
if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
UserLeave();
return Ret;
return Ret;
}
@ -2430,78 +2440,49 @@ NtUserGetClassName (IN HWND hWnd,
}
/* Return Pointer to Class structure. */
PCLS APIENTRY
NtUserGetWOWClass(HINSTANCE hInstance,
PUNICODE_STRING ClassName)
PCLS
APIENTRY
NtUserGetWOWClass(
HINSTANCE hInstance,
PUNICODE_STRING ClassName)
{
UNICODE_STRING SafeClassName;
PPROCESSINFO pi;
PCLS Class = NULL;
RTL_ATOM ClassAtom = 0;
BOOL Hit = FALSE;
UNICODE_STRING SafeClassName;
PPROCESSINFO pi;
PCLS Class = NULL;
RTL_ATOM ClassAtom = 0;
NTSTATUS Status;
UserEnterExclusive();
Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
if (!NT_SUCCESS(Status))
{
ERR("Error capturing the class name\n");
SetLastNtError(Status);
return FALSE;
}
pi = GetW32ProcessInfo();
UserEnterExclusive();
_SEH2_TRY
{
if (ClassName->Length != 0)
{
ProbeForRead( ClassName->Buffer,
ClassName->Length,
sizeof(WCHAR));
pi = GetW32ProcessInfo();
RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
SafeClassName.MaximumLength,
TAG_STRING);
RtlCopyMemory( SafeClassName.Buffer,
ClassName->Buffer,
SafeClassName.MaximumLength);
}
else
{
if (!IS_ATOM(ClassName->Buffer))
{
ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
Hit = TRUE;
}
else
{
SafeClassName.Buffer = ClassName->Buffer;
SafeClassName.Length = 0;
SafeClassName.MaximumLength = 0;
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
Hit = TRUE;
}
_SEH2_END;
if (!Hit)
{
ClassAtom = IntGetClassAtom( &SafeClassName,
hInstance,
pi,
&Class,
NULL);
if (!ClassAtom)
{
ClassAtom = IntGetClassAtom(&SafeClassName,
hInstance,
pi,
&Class,
NULL);
if (!ClassAtom)
{
EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
}
}
}
if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
UserLeave();
if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
UserLeave();
//
// Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
//
return Class;
return Class;
}
/* EOF */

View file

@ -48,8 +48,10 @@ UserAddCallProcToClass(IN OUT PCLS Class,
IN PCALLPROCDATA CallProc);
BOOL
IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
OUT RTL_ATOM *Atom);
NTAPI
IntGetAtomFromStringOrAtom(
_In_ PUNICODE_STRING ClassName,
_Out_ RTL_ATOM *Atom);
BOOL
IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,