reactos/win32ss/user/user32/windows/class.c
Timo Kreuzer 05cd3406e7 [USER32] Fix SetWindowWord/Long
These must use the corresponding NtUserSetWindowWord/Long function and cannot use NtUserSetWindowLongPtr, otherwise the function can fail, when there is only space for a LONG, but not for a LONG_PTR at the specified offset.
2023-05-25 18:56:02 +03:00

1809 lines
44 KiB
C

/*
* PROJECT: ReactOS user32.dll
* COPYRIGHT: GPL - See COPYING in the top level directory
* FILE: win32ss/user/user32/windows/class.c
* PURPOSE: Window classes
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* UPDATE HISTORY:
* 09-05-2001 CSH Created
*/
#include <user32.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
#define USE_VERSIONED_CLASSES
/* From rtl/actctx.c and must match! */
struct strsection_header
{
DWORD magic;
ULONG size;
DWORD unk1[3];
ULONG count;
ULONG index_offset;
DWORD unk2[2];
ULONG global_offset;
ULONG global_len;
};
struct wndclass_redirect_data
{
ULONG size;
DWORD res;
ULONG name_len;
ULONG name_offset; /* versioned name offset */
ULONG module_len;
ULONG module_offset;/* container name offset */
};
//
// Use wine hack to process extended context classes.
//
/***********************************************************************
* is_comctl32_class
*/
LPCWSTR is_comctl32_class( const WCHAR *name )
{
static const WCHAR classesW[][20] =
{
{'C','o','m','b','o','B','o','x','E','x','3','2',0},
{'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
{'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
{'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
{'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
{'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
{'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
{'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
{'S','y','s','A','n','i','m','a','t','e','3','2',0},
{'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
{'S','y','s','H','e','a','d','e','r','3','2',0},
{'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
{'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
{'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
{'S','y','s','P','a','g','e','r',0},
{'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
{'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
{'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
{'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
};
int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;
while (min <= max)
{
int res, pos = (min + max) / 2;
if (!(res = strcmpiW( name, classesW[pos] ))) return classesW[pos];
if (res < 0) max = pos - 1;
else min = pos + 1;
}
return NULL;
}
LPCWSTR
FASTCALL
ClassNameToVersion(
const void* lpszClass,
LPCWSTR lpszMenuName,
LPCWSTR *plpLibFileName,
HANDLE *pContext,
BOOL bAnsi)
{
LPCWSTR VersionedClass = NULL;
#ifdef USE_VERSIONED_CLASSES
NTSTATUS Status;
#endif
UNICODE_STRING SectionName;
WCHAR SectionNameBuf[MAX_PATH] = {0};
ACTCTX_SECTION_KEYED_DATA KeyedData = { sizeof(KeyedData) };
if (!lpszClass)
{
ERR("Null class given !\n");
return NULL;
}
if (IS_ATOM(lpszClass))
{
RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
if(!NtUserGetAtomName(LOWORD((DWORD_PTR)lpszClass), &SectionName))
{
ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR)lpszClass));
return NULL;
}
SectionName.Length = (USHORT)wcslen(SectionNameBuf) * sizeof(WCHAR);
TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName);
}
else
{
if (bAnsi)
{
ANSI_STRING AnsiString;
RtlInitAnsiString(&AnsiString, lpszClass);
RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
RtlAnsiStringToUnicodeString(&SectionName, &AnsiString, FALSE);
}
else
{
RtlInitUnicodeString(&SectionName, lpszClass);
}
}
#ifdef USE_VERSIONED_CLASSES
Status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
NULL,
ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
&SectionName,
&KeyedData );
if (NT_SUCCESS(Status) && KeyedData.ulDataFormatVersion == 1)
{
struct strsection_header *SectionHeader = KeyedData.lpSectionBase;
/* Find activation context */
if(SectionHeader && SectionHeader->count > 0)
{
struct wndclass_redirect_data *WindowRedirectionData = KeyedData.lpData;
if(WindowRedirectionData && WindowRedirectionData->module_len)
{
LPCWSTR lpLibFileName;
VersionedClass = (WCHAR*)((BYTE*)WindowRedirectionData + WindowRedirectionData->name_offset);
lpLibFileName = (WCHAR*)((BYTE*)KeyedData.lpSectionBase + WindowRedirectionData->module_offset);
TRACE("Returning VersionedClass=%S, plpLibFileName=%S for class %S\n", VersionedClass, lpLibFileName, SectionName.Buffer);
if (pContext) *pContext = KeyedData.hActCtx;
if (plpLibFileName) *plpLibFileName = lpLibFileName;
}
}
}
if (KeyedData.hActCtx)
RtlReleaseActivationContext(KeyedData.hActCtx);
#endif
#ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED
/* This block is a hack! */
if (!VersionedClass)
{
/*
* In windows the default activation context always contains comctl32v5
* In reactos we don't have a default activation context so we
* mimic wine here.
*/
VersionedClass = is_comctl32_class(SectionName.Buffer);
if (VersionedClass)
{
if (pContext) *pContext = 0;
if (plpLibFileName) *plpLibFileName = L"comctl32";
}
}
#endif
/*
* The returned strings are pointers in the activation context and
* will get freed when the activation context gets freed
*/
return VersionedClass;
}
//
// Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
//
BOOL
FASTCALL
VersionRegisterClass(
PCWSTR pszClass,
LPCWSTR lpLibFileName,
HANDLE Contex,
HMODULE * phLibModule)
{
BOOL Ret = FALSE;
HMODULE hLibModule = NULL;
PREGISTERCLASSNAMEW pRegisterClassNameW;
UNICODE_STRING ClassName;
WCHAR ClassNameBuf[MAX_PATH] = {0};
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame = { sizeof(Frame), 1 };
ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S.\n", lpLibFileName);
RtlActivateActivationContextUnsafeFast(&Frame, Contex);
_SEH2_TRY
{
hLibModule = LoadLibraryW(lpLibFileName);
if (hLibModule)
{
if ((pRegisterClassNameW = (void*)GetProcAddress(hLibModule, "RegisterClassNameW")))
{
if (IS_ATOM(pszClass))
{
RtlInitEmptyUnicodeString(&ClassName, ClassNameBuf, sizeof(ClassNameBuf));
if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
{
ERR("Error while verifying ATOM\n");
_SEH2_YIELD(goto Error_Exit);
}
pszClass = ClassName.Buffer;
}
Ret = pRegisterClassNameW(pszClass);
}
else
{
WARN("No RegisterClassNameW PROC\n");
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception while trying to call RegisterClassNameW!\n");
}
_SEH2_END
Error_Exit:
if (Ret || !hLibModule)
{
if (phLibModule) *phLibModule = hLibModule;
}
else
{
DWORD dwLastError = GetLastError();
FreeLibrary(hLibModule);
SetLastError(dwLastError);
}
RtlDeactivateActivationContextUnsafeFast(&Frame);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
GetClassInfoExA(
HINSTANCE hInstance,
LPCSTR lpszClass,
LPWNDCLASSEXA lpwcx)
{
UNICODE_STRING ClassName = {0};
LPCSTR pszMenuName;
HMODULE hLibModule = NULL;
DWORD dwLastError;
BOOL Ret, ClassFound = FALSE, ConvertedString = FALSE;
LPCWSTR lpszClsVersion;
HANDLE pCtx = NULL;
LPCWSTR lpLibFileName = NULL;
TRACE("%p class/atom: %s/%04x %p\n", hInstance,
IS_ATOM(lpszClass) ? NULL : lpszClass,
IS_ATOM(lpszClass) ? lpszClass : 0,
lpwcx);
if (!lpwcx)
{
SetLastError(ERROR_NOACCESS);
return FALSE;
}
if (hInstance == User32Instance)
{
hInstance = NULL;
}
if (lpszClass == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, TRUE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (IS_ATOM(lpszClass))
{
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
}
else
{
ConvertedString = TRUE;
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
if (!RegisterDefaultClasses)
{
TRACE("RegisterSystemControls\n");
RegisterSystemControls();
}
for(;;)
{
Ret = NtUserGetClassInfo(hInstance,
&ClassName,
(LPWNDCLASSEXW)lpwcx,
(LPWSTR *)&pszMenuName,
TRUE);
if (Ret) break;
if (!lpLibFileName) break;
if (!ClassFound)
{
dwLastError = GetLastError();
if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
{
ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue;
}
}
if (hLibModule)
{
dwLastError = GetLastError();
FreeLibrary(hLibModule);
SetLastError(dwLastError);
hLibModule = 0;
}
break;
}
if (Ret)
{
lpwcx->lpszClassName = lpszClass;
// lpwcx->lpszMenuName = pszMenuName;
}
if (ConvertedString)
{
RtlFreeUnicodeString(&ClassName);
}
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
GetClassInfoExW(
HINSTANCE hInstance,
LPCWSTR lpszClass,
LPWNDCLASSEXW lpwcx)
{
UNICODE_STRING ClassName = {0};
LPWSTR pszMenuName;
HMODULE hLibModule = NULL;
DWORD dwLastError;
BOOL Ret, ClassFound = FALSE;
LPCWSTR lpszClsVersion;
HANDLE pCtx = NULL;
LPCWSTR lpLibFileName = NULL;
TRACE("%p class/atom: %S/%04x %p\n", hInstance,
IS_ATOM(lpszClass) ? NULL : lpszClass,
IS_ATOM(lpszClass) ? lpszClass : 0,
lpwcx);
/* From wine, for speed only, ReactOS supports the correct return in
* Win32k. cbSize is ignored.
*/
if (!lpwcx)
{
SetLastError( ERROR_NOACCESS );
return FALSE;
}
if (hInstance == User32Instance)
{
hInstance = NULL;
}
if (lpszClass == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, FALSE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (IS_ATOM(lpszClass))
{
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
}
else
{
RtlInitUnicodeString(&ClassName, lpszClass);
}
if (!RegisterDefaultClasses)
{
TRACE("RegisterSystemControls\n");
RegisterSystemControls();
}
for(;;)
{
Ret = NtUserGetClassInfo( hInstance,
&ClassName,
lpwcx,
&pszMenuName,
FALSE);
if (Ret) break;
if (!lpLibFileName) break;
if (!ClassFound)
{
dwLastError = GetLastError();
if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
{
ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue;
}
}
if (hLibModule)
{
dwLastError = GetLastError();
FreeLibrary(hLibModule);
SetLastError(dwLastError);
hLibModule = 0;
}
break;
}
if (Ret)
{
lpwcx->lpszClassName = lpszClass;
// lpwcx->lpszMenuName = pszMenuName;
}
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
GetClassInfoA(
HINSTANCE hInstance,
LPCSTR lpClassName,
LPWNDCLASSA lpWndClass)
{
WNDCLASSEXA wcex;
BOOL retval;
retval = GetClassInfoExA(hInstance, lpClassName, &wcex);
if (retval)
{
lpWndClass->style = wcex.style;
lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
lpWndClass->cbClsExtra = wcex.cbClsExtra;
lpWndClass->cbWndExtra = wcex.cbWndExtra;
lpWndClass->hInstance = wcex.hInstance;
lpWndClass->hIcon = wcex.hIcon;
lpWndClass->hCursor = wcex.hCursor;
lpWndClass->hbrBackground = wcex.hbrBackground;
lpWndClass->lpszMenuName = wcex.lpszMenuName;
lpWndClass->lpszClassName = wcex.lpszClassName;
}
return retval;
}
/*
* @implemented
*/
BOOL
WINAPI
GetClassInfoW(
HINSTANCE hInstance,
LPCWSTR lpClassName,
LPWNDCLASSW lpWndClass)
{
WNDCLASSEXW wcex;
BOOL retval;
retval = GetClassInfoExW(hInstance, lpClassName, &wcex);
if (retval)
{
lpWndClass->style = wcex.style;
lpWndClass->lpfnWndProc = wcex.lpfnWndProc;
lpWndClass->cbClsExtra = wcex.cbClsExtra;
lpWndClass->cbWndExtra = wcex.cbWndExtra;
lpWndClass->hInstance = wcex.hInstance;
lpWndClass->hIcon = wcex.hIcon;
lpWndClass->hCursor = wcex.hCursor;
lpWndClass->hbrBackground = wcex.hbrBackground;
lpWndClass->lpszMenuName = wcex.lpszMenuName;
lpWndClass->lpszClassName = wcex.lpszClassName;
}
return retval;
}
//
// Based on find_winproc... Fixes many whine tests......
//
ULONG_PTR FASTCALL
IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi)
{
INT i;
ULONG_PTR gcpd, Ret = 0;
// If server side, sweep through proc list and return the client side proc.
if (Class->CSF_flags & CSF_SERVERSIDEPROC)
{ // Always scan through the list due to wine class "deftest".
for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
{
if (GETPFNSERVER(i) == Class->lpfnWndProc)
{
if (Ansi)
Ret = (ULONG_PTR)GETPFNCLIENTA(i);
else
Ret = (ULONG_PTR)GETPFNCLIENTW(i);
}
}
return Ret;
}
// Set return proc.
Ret = (ULONG_PTR)Class->lpfnWndProc;
// Return the proc if one of the FnId default class type.
if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
{
if (Ansi)
{ // If match return the right proc by type.
if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid);
}
else
{
if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid);
}
}
// Return on change or Ansi/Unicode proc equal.
if ( Ret != (ULONG_PTR)Class->lpfnWndProc ||
Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
return Ret;
/* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
This will force CallWindowProc to deal with it. */
gcpd = NtUserGetCPD( UserHMGetHandle(pWnd),
(Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWndtoCls,
Ret);
return (gcpd ? gcpd : Ret);
}
//
// Based on IntGetClsWndProc
//
WNDPROC FASTCALL
IntGetWndProc(PWND pWnd, BOOL Ansi)
{
INT i;
WNDPROC gcpd, Ret = 0;
PCLS Class = DesktopPtrToUser(pWnd->pcls);
if (!Class) return Ret;
if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
{
for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
{
if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
{
if (Ansi)
Ret = GETPFNCLIENTA(i);
else
Ret = GETPFNCLIENTW(i);
}
}
return Ret;
}
// Wine Class tests:
/* Edit controls are special - they return a wndproc handle when
GetWindowLongPtr is called with a different A/W.
On the other hand there is no W->A->W conversion so this control
is treated specially.
*/
if (Class->fnid == FNID_EDIT)
Ret = pWnd->lpfnWndProc;
else
{
// Set return proc.
Ret = pWnd->lpfnWndProc;
if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
{
if (Ansi)
{
if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
Ret = GETPFNCLIENTA(Class->fnid);
}
else
{
if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
Ret = GETPFNCLIENTW(Class->fnid);
}
}
// Return on the change.
if ( Ret != pWnd->lpfnWndProc)
return Ret;
}
if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
return Ret;
gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd),
(Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
(ULONG_PTR)Ret);
return (gcpd ? gcpd : Ret);
}
static ULONG_PTR FASTCALL
IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex)
{
ULONG_PTR Ret = 0;
if (nIndex >= 0)
{
if (nIndex + sizeof(ULONG_PTR) < nIndex ||
nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
{
SetLastError(ERROR_INVALID_PARAMETER);
}
else
Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
}
else
{
switch (nIndex)
{
case GCL_CBWNDEXTRA:
Ret = (ULONG_PTR)Class->cbwndExtra;
break;
case GCL_CBCLSEXTRA:
Ret = (ULONG_PTR)Class->cbclsExtra;
break;
case GCL_HBRBACKGROUND:
Ret = (ULONG_PTR)Class->hbrBackground;
if (Ret != 0 && Ret < 0x4000)
Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
break;
case GCL_HMODULE:
//ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
Ret = (ULONG_PTR)Class->hModule;
break;
case GCL_MENUNAME:
Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
break;
case GCL_STYLE:
Ret = (ULONG_PTR)Class->style;
break;
case GCW_ATOM:
Ret = (ULONG_PTR)Class->atomNVClassName;
break;
case GCLP_HCURSOR:
Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
break;
case GCLP_HICON:
Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
break;
case GCLP_HICONSM:
Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
break;
case GCLP_WNDPROC:
Ret = IntGetClsWndProc(Wnd, Class, TRUE);
break;
default:
SetLastError(ERROR_INVALID_INDEX);
break;
}
}
return Ret;
}
static ULONG_PTR FASTCALL
IntGetClassLongW(PWND Wnd, PCLS Class, int nIndex)
{
ULONG_PTR Ret = 0;
if (nIndex >= 0)
{
if (nIndex + sizeof(ULONG_PTR) < nIndex ||
nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
{
SetLastError(ERROR_INVALID_PARAMETER);
}
else
Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
}
else
{
switch (nIndex)
{
case GCL_CBWNDEXTRA:
Ret = (ULONG_PTR)Class->cbwndExtra;
break;
case GCL_CBCLSEXTRA:
Ret = (ULONG_PTR)Class->cbclsExtra;
break;
case GCLP_HBRBACKGROUND:
Ret = (ULONG_PTR)Class->hbrBackground;
if (Ret != 0 && Ret < 0x4000)
Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
break;
case GCL_HMODULE:
Ret = (ULONG_PTR)Class->hModule;
break;
case GCLP_MENUNAME:
Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
break;
case GCL_STYLE:
Ret = (ULONG_PTR)Class->style;
break;
case GCW_ATOM:
Ret = (ULONG_PTR)Class->atomNVClassName;
break;
case GCLP_HCURSOR:
Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
break;
case GCLP_HICON:
Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
break;
case GCLP_HICONSM:
Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
break;
case GCLP_WNDPROC:
Ret = IntGetClsWndProc(Wnd, Class, FALSE);
break;
default:
SetLastError(ERROR_INVALID_INDEX);
break;
}
}
return Ret;
}
/*
* @implemented
*/
DWORD WINAPI
GetClassLongA(HWND hWnd, int nIndex)
{
PWND Wnd;
PCLS Class;
ULONG_PTR Ret = 0;
TRACE("%p %d\n", hWnd, nIndex);
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
_SEH2_TRY
{
Class = DesktopPtrToUser(Wnd->pcls);
if (Class != NULL)
{
#ifdef _WIN64
switch (nIndex)
{
case GCLP_HBRBACKGROUND:
case GCLP_HCURSOR:
case GCLP_HICON:
case GCLP_HICONSM:
case GCLP_HMODULE:
case GCLP_MENUNAME:
case GCLP_WNDPROC:
SetLastError(ERROR_INVALID_INDEX);
break;
default:
Ret = IntGetClassLongA(Wnd, Class, nIndex);
break;
}
#else
Ret = IntGetClassLongA(Wnd, Class, nIndex);
#endif
}
else
{
WARN("Invalid class for hwnd 0x%p!\n", hWnd);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = 0;
}
_SEH2_END;
return (DWORD)Ret;
}
/*
* @implemented
*/
DWORD WINAPI
GetClassLongW(HWND hWnd, int nIndex)
{
PWND Wnd;
PCLS Class;
ULONG_PTR Ret = 0;
TRACE("%p %d\n", hWnd, nIndex);
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
_SEH2_TRY
{
Class = DesktopPtrToUser(Wnd->pcls);
if (Class != NULL)
{
#ifdef _WIN64
switch (nIndex)
{
case GCLP_HBRBACKGROUND:
case GCLP_HCURSOR:
case GCLP_HICON:
case GCLP_HICONSM:
case GCLP_HMODULE:
case GCLP_MENUNAME:
case GCLP_WNDPROC:
SetLastError(ERROR_INVALID_INDEX);
break;
default:
Ret = IntGetClassLongW(Wnd, Class, nIndex);
break;
}
#else
Ret = IntGetClassLongW(Wnd, Class, nIndex);
#endif
}
else
{
WARN("Invalid class for hwnd 0x%p!\n", hWnd);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = 0;
}
_SEH2_END;
return (DWORD)Ret;
}
#ifdef _WIN64
/*
* @implemented
*/
ULONG_PTR
WINAPI
GetClassLongPtrA(HWND hWnd,
INT nIndex)
{
PWND Wnd;
PCLS Class;
ULONG_PTR Ret = 0;
TRACE("%p %d\n", hWnd, nIndex);
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
_SEH2_TRY
{
Class = DesktopPtrToUser(Wnd->pcls);
if (Class != NULL)
{
Ret = IntGetClassLongA(Wnd, Class, nIndex);
}
else
{
WARN("Invalid class for hwnd 0x%p!\n", hWnd);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = 0;
}
_SEH2_END;
return Ret;
}
/*
* @implemented
*/
ULONG_PTR
WINAPI
GetClassLongPtrW(HWND hWnd,
INT nIndex)
{
PWND Wnd;
PCLS Class;
ULONG_PTR Ret = 0;
TRACE("%p %d\n", hWnd, nIndex);
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
_SEH2_TRY
{
Class = DesktopPtrToUser(Wnd->pcls);
if (Class != NULL)
{
Ret = IntGetClassLongW(Wnd, Class, nIndex);
}
else
{
WARN("Invalid class for hwnd 0x%p!\n", hWnd);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = 0;
}
_SEH2_END;
return Ret;
}
#endif
/*
* @implemented
*/
int WINAPI
GetClassNameA(
HWND hWnd,
LPSTR lpClassName,
int nMaxCount)
{
WCHAR tmpbuf[MAX_ATOM_LEN + 1];
int len;
if (nMaxCount <= 0) return 0;
if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
lpClassName[len] = 0;
TRACE("%p class/atom: %s/%04x %x\n", hWnd,
IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0,
nMaxCount);
return len;
}
/*
* @implemented
*/
int
WINAPI
GetClassNameW(
HWND hWnd,
LPWSTR lpClassName,
int nMaxCount)
{
UNICODE_STRING ClassName;
int Result;
RtlInitEmptyUnicodeString(&ClassName,
lpClassName,
nMaxCount * sizeof(WCHAR));
Result = NtUserGetClassName(hWnd,
FALSE,
&ClassName);
TRACE("%p class/atom: %S/%04x %x\n", hWnd,
IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0,
nMaxCount);
return Result;
}
/*
* @implemented
*/
WORD
WINAPI
GetClassWord(
HWND hwnd,
int offset)
{
PWND Wnd;
PCLS class;
WORD retvalue = 0;
if (offset < 0) return GetClassLongA( hwnd, offset );
Wnd = ValidateHwnd(hwnd);
if (!Wnd)
return 0;
class = DesktopPtrToUser(Wnd->pcls);
if (class == NULL) return 0;
if (offset <= class->cbclsExtra - sizeof(WORD))
memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
else
SetLastError( ERROR_INVALID_INDEX );
return retvalue;
}
LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
{
LONG_PTR retvalue = 0;
WND *wndPtr;
if (offset == GWLP_HWNDPARENT)
{
HWND parent = GetAncestor( hwnd, GA_PARENT );
if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
return (ULONG_PTR)parent;
}
if (!(wndPtr = ValidateHwnd( hwnd )))
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return 0;
}
if (offset >= 0 && wndPtr->fnid != FNID_DESKTOP)
{
if (offset > (int)(wndPtr->cbwndExtra - size))
{
WARN("Invalid offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
/* WINE: special case for dialog window procedure */
//if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
// retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
return retvalue;
}
switch(offset)
{
case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
case GWL_STYLE: retvalue = wndPtr->style; break;
case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
case GWLP_ID: retvalue = wndPtr->IDMenu; break;
case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
#if 0
/* -1 is an undocumented case which returns WW* */
/* source: http://www.geoffchappell.com/studies/windows/win32/user32/structs/wnd/index.htm*/
case -1: retvalue = (ULONG_PTR)&wndPtr->ww; break;
#else
/* We don't have a WW but WND already contains the same fields in the right order, */
/* so we can return a pointer to its first field */
case -1: retvalue = (ULONG_PTR)&wndPtr->state; break;
#endif
case GWLP_WNDPROC:
{
if (!TestWindowProcess(wndPtr))
{
SetLastError(ERROR_ACCESS_DENIED);
retvalue = 0;
ERR("Outside Access and Denied!\n");
break;
}
retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
break;
}
default:
WARN("Unknown offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
break;
}
return retvalue;
}
/*
* @implemented
*/
LONG
WINAPI
GetWindowLongA ( HWND hWnd, int nIndex )
{
return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
}
/*
* @implemented
*/
LONG
WINAPI
GetWindowLongW(HWND hWnd, int nIndex)
{
return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
}
#ifdef _WIN64
/*
* @implemented
*/
LONG_PTR
WINAPI
GetWindowLongPtrA(HWND hWnd,
INT nIndex)
{
return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
}
/*
* @implemented
*/
LONG_PTR
WINAPI
GetWindowLongPtrW(HWND hWnd,
INT nIndex)
{
return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
}
#endif // _WIN64
/*
* @implemented
*/
WORD
WINAPI
GetWindowWord(HWND hWnd, int nIndex)
{
switch(nIndex)
{
case GWLP_ID:
case GWLP_HINSTANCE:
case GWLP_HWNDPARENT:
break;
default:
if (nIndex < 0)
{
WARN("Invalid offset %d\n", nIndex );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
break;
}
return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
}
/*
* @implemented
*/
UINT
WINAPI
RealGetWindowClassW(
HWND hwnd,
LPWSTR pszType,
UINT cchType)
{
UNICODE_STRING ClassName;
RtlInitEmptyUnicodeString(&ClassName,
pszType,
cchType * sizeof(WCHAR));
return NtUserGetClassName(hwnd,TRUE,&ClassName);
}
/*
* @implemented
*/
UINT
WINAPI
RealGetWindowClassA(
HWND hwnd,
LPSTR pszType,
UINT cchType)
{
WCHAR tmpbuf[MAX_ATOM_LEN + 1];
UINT len;
if ((INT)cchType <= 0) return 0;
if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
pszType[len] = 0;
return len;
}
ATOM WINAPI
RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
LPDWORD pdwWowData,
WORD fnID,
DWORD dwFlags,
BOOL ChkRegCls)
{
ATOM Atom;
WNDCLASSEXW WndClass;
UNICODE_STRING ClassName;
UNICODE_STRING ClassVersion;
UNICODE_STRING MenuName = {0};
CLSMENUNAME clsMenuName;
ANSI_STRING AnsiMenuName;
LPCWSTR lpszClsVersion;
if (lpwcx == NULL || lpwcx->cbSize != sizeof(*lpwcx) ||
lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
lpwcx->lpszClassName == NULL)
{
TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (ChkRegCls)
{
if (!RegisterDefaultClasses) RegisterSystemControls();
}
/*
* On real Windows this looks more like:
* if (lpwcx->hInstance == User32Instance &&
* *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
* But since I have no idea what the magic field in the
* TEB structure means, I rather decided to omit that.
* -- Filip Navara
GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
*/
if (lpwcx->hInstance == User32Instance)
{
TRACE("RegisterClassExWOWW User32Instance!\n");
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
/* Yes, this is correct. We should modify the passed structure. */
if (lpwcx->hInstance == NULL)
((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0);
if (!IS_INTRESOURCE(WndClass.lpszMenuName))
{
if (WndClass.lpszMenuName[0])
{
RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
RtlUnicodeStringToAnsiString(&AnsiMenuName, &MenuName, TRUE);
}
}
else
{
MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
}
if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
{
RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
}
else
{
ClassName.Length = ClassName.MaximumLength = 0;
ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
}
ClassVersion = ClassName;
if (fnID == 0)
{
lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
}
}
clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
clsMenuName.pusMenuName = &MenuName;
Atom = NtUserRegisterClassExWOW(&WndClass,
&ClassName,
&ClassVersion,
&clsMenuName,
fnID,
dwFlags,
pdwWowData);
TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
return Atom;
}
/*
* @implemented
*/
ATOM WINAPI
RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
{
ATOM Atom;
WNDCLASSEXW WndClass;
WCHAR mname[MAX_BUFFER_LEN];
WCHAR cname[MAX_BUFFER_LEN];
C_ASSERT(sizeof(WndClass) == sizeof(*lpwcx));
RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
if (WndClass.lpszMenuName && !IS_INTRESOURCE(WndClass.lpszMenuName))
{
if (WndClass.lpszMenuName[0])
{
if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 ))
return 0;
WndClass.lpszMenuName = mname;
}
}
if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
{
if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 ))
return 0;
WndClass.lpszClassName = cname;
}
Atom = RegisterClassExWOWW(&WndClass,
NULL,
0,
CSF_ANSIPROC,
TRUE);
TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
return Atom;
}
/*
* @implemented
*/
ATOM WINAPI
RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
{
ATOM Atom;
Atom = RegisterClassExWOWW((WNDCLASSEXW *)lpwcx, NULL, 0, 0, TRUE);
TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
return Atom;
}
/*
* @implemented
*/
ATOM WINAPI
RegisterClassA(CONST WNDCLASSA *lpWndClass)
{
WNDCLASSEXA Class;
if (lpWndClass == NULL)
return 0;
/* These MUST be copied manually, since on 64 bit architectures the
alignment of the members is different between the 2 structs! */
Class.style = lpWndClass->style;
Class.lpfnWndProc = lpWndClass->lpfnWndProc;
Class.cbClsExtra = lpWndClass->cbClsExtra;
Class.cbWndExtra = lpWndClass->cbWndExtra;
Class.hInstance = lpWndClass->hInstance;
Class.hIcon = lpWndClass->hIcon;
Class.hCursor = lpWndClass->hCursor;
Class.hbrBackground = lpWndClass->hbrBackground;
Class.lpszMenuName = lpWndClass->lpszMenuName;
Class.lpszClassName = lpWndClass->lpszClassName;
Class.cbSize = sizeof(Class);
Class.hIconSm = NULL;
return RegisterClassExA(&Class);
}
/*
* @implemented
*/
ATOM WINAPI
RegisterClassW(CONST WNDCLASSW *lpWndClass)
{
WNDCLASSEXW Class;
if (lpWndClass == NULL)
return 0;
/* These MUST be copied manually, since on 64 bit architectures the
alignment of the members is different between the 2 structs! */
Class.style = lpWndClass->style;
Class.lpfnWndProc = lpWndClass->lpfnWndProc;
Class.cbClsExtra = lpWndClass->cbClsExtra;
Class.cbWndExtra = lpWndClass->cbWndExtra;
Class.hInstance = lpWndClass->hInstance;
Class.hIcon = lpWndClass->hIcon;
Class.hCursor = lpWndClass->hCursor;
Class.hbrBackground = lpWndClass->hbrBackground;
Class.lpszMenuName = lpWndClass->lpszMenuName;
Class.lpszClassName = lpWndClass->lpszClassName;
Class.cbSize = sizeof(Class);
Class.hIconSm = NULL;
return RegisterClassExW(&Class);
}
/*
* @implemented
*/
DWORD
WINAPI
SetClassLongA(HWND hWnd,
int nIndex,
LONG dwNewLong)
{
PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
UNICODE_STRING Value = {0};
BOOL Allocated = FALSE;
DWORD Ret;
/* FIXME - portability!!!! */
if (nIndex == GCL_MENUNAME && lpStr != NULL)
{
if (!IS_INTRESOURCE(lpStr))
{
if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
Allocated = TRUE;
}
else
{
Value.Buffer = (PWSTR)lpStr;
}
dwNewLong = (LONG_PTR)&Value;
}
else if (nIndex == GCW_ATOM && lpStr != NULL)
{
if (!IS_ATOM(lpStr))
{
if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
Allocated = TRUE;
}
else
{
Value.Buffer = (PWSTR)lpStr;
}
dwNewLong = (LONG_PTR)&Value;
}
Ret = (DWORD)NtUserSetClassLong(hWnd,
nIndex,
dwNewLong,
TRUE);
if (Allocated)
{
RtlFreeUnicodeString(&Value);
}
return Ret;
}
/*
* @implemented
*/
DWORD
WINAPI
SetClassLongW(HWND hWnd,
int nIndex,
LONG dwNewLong)
{
PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
UNICODE_STRING Value = {0};
TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
/* FIXME - portability!!!! */
if (nIndex == GCL_MENUNAME && lpStr != NULL)
{
if (!IS_INTRESOURCE(lpStr))
RtlInitUnicodeString(&Value, lpStr);
else
Value.Buffer = lpStr;
dwNewLong = (LONG_PTR)&Value;
}
else if (nIndex == GCW_ATOM && lpStr != NULL)
{
if (!IS_ATOM(lpStr))
RtlInitUnicodeString(&Value, lpStr);
else
Value.Buffer = lpStr;
dwNewLong = (LONG_PTR)&Value;
}
return (DWORD)NtUserSetClassLong(hWnd,
nIndex,
dwNewLong,
FALSE);
}
#ifdef _WIN64
/*
* @unimplemented
*/
ULONG_PTR
WINAPI
SetClassLongPtrA(HWND hWnd,
INT nIndex,
LONG_PTR dwNewLong)
{
UNIMPLEMENTED;
return 0;
}
/*
* @unimplemented
*/
ULONG_PTR
WINAPI
SetClassLongPtrW(HWND hWnd,
INT nIndex,
LONG_PTR dwNewLong)
{
UNIMPLEMENTED;
return 0;
}
#endif // _WIN64
/*
* @implemented
*/
WORD
WINAPI
SetClassWord(
HWND hWnd,
int nIndex,
WORD wNewWord)
/*
* NOTE: Obsoleted in 32-bit windows
*/
{
if ((nIndex < 0) && (nIndex != GCW_ATOM))
return 0;
return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
}
/*
* @implemented
*/
WORD
WINAPI
SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
{
switch(nIndex)
{
case GWLP_ID:
case GWLP_HINSTANCE:
case GWLP_HWNDPARENT:
break;
default:
if (nIndex < 0)
{
WARN("Invalid offset %d\n", nIndex );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
break;
}
/* DO NOT USE NtUserSetWindowLong(Ptr)! */
return NtUserSetWindowWord(hWnd, nIndex, wNewWord);
}
/*
* @implemented
*/
LONG
WINAPI
DECLSPEC_HOTPATCH
SetWindowLongA(
HWND hWnd,
int nIndex,
LONG dwNewLong)
{
/* DO NOT USE NtUserSetWindowLongPtr! */
return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
}
/*
* @implemented
*/
LONG
WINAPI
SetWindowLongW(
HWND hWnd,
int nIndex,
LONG dwNewLong)
{
/* DO NOT USE NtUserSetWindowLongPtr! */
return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
}
#ifdef _WIN64
/*
* @implemented
*/
LONG_PTR
WINAPI
SetWindowLongPtrA(HWND hWnd,
INT nIndex,
LONG_PTR dwNewLong)
{
return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE);
}
/*
* @implemented
*/
LONG_PTR
WINAPI
SetWindowLongPtrW(HWND hWnd,
INT nIndex,
LONG_PTR dwNewLong)
{
return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE);
}
#endif
/*
* @implemented
*/
BOOL
WINAPI
UnregisterClassA(
LPCSTR lpClassName,
HINSTANCE hInstance)
{
UNICODE_STRING ClassName = {0};
BOOL Ret;
LPCWSTR lpszClsVersion;
BOOL ConvertedString = FALSE;
TRACE("class/atom: %s/%04x %p\n",
IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0,
hInstance);
lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (!IS_ATOM(lpClassName))
{
ConvertedString = TRUE;
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
}
else
{
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
}
Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
if (ConvertedString)
RtlFreeUnicodeString(&ClassName);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
UnregisterClassW(
LPCWSTR lpClassName,
HINSTANCE hInstance)
{
UNICODE_STRING ClassName = {0};
LPCWSTR lpszClsVersion;
TRACE("class/atom: %S/%04x %p\n",
IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0,
hInstance);
lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (!IS_ATOM(lpClassName))
{
RtlInitUnicodeString(&ClassName, lpClassName);
}
else
{
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
}
return NtUserUnregisterClass(&ClassName, hInstance, 0);
}
/* EOF */