-Fix a couple of cases where we use the versioned class atom instead of the non versioned one.

[USER32]
- Add support for versioned classes in RegisterClassExWOWW, GetClassInfoExW, GetClassInfoExA, UnregisterClassA, UnregisterClassW, and User32CreateWindowEx
- Make ClassNameToVersion return the name of the versioned class and the library name that implements it while preserving a hack that lets user32 know which classes are registered by comctl32 (this is needed because the default activation context doesn't contain the non versioned classes yet).
- Make VersionRegisterClass to load the specified library and make it register its classes which is used when the class is not registered yet but its manifest is active.

svn path=/trunk/; revision=73806
This commit is contained in:
Giannis Adamopoulos 2017-02-17 11:07:14 +00:00
parent ebf8247723
commit c607de714c
4 changed files with 263 additions and 262 deletions

View file

@ -2743,6 +2743,7 @@ NtUserGetClassInfo(
NULL); NULL);
if (ClassAtom != (RTL_ATOM)0) if (ClassAtom != (RTL_ATOM)0)
{ {
ClassAtom = Class->atomNVClassName;
Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance); Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance);
} }
else else

View file

@ -2807,7 +2807,7 @@ IntFindWindow(PWND Parent,
/* Do not send WM_GETTEXT messages in the kernel mode version! /* Do not send WM_GETTEXT messages in the kernel mode version!
The user mode version however calls GetWindowText() which will The user mode version however calls GetWindowText() which will
send WM_GETTEXT messages to windows belonging to its processes */ send WM_GETTEXT messages to windows belonging to its processes */
if (!ClassAtom || Child->pcls->atomClassName == ClassAtom) if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
{ {
// FIXME: LARGE_STRING truncated // FIXME: LARGE_STRING truncated
CurrentWindowName.Buffer = Child->strName.Buffer; CurrentWindowName.Buffer = Child->strName.Buffer;
@ -2999,7 +2999,7 @@ NtUserFindWindowEx(HWND hwndParent,
(TopLevelWindow->strName.Length < 0xFFFF && (TopLevelWindow->strName.Length < 0xFFFF &&
!RtlCompareUnicodeString(&WindowName, &ustr, TRUE)); !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
ClassMatches = (ClassAtom == (RTL_ATOM)0) || ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
ClassAtom == TopLevelWindow->pcls->atomClassName; ClassAtom == TopLevelWindow->pcls->atomNVClassName;
if (WindowMatches && ClassMatches) if (WindowMatches && ClassMatches)
{ {

View file

@ -13,177 +13,38 @@
#include <wine/debug.h> #include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32); WINE_DEFAULT_DEBUG_CHANNEL(user32);
#define USE_VERSIONED_CLASSES
/* From rtl/actctx.c and must match! */ /* From rtl/actctx.c and must match! */
struct entity struct strsection_header
{ {
DWORD kind; // Activation context type DWORD magic;
WCHAR *name; // Class name ULONG size;
WCHAR *clsid; // Not supported yet but needed for menu name. DWORD unk1[3];
ULONG count;
ULONG index_offset;
DWORD unk2[2];
ULONG global_offset;
ULONG global_len;
}; };
struct dll_redirect struct wndclass_redirect_data
{ {
WCHAR *name; // Dll name ULONG size;
WCHAR *hash; DWORD res;
DWORD Data; // Junk ULONG name_len;
ULONG name_offset; /* versioned name offset */
ULONG module_len;
ULONG module_offset;/* container name offset */
}; };
LPCWSTR
FASTCALL
ClassNameToVersion(
LPCTSTR lpszClass,
LPCWSTR lpszMenuName,
LPCWSTR *plpLibFileName,
HANDLE *pContext,
BOOL bAnsi)
{
NTSTATUS Status;
UNICODE_STRING SectionName;
WCHAR SeactionNameBuf[MAX_PATH] = {0};
ACTCTX_SECTION_KEYED_DATA KeyedData = { sizeof(KeyedData) };
if (IS_ATOM(lpszClass))
{
SectionName.Buffer = (LPWSTR)&SeactionNameBuf;
SectionName.MaximumLength = sizeof(SeactionNameBuf);
if(!NtUserGetAtomName(LOWORD((DWORD_PTR)lpszClass), &SectionName))
{
return NULL;
}
}
else
{
if (bAnsi)
{
RtlCreateUnicodeStringFromAsciiz(&SectionName, (LPSTR)lpszClass);
}
else
{
RtlInitUnicodeString(&SectionName, lpszClass);
}
}
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 dll_redirect *dll = KeyedData.lpSectionBase;
if (plpLibFileName) *plpLibFileName = dll->name;
if (lpszMenuName)
{
WCHAR * mnubuf;
LPWSTR mnuNameW;
LPSTR mnuNameA;
int len = 0;
struct entity *entity = KeyedData.lpData;
FIXME("actctx: Needs to support menu name from redirected class!");
if (entity->clsid)
{
mnubuf = entity->clsid;
if (bAnsi)
{
mnuNameA = (LPSTR)lpszMenuName;
RtlUnicodeToMultiByteN( mnuNameA, 255, (PULONG)&len, mnubuf, strlenW(mnubuf) * sizeof(WCHAR) );
mnuNameA[len] = 0;
}
else
{
mnuNameW = (LPWSTR)lpszMenuName;
len = strlenW(mnubuf) * sizeof(WCHAR);
RtlCopyMemory((void *)mnuNameW, mnubuf, len);
mnuNameW[len] = 0;
}
}
}
if (pContext) *pContext = KeyedData.hActCtx;
}
if (!IS_ATOM(lpszClass) && bAnsi)
RtlFreeUnicodeString(&SectionName);
if (KeyedData.hActCtx)
RtlReleaseActivationContext(KeyedData.hActCtx);
return lpszClass;
}
// //
// Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html // Use wine hack to process extended context classes.
//
BOOL
FASTCALL
Real_VersionRegisterClass(
PCWSTR pszClass,
LPCWSTR lpLibFileName,
HANDLE Contex,
HMODULE * phLibModule)
{
BOOL Ret;
HMODULE hLibModule;
PREGISTERCLASSNAMEW pRegisterClassNameW;
UNICODE_STRING ClassName;
WCHAR ClassNameBuf[MAX_PATH] = {0};
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame = { sizeof(Frame), 1 };
RtlActivateActivationContextUnsafeFast(&Frame, Contex);
Ret = FALSE;
hLibModule = NULL;
_SEH2_TRY
{
hLibModule = LoadLibraryW(lpLibFileName);
if ( hLibModule )
{
if ((pRegisterClassNameW = (void*) GetProcAddress(hLibModule, "RegisterClassNameW")))
{
if (IS_ATOM(pszClass))
{
ClassName.Buffer = (LPWSTR)&ClassNameBuf;
ClassName.MaximumLength = sizeof(ClassNameBuf);
if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
{
_SEH2_YIELD(goto Error_Exit);
}
pszClass = (PCWSTR)&ClassNameBuf;
}
Ret = pRegisterClassNameW(pszClass);
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
_SEH2_END
Error_Exit:
if ( Ret || !hLibModule )
{
if ( phLibModule ) *phLibModule = hLibModule;
}
else
{
DWORD save_error = GetLastError();
FreeLibrary(hLibModule);
SetLastError(save_error);
}
return Ret;
}
//
// Use wine hack to process extened context classes.
// //
/*********************************************************************** /***********************************************************************
* is_comctl32_class * is_comctl32_class
*/ */
static BOOL is_comctl32_class( const WCHAR *name ) LPCWSTR is_comctl32_class( const WCHAR *name )
{ {
static const WCHAR classesW[][20] = static const WCHAR classesW[][20] =
{ {
@ -213,13 +74,121 @@ static BOOL is_comctl32_class( const WCHAR *name )
while (min <= max) while (min <= max)
{ {
int res, pos = (min + max) / 2; int res, pos = (min + max) / 2;
if (!(res = strcmpiW( name, classesW[pos] ))) return TRUE; if (!(res = strcmpiW( name, classesW[pos] ))) return classesW[pos];
if (res < 0) max = pos - 1; if (res < 0) max = pos - 1;
else min = pos + 1; else min = pos + 1;
} }
return FALSE; return NULL;
} }
LPCWSTR
FASTCALL
ClassNameToVersion(
const void* lpszClass,
LPCWSTR lpszMenuName,
LPCWSTR *plpLibFileName,
HANDLE *pContext,
BOOL bAnsi)
{
LPCWSTR VersionedClass = NULL;
NTSTATUS Status;
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 = 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);
}
}
Status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
NULL,
ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
&SectionName,
&KeyedData );
#ifdef USE_VERSIONED_CLASSES
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 BOOL
FASTCALL FASTCALL
VersionRegisterClass( VersionRegisterClass(
@ -228,64 +197,61 @@ VersionRegisterClass(
HANDLE Contex, HANDLE Contex,
HMODULE * phLibModule) HMODULE * phLibModule)
{ {
// Should be lpLibFileName..... BOOL Ret = FALSE;
static const WCHAR comctl32W[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0}; HMODULE hLibModule = NULL;
//
PREGISTERCLASSNAMEW pRegisterClassNameW; PREGISTERCLASSNAMEW pRegisterClassNameW;
UNICODE_STRING ClassName; UNICODE_STRING ClassName;
WCHAR ClassNameBuf[MAX_PATH] = {0}; WCHAR ClassNameBuf[MAX_PATH] = {0};
BOOL Ret = FALSE; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame = { sizeof(Frame), 1 };
HMODULE hLibModule = NULL;
if (!IS_ATOM(pszClass) && is_comctl32_class( pszClass )) RtlActivateActivationContextUnsafeFast(&Frame, Contex);
_SEH2_TRY
{ {
_SEH2_TRY hLibModule = LoadLibraryW(lpLibFileName);
if ( hLibModule )
{ {
hLibModule = LoadLibraryW(comctl32W); if ((pRegisterClassNameW = (void*) GetProcAddress(hLibModule, "RegisterClassNameW")))
if ( hLibModule )
{ {
if ((pRegisterClassNameW = (void*) GetProcAddress(hLibModule, "RegisterClassNameW"))) if (IS_ATOM(pszClass))
{ {
if (IS_ATOM(pszClass)) ClassName.Buffer = ClassNameBuf;
ClassName.MaximumLength = sizeof(ClassNameBuf);
if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
{ {
ClassName.Buffer = (LPWSTR)&ClassNameBuf; ERR("Error while verifying ATOM\n");
ClassName.MaximumLength = sizeof(ClassNameBuf); _SEH2_YIELD(goto Error_Exit);
if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
{
ERR("Error while verifying ATOM\n");
_SEH2_YIELD(goto Error_Exit);
}
pszClass = (PCWSTR)&ClassNameBuf;
} }
Ret = pRegisterClassNameW(pszClass); pszClass = ClassName.Buffer;
} }
Ret = pRegisterClassNameW(pszClass);
}
else
{
WARN("No RegisterClassNameW PROC\n");
} }
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) }
{ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
} {
_SEH2_END }
_SEH2_END
Error_Exit: Error_Exit:
if ( Ret || !hLibModule ) if ( Ret || !hLibModule )
{ {
if ( phLibModule ) *phLibModule = hLibModule; if ( phLibModule ) *phLibModule = hLibModule;
}
else
{
DWORD save_error = GetLastError();
FreeLibrary(hLibModule);
SetLastError(save_error);
}
TRACE( "%s retrying after loading comctl32\n", debugstr_w(pszClass) );
return Ret;
} }
TRACE("NO ComCtl32 Class %S!\n",pszClass); else
return FALSE; {
DWORD save_error = GetLastError();
FreeLibrary(hLibModule);
SetLastError(save_error);
}
RtlDeactivateActivationContextUnsafeFast(&Frame);
return Ret;
} }
//
//
//
/* /*
* @implemented * @implemented
@ -301,7 +267,10 @@ GetClassInfoExA(
LPCSTR pszMenuName; LPCSTR pszMenuName;
HMODULE hLibModule = NULL; HMODULE hLibModule = NULL;
DWORD save_error; DWORD save_error;
BOOL Ret, ClassFound = FALSE; BOOL Ret, ClassFound = FALSE, ConvertedString = FALSE;
LPCWSTR lpszClsVersion;
HANDLE pCtx = NULL;
LPCWSTR lpLibFileName = NULL;
TRACE("%p class/atom: %s/%04x %p\n", hInstance, TRACE("%p class/atom: %s/%04x %p\n", hInstance,
IS_ATOM(lpszClass) ? NULL : lpszClass, IS_ATOM(lpszClass) ? NULL : lpszClass,
@ -325,14 +294,19 @@ GetClassInfoExA(
return FALSE; return FALSE;
} }
if (IS_ATOM(lpszClass)) lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, TRUE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (IS_ATOM(lpszClass))
{ {
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass); ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
} }
else else
{ {
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, ConvertedString = TRUE;
lpszClass)) if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass))
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE; return FALSE;
@ -353,13 +327,14 @@ GetClassInfoExA(
(LPWSTR *)&pszMenuName, (LPWSTR *)&pszMenuName,
TRUE); TRUE);
if (Ret) break; if (Ret) break;
if (!lpLibFileName) break;
if (!ClassFound) if (!ClassFound)
{ {
save_error = GetLastError(); save_error = GetLastError();
if ( save_error == ERROR_CANNOT_FIND_WND_CLASS || if ( save_error == ERROR_CANNOT_FIND_WND_CLASS ||
save_error == ERROR_CLASS_DOES_NOT_EXIST ) save_error == ERROR_CLASS_DOES_NOT_EXIST )
{ {
ClassFound = VersionRegisterClass(ClassName.Buffer, NULL, NULL, &hLibModule); ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue; if (ClassFound) continue;
} }
} }
@ -379,7 +354,7 @@ GetClassInfoExA(
// lpwcx->lpszMenuName = pszMenuName; // lpwcx->lpszMenuName = pszMenuName;
} }
if (!IS_ATOM(lpszClass)) if (ConvertedString)
{ {
RtlFreeUnicodeString(&ClassName); RtlFreeUnicodeString(&ClassName);
} }
@ -403,6 +378,9 @@ GetClassInfoExW(
HMODULE hLibModule = NULL; HMODULE hLibModule = NULL;
DWORD save_error; DWORD save_error;
BOOL Ret, ClassFound = FALSE; BOOL Ret, ClassFound = FALSE;
LPCWSTR lpszClsVersion;
HANDLE pCtx = NULL;
LPCWSTR lpLibFileName = NULL;
TRACE("%p class/atom: %S/%04x %p\n", hInstance, TRACE("%p class/atom: %S/%04x %p\n", hInstance,
IS_ATOM(lpszClass) ? NULL : lpszClass, IS_ATOM(lpszClass) ? NULL : lpszClass,
@ -429,14 +407,18 @@ GetClassInfoExW(
return FALSE; return FALSE;
} }
if (IS_ATOM(lpszClass)) lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, FALSE);
if (lpszClsVersion)
{
RtlInitUnicodeString(&ClassName, lpszClsVersion);
}
else if (IS_ATOM(lpszClass))
{ {
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass); ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
} }
else else
{ {
RtlInitUnicodeString(&ClassName, RtlInitUnicodeString(&ClassName, lpszClass);
lpszClass);
} }
if (!RegisterDefaultClasses) if (!RegisterDefaultClasses)
@ -453,13 +435,14 @@ GetClassInfoExW(
&pszMenuName, &pszMenuName,
FALSE); FALSE);
if (Ret) break; if (Ret) break;
if (!lpLibFileName) break;
if (!ClassFound) if (!ClassFound)
{ {
save_error = GetLastError(); save_error = GetLastError();
if ( save_error == ERROR_CANNOT_FIND_WND_CLASS || if ( save_error == ERROR_CANNOT_FIND_WND_CLASS ||
save_error == ERROR_CLASS_DOES_NOT_EXIST ) save_error == ERROR_CLASS_DOES_NOT_EXIST )
{ {
ClassFound = VersionRegisterClass(ClassName.Buffer, NULL, NULL, &hLibModule); ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue; if (ClassFound) continue;
} }
} }
@ -1419,12 +1402,11 @@ RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
ATOM Atom; ATOM Atom;
WNDCLASSEXW WndClass; WNDCLASSEXW WndClass;
UNICODE_STRING ClassName; UNICODE_STRING ClassName;
UNICODE_STRING ClassVersion;
UNICODE_STRING MenuName = {0}; UNICODE_STRING MenuName = {0};
CLSMENUNAME clsMenuName; CLSMENUNAME clsMenuName;
ANSI_STRING AnsiMenuName; ANSI_STRING AnsiMenuName;
HMODULE hLibModule = NULL; LPCWSTR lpszClsVersion;
DWORD save_error;
BOOL ClassFound = FALSE;
if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) || if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 || lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
@ -1495,40 +1477,27 @@ RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
RtlInitUnicodeString(&ClassName, WndClass.lpszClassName); RtlInitUnicodeString(&ClassName, 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.pszClientAnsiMenuName = AnsiMenuName.Buffer;
clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer; clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
clsMenuName.pusMenuName = &MenuName; clsMenuName.pusMenuName = &MenuName;
for(;;) Atom = NtUserRegisterClassExWOW( &WndClass,
{ &ClassName,
Atom = NtUserRegisterClassExWOW( &WndClass, &ClassVersion,
&ClassName, &clsMenuName,
&ClassName, //PUNICODE_STRING ClsNVersion, fnID,
&clsMenuName, dwFlags,
fnID, pdwWowData);
dwFlags,
pdwWowData);
if (Atom) break;
if (!ClassFound)
{
save_error = GetLastError();
if ( save_error == ERROR_CANNOT_FIND_WND_CLASS ||
save_error == ERROR_CLASS_DOES_NOT_EXIST )
{
ClassFound = VersionRegisterClass(ClassName.Buffer, NULL, NULL, &hLibModule);
if (ClassFound) continue;
}
}
if (hLibModule)
{
save_error = GetLastError();
FreeLibrary(hLibModule);
SetLastError(save_error);
hLibModule = 0;
}
break;
}
TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n", 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, Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
@ -1886,16 +1855,23 @@ UnregisterClassA(
{ {
UNICODE_STRING ClassName = {0}; UNICODE_STRING ClassName = {0};
BOOL Ret; BOOL Ret;
LPCWSTR lpszClsVersion;
BOOL ConvertedString = FALSE;
TRACE("class/atom: %s/%04x %p\n", TRACE("class/atom: %s/%04x %p\n",
IS_ATOM(lpClassName) ? NULL : lpClassName, IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0, IS_ATOM(lpClassName) ? lpClassName : 0,
hInstance); hInstance);
if (!IS_ATOM(lpClassName)) lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
if (lpszClsVersion)
{ {
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, RtlInitUnicodeString(&ClassName, lpszClsVersion);
lpClassName)) }
else if (!IS_ATOM(lpClassName))
{
ConvertedString = TRUE;
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName))
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0; return 0;
@ -1904,11 +1880,9 @@ UnregisterClassA(
else else
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
Ret = NtUserUnregisterClass(&ClassName, Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
hInstance,
0);
if (!IS_ATOM(lpClassName)) if (ConvertedString)
RtlFreeUnicodeString(&ClassName); RtlFreeUnicodeString(&ClassName);
return Ret; return Ret;
@ -1925,23 +1899,28 @@ UnregisterClassW(
HINSTANCE hInstance) HINSTANCE hInstance)
{ {
UNICODE_STRING ClassName = {0}; UNICODE_STRING ClassName = {0};
LPCWSTR lpszClsVersion;
TRACE("class/atom: %S/%04x %p\n", TRACE("class/atom: %S/%04x %p\n",
IS_ATOM(lpClassName) ? NULL : lpClassName, IS_ATOM(lpClassName) ? NULL : lpClassName,
IS_ATOM(lpClassName) ? lpClassName : 0, IS_ATOM(lpClassName) ? lpClassName : 0,
hInstance); hInstance);
if (!IS_ATOM(lpClassName)) lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
if (lpszClsVersion)
{ {
RtlInitUnicodeString(&ClassName, RtlInitUnicodeString(&ClassName, lpszClsVersion);
lpClassName); }
else if (!IS_ATOM(lpClassName))
{
RtlInitUnicodeString(&ClassName, lpClassName);
} }
else else
{
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
}
return NtUserUnregisterClass(&ClassName, return NtUserUnregisterClass(&ClassName, hInstance, 0);
hInstance,
0);
} }
/* EOF */ /* EOF */

View file

@ -16,6 +16,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(user32); WINE_DEFAULT_DEBUG_CHANNEL(user32);
void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id ); void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id );
extern LPCWSTR FASTCALL ClassNameToVersion(const void *lpszClass, LPCWSTR lpszMenuName, LPCWSTR *plpLibFileName, HANDLE *pContext, BOOL bAnsi);
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
@ -165,13 +166,18 @@ User32CreateWindowEx(DWORD dwExStyle,
{ {
LARGE_STRING WindowName; LARGE_STRING WindowName;
LARGE_STRING lstrClassName, *plstrClassName; LARGE_STRING lstrClassName, *plstrClassName;
LARGE_STRING lstrClassVersion, *plstrClassVersion;
UNICODE_STRING ClassName; UNICODE_STRING ClassName;
UNICODE_STRING ClassVersion;
WNDCLASSEXA wceA; WNDCLASSEXA wceA;
WNDCLASSEXW wceW; WNDCLASSEXW wceW;
HMODULE hLibModule = NULL; HMODULE hLibModule = NULL;
DWORD save_error; DWORD save_error;
BOOL Unicode, ClassFound = FALSE; BOOL Unicode, ClassFound = FALSE;
HWND Handle = NULL; HWND Handle = NULL;
LPCWSTR lpszClsVersion;
HANDLE pCtx;
LPCWSTR lpLibFileName;
#if 0 #if 0
DbgPrint("[window] User32CreateWindowEx style %d, exstyle %d, parent %d\n", dwStyle, dwExStyle, hWndParent); DbgPrint("[window] User32CreateWindowEx style %d, exstyle %d, parent %d\n", dwStyle, dwExStyle, hWndParent);
@ -263,11 +269,25 @@ User32CreateWindowEx(DWORD dwExStyle,
if (!Unicode) dwExStyle |= WS_EX_SETANSICREATOR; if (!Unicode) dwExStyle |= WS_EX_SETANSICREATOR;
lpszClsVersion = ClassNameToVersion(lpClassName, NULL, &lpLibFileName, &pCtx, !Unicode);
if (!lpszClsVersion)
{
plstrClassVersion = plstrClassName;
}
else
{
RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
lstrClassVersion.Buffer = ClassVersion.Buffer;
lstrClassVersion.Length = ClassVersion.Length;
lstrClassVersion.MaximumLength = ClassVersion.MaximumLength;
plstrClassVersion = &lstrClassVersion;
}
for(;;) for(;;)
{ {
Handle = NtUserCreateWindowEx(dwExStyle, Handle = NtUserCreateWindowEx(dwExStyle,
plstrClassName, plstrClassName,
plstrClassName, plstrClassVersion,
&WindowName, &WindowName,
dwStyle, dwStyle,
x, x,
@ -281,12 +301,13 @@ User32CreateWindowEx(DWORD dwExStyle,
dwFlags, dwFlags,
NULL); NULL);
if (Handle) break; if (Handle) break;
if (!lpLibFileName) break;
if (!ClassFound) if (!ClassFound)
{ {
save_error = GetLastError(); save_error = GetLastError();
if ( save_error == ERROR_CANNOT_FIND_WND_CLASS ) if ( save_error == ERROR_CANNOT_FIND_WND_CLASS )
{ {
ClassFound = VersionRegisterClass(ClassName.Buffer, NULL, NULL, &hLibModule); ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue; if (ClassFound) continue;
} }
} }