[WIN32K / USER32]

Convert the window text string from UNICODE_STRING to LARGE_STRING and fix NtUserCreateWindowEx parameters. We currently still pass UNICODE only LARGE_STRINGs, as the rest of the code in win32k expects this.
Fixes display of large text windows, like the winzip license.
See issue #2900 for more details.

svn path=/trunk/; revision=47295
This commit is contained in:
Timo Kreuzer 2010-05-22 01:05:31 +00:00
parent c7ae2ad589
commit 709fe1efef
7 changed files with 260 additions and 145 deletions

View file

@ -137,6 +137,34 @@ CloseWindow(HWND hWnd)
return (BOOL)(hWnd);
}
VOID
FORCEINLINE
RtlInitLargeString(
OUT PLARGE_STRING plstr,
LPCVOID psz,
BOOL bUnicode)
{
if(bUnicode)
{
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)plstr, (PWSTR)psz, 0);
}
else
{
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)plstr, (PSTR)psz, 0);
}
}
VOID
NTAPI
RtlFreeLargeString(
IN PLARGE_STRING LargeString)
{
if (LargeString->Buffer)
{
RtlFreeHeap(GetProcessHeap(), 0, LargeString->Buffer);
RtlZeroMemory(LargeString, sizeof(LARGE_STRING));
}
}
HWND WINAPI
User32CreateWindowEx(DWORD dwExStyle,
@ -153,7 +181,8 @@ User32CreateWindowEx(DWORD dwExStyle,
LPVOID lpParam,
BOOL Unicode)
{
UNICODE_STRING WindowName;
LARGE_STRING WindowName;
LARGE_STRING lstrClassName, *plstrClassName;
UNICODE_STRING ClassName;
WNDCLASSEXA wceA;
WNDCLASSEXW wceW;
@ -171,8 +200,7 @@ User32CreateWindowEx(DWORD dwExStyle,
if (IS_ATOM(lpClassName))
{
RtlInitUnicodeString(&ClassName, NULL);
ClassName.Buffer = (LPWSTR)lpClassName;
plstrClassName = (PVOID)lpClassName;
}
else
{
@ -180,26 +208,49 @@ User32CreateWindowEx(DWORD dwExStyle,
RtlInitUnicodeString(&ClassName, (PCWSTR)lpClassName);
else
{
if (!RtlCreateUnicodeStringFromAsciiz(&(ClassName), (PCSZ)lpClassName))
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, (PCSZ)lpClassName))
{
SetLastError(ERROR_OUTOFMEMORY);
return (HWND)0;
}
}
/* Copy it to a LARGE_STRING */
lstrClassName.Buffer = ClassName.Buffer;
lstrClassName.Length = ClassName.Length;
lstrClassName.MaximumLength = ClassName.MaximumLength;
plstrClassName = &lstrClassName;
}
if (Unicode)
RtlInitUnicodeString(&WindowName, (PCWSTR)lpWindowName);
else
/* Initialize a LARGE_STRING */
RtlInitLargeString(&WindowName, lpWindowName, Unicode);
// HACK: The current implementation expects the Window name to be UNICODE
if (!Unicode)
{
if (!RtlCreateUnicodeStringFromAsciiz(&WindowName, (PCSZ)lpWindowName))
NTSTATUS Status;
PSTR AnsiBuffer = WindowName.Buffer;
ULONG AnsiLength = WindowName.Length;
WindowName.Length = 0;
WindowName.MaximumLength = AnsiLength * sizeof(WCHAR);
WindowName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
WindowName.MaximumLength);
if (!WindowName.Buffer)
{
if (!IS_ATOM(lpClassName))
{
RtlFreeUnicodeString(&ClassName);
}
SetLastError(ERROR_OUTOFMEMORY);
return (HWND)0;
goto cleanup;
}
Status = RtlMultiByteToUnicodeN(WindowName.Buffer,
WindowName.MaximumLength,
&WindowName.Length,
AnsiBuffer,
AnsiLength);
if (!NT_SUCCESS(Status))
{
goto cleanup;
}
}
@ -223,8 +274,11 @@ User32CreateWindowEx(DWORD dwExStyle,
}
}
if (!Unicode) dwExStyle |= WS_EX_SETANSICREATOR;
Handle = NtUserCreateWindowEx(dwExStyle,
&ClassName,
plstrClassName,
NULL,
&WindowName,
dwStyle,
x,
@ -235,23 +289,23 @@ User32CreateWindowEx(DWORD dwExStyle,
hMenu,
hInstance,
lpParam,
SW_SHOW,
Unicode,
0);
0,
NULL);
#if 0
DbgPrint("[window] NtUserCreateWindowEx() == %d\n", Handle);
#endif
cleanup:
if(!Unicode)
{
RtlFreeUnicodeString(&WindowName);
if (!IS_ATOM(lpClassName))
{
RtlFreeUnicodeString(&ClassName);
}
RtlFreeLargeString(&WindowName);
}
return Handle;
}

View file

@ -514,7 +514,7 @@ typedef struct _WND
HRGN hrgnClip;
HRGN hrgnNewFrame;
/* Window name. */
UNICODE_STRING strName;
LARGE_UNICODE_STRING strName;
/* Size of the extra data associated with the window. */
ULONG cbwndExtra;
HWND hWndLastActive;
@ -1469,31 +1469,12 @@ NtUserCreateLocalMemHandle(
DWORD Unknown2,
DWORD Unknown3);
HWND
NTAPI
NtUserCreateWindowEx(
DWORD dwExStyle,
PUNICODE_STRING lpClassName,
PUNICODE_STRING lpWindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
BOOL bUnicodeWindow,
DWORD dwUnknown);
#if 0
HWND
NTAPI
NtUserCreateWindowEx(
DWORD dwExStyle, // |= 0x80000000 == Ansi used to set WNDS_ANSICREATOR
PLARGE_STRING plstrClassName,
PLARGE_STRING plstrClsVesrion,
PLARGE_STRING plstrClsVersion,
PLARGE_STRING plstrWindowName,
DWORD dwStyle,
int x,
@ -1506,7 +1487,6 @@ NtUserCreateWindowEx(
LPVOID lpParam,
DWORD dwFlags,
PVOID acbiBuffer);
#endif
HWINSTA
NTAPI

View file

@ -155,7 +155,7 @@ IntDefWindowProc( PWINDOW_OBJECT Window, UINT Msg, WPARAM wParam, LPARAM lParam,
VOID FASTCALL IntNotifyWinEvent(DWORD, PWND, LONG, LONG);
PWND APIENTRY co_IntCreateWindowEx(DWORD,PUNICODE_STRING,PUNICODE_STRING,DWORD,LONG,LONG,LONG,LONG,HWND,HMENU,HINSTANCE,LPVOID,DWORD,BOOL);
PWND APIENTRY co_IntCreateWindowEx(DWORD,PUNICODE_STRING,PLARGE_STRING,DWORD,LONG,LONG,LONG,LONG,HWND,HMENU,HINSTANCE,LPVOID,DWORD,BOOL);
WNDPROC FASTCALL IntGetWindowProc(PWND,BOOL);
/* EOF */

View file

@ -882,7 +882,8 @@ NtUserCreateDesktop(
ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
HWINSTA hWindowStation = NULL ;
PUNICODE_STRING lpszDesktopName = NULL;
UNICODE_STRING ClassName, WindowName, MenuName;
UNICODE_STRING ClassName, MenuName;
LARGE_STRING WindowName;
PWND pWnd = NULL;
DECLARE_RETURN(HDESK);

View file

@ -171,7 +171,7 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non
NCCALCSIZE_PARAMS *PackedNcCalcsize;
CREATESTRUCTW *UnpackedCs;
CREATESTRUCTW *PackedCs;
PUNICODE_STRING WindowName;
PLARGE_STRING WindowName;
PUNICODE_STRING ClassName;
POOL_TYPE PoolType;
UINT Size;
@ -205,7 +205,7 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non
else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
{
UnpackedCs = (CREATESTRUCTW *) lParam;
WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
if (IS_ATOM(ClassName->Buffer))

View file

@ -1896,7 +1896,13 @@ BOOL UserDrawCaption(
if (str)
UserDrawCaptionText(hMemDc, str, &r, uFlags);
else if (pWnd != NULL)
UserDrawCaptionText(hMemDc, &pWnd->Wnd->strName, &r, uFlags);
{
UNICODE_STRING ustr;
ustr.Buffer = pWnd->Wnd->strName.Buffer;
ustr.Length = pWnd->Wnd->strName.Length;
ustr.MaximumLength = pWnd->Wnd->strName.MaximumLength;
UserDrawCaptionText(hMemDc, &ustr, &r, uFlags);
}
}
if(!NtGdiBitBlt(hDc, lpRc->left, lpRc->top,

View file

@ -1660,7 +1660,7 @@ IntCalcDefPosSize(PWINDOW_OBJECT Parent, RECTL *rc, BOOL IncPos)
PWND APIENTRY
co_IntCreateWindowEx(DWORD dwExStyle,
PUNICODE_STRING ClassName,
PUNICODE_STRING WindowName,
PLARGE_STRING WindowName,
DWORD dwStyle,
LONG x,
LONG y,
@ -2485,106 +2485,166 @@ CLEANUP:
END_CLEANUP;
}
HWND APIENTRY
NtUserCreateWindowEx(DWORD dwExStyle,
PUNICODE_STRING UnsafeClassName,
PUNICODE_STRING UnsafeWindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
BOOL bUnicodeWindow,
DWORD dwUnknown)
NTSTATUS
NTAPI
ProbeAndCaptureLargeString(
OUT PLARGE_STRING plstrSafe,
IN PLARGE_STRING plstrUnsafe)
{
NTSTATUS Status;
UNICODE_STRING WindowName;
UNICODE_STRING ClassName;
HWND NewWindow = NULL;
PWND pNewWindow;
DECLARE_RETURN(HWND);
LARGE_STRING lstrTemp;
PVOID pvBuffer = NULL;
DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
UserEnterExclusive();
_SEH2_TRY
{
/* Probe and copy the string */
ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
lstrTemp = *plstrUnsafe;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Fail */
_SEH2_YIELD(return _SEH2_GetExceptionCode();)
}
_SEH2_END
/* Get the class name (string or atom) */
Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( NULL);
}
if (ClassName.Length != 0)
{
Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( NULL);
}
}
else if (! IS_ATOM(ClassName.Buffer))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN(NULL);
}
if (lstrTemp.Length != 0)
{
/* Allocate a buffer from paged pool */
pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
if (!pvBuffer)
{
return STATUS_NO_MEMORY;
}
/* safely copy the window name */
if (NULL != UnsafeWindowName)
{
Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
if (! NT_SUCCESS(Status))
{
if (! IS_ATOM(ClassName.Buffer))
{
ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
}
SetLastNtError(Status);
RETURN( NULL);
}
}
else
{
RtlInitUnicodeString(&WindowName, NULL);
}
_SEH2_TRY
{
/* Probe and copy the buffer */
ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Cleanup and fail */
ExFreePool(pvBuffer);
_SEH2_YIELD(return _SEH2_GetExceptionCode();)
}
_SEH2_END
}
pNewWindow = co_IntCreateWindowEx( dwExStyle,
&ClassName,
&WindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam,
dwShowMode,
bUnicodeWindow);
/* Set the output string */
plstrSafe->Buffer = pvBuffer;
plstrSafe->Length = lstrTemp.Length;
plstrSafe->MaximumLength = lstrTemp.Length;
if (pNewWindow) NewWindow = UserHMGetHandle(pNewWindow);
return STATUS_SUCCESS;
}
if (WindowName.Buffer)
{
ExFreePoolWithTag(WindowName.Buffer, TAG_STRING);
}
if (! IS_ATOM(ClassName.Buffer))
{
ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
}
/**
* \todo Allow passing plstrClassName as ANSI.
*/
HWND
NTAPI
NtUserCreateWindowEx(
DWORD dwExStyle,
PLARGE_STRING plstrClassName,
PLARGE_STRING plstrClsVersion,
PLARGE_STRING plstrWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwFlags,
PVOID acbiBuffer)
{
NTSTATUS Status;
LARGE_STRING lstrWindowName;
LARGE_STRING lstrClassName;
UNICODE_STRING ustrClassName;
HWND hwnd = NULL;
PWND pwnd;
RETURN( NewWindow);
DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
UserEnterExclusive();
CLEANUP:
DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
lstrWindowName.Buffer = NULL;
lstrClassName.Buffer = NULL;
/* Check if we got a Window name */
if (plstrWindowName)
{
/* Copy the string to kernel mode */
Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
goto leave;
}
plstrWindowName = &lstrWindowName;
}
/* Check if the class is an atom */
if (IS_ATOM(plstrClassName))
{
/* It is, pass the atom in the UNICODE_STRING */
ustrClassName.Buffer = (PVOID)plstrClassName;
ustrClassName.Length = 0;
ustrClassName.MaximumLength = 0;
}
else
{
/* It's not, capture the class name */
Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
if (!NT_SUCCESS(Status))
{
/* Set last error, cleanup and return */
SetLastNtError(Status);
goto cleanup;
}
/* We pass it on as a UNICODE_STRING */
ustrClassName.Buffer = lstrClassName.Buffer;
ustrClassName.Length = lstrClassName.Length;
ustrClassName.MaximumLength = lstrClassName.MaximumLength;
}
/* Call the internal function */
pwnd = co_IntCreateWindowEx(dwExStyle,
&ustrClassName,
plstrWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam,
SW_SHOW,
!(dwExStyle & WS_EX_SETANSICREATOR));
hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
cleanup:
if (lstrWindowName.Buffer)
{
ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
}
if (lstrClassName.Buffer)
{
ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
}
leave:
DPRINT("Leave NtUserCreateWindowEx, hwnd=%i\n", hwnd);
UserLeave();
END_CLEANUP;
return hwnd;
}
/*
@ -2852,6 +2912,7 @@ IntFindWindow(PWINDOW_OBJECT Parent,
BOOL CheckWindowName;
HWND *List, *phWnd;
HWND Ret = NULL;
UNICODE_STRING CurrentWindowName;
ASSERT(Parent);
@ -2879,13 +2940,20 @@ IntFindWindow(PWINDOW_OBJECT Parent,
/* Do not send WM_GETTEXT messages in the kernel mode version!
The user mode version however calls GetWindowText() which will
send WM_GETTEXT messages to windows belonging to its processes */
if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->Wnd->strName), TRUE)) &&
(!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom))
if (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom)
{
Ret = Child->hSelf;
break;
// HACK: use UNICODE_STRING instead of LARGE_STRING
CurrentWindowName.Buffer = Child->Wnd->strName.Buffer;
CurrentWindowName.Length = Child->Wnd->strName.Length;
CurrentWindowName.MaximumLength = Child->Wnd->strName.MaximumLength;
if(!CheckWindowName ||
(Child->Wnd->strName.Length < 0xFFFF &&
!RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
{
Ret = Child->hSelf;
break;
}
}
}
ExFreePool(List);
}
@ -3042,6 +3110,8 @@ NtUserFindWindowEx(HWND hwndParent,
/* search children */
while(*phWnd)
{
UNICODE_STRING ustr;
if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
{
continue;
@ -3050,8 +3120,12 @@ NtUserFindWindowEx(HWND hwndParent,
/* Do not send WM_GETTEXT messages in the kernel mode version!
The user mode version however calls GetWindowText() which will
send WM_GETTEXT messages to windows belonging to its processes */
WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
&WindowName, &TopLevelWindow->Wnd->strName, TRUE);
ustr.Buffer = TopLevelWindow->Wnd->strName.Buffer;
ustr.Length = TopLevelWindow->Wnd->strName.Length;
ustr.MaximumLength = TopLevelWindow->Wnd->strName.MaximumLength;
WindowMatches = !CheckWindowName ||
(TopLevelWindow->Wnd->strName.Length < 0xFFFF &&
!RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;