#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
+#define USE_VERSIONED_CLASSES
+
/* From rtl/actctx.c and must match! */
-struct entity
+struct strsection_header
{
- DWORD kind; // Activation context type
- WCHAR *name; // Class name
- WCHAR *clsid; // Not supported yet but needed for menu name.
+ DWORD magic;
+ ULONG size;
+ 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
- WCHAR *hash;
- DWORD Data; // Junk
+ 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(
- LPCTSTR lpszClass,
+ const void* lpszClass,
LPCWSTR lpszMenuName,
LPCWSTR *plpLibFileName,
HANDLE *pContext,
BOOL bAnsi)
{
+ LPCWSTR VersionedClass = NULL;
NTSTATUS Status;
UNICODE_STRING SectionName;
- WCHAR SeactionNameBuf[MAX_PATH] = {0};
+ 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))
{
- SectionName.Buffer = (LPWSTR)&SeactionNameBuf;
- SectionName.MaximumLength = sizeof(SeactionNameBuf);
+ 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)
{
- RtlCreateUnicodeStringFromAsciiz(&SectionName, (LPSTR)lpszClass);
+ ANSI_STRING AnsiString;
+ RtlInitAnsiString(&AnsiString, lpszClass);
+ RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
+ RtlAnsiStringToUnicodeString(&SectionName, &AnsiString, FALSE);
}
else
{
&SectionName,
&KeyedData );
+#ifdef USE_VERSIONED_CLASSES
if (NT_SUCCESS(Status) && KeyedData.ulDataFormatVersion == 1)
{
- struct dll_redirect *dll = KeyedData.lpSectionBase;
-
- if (plpLibFileName) *plpLibFileName = dll->name;
+ struct strsection_header *SectionHeader = KeyedData.lpSectionBase;
- if (lpszMenuName)
+ /* Find activation context */
+ if(SectionHeader && SectionHeader->count > 0)
{
- WCHAR * mnubuf;
- LPWSTR mnuNameW;
- LPSTR mnuNameA;
- int len = 0;
- struct entity *entity = KeyedData.lpData;
+ struct wndclass_redirect_data *WindowRedirectionData = KeyedData.lpData;
+ if(WindowRedirectionData && WindowRedirectionData->module_len)
+ {
+ LPCWSTR lpLibFileName;
- FIXME("actctx: Needs to support menu name from redirected class!");
+ 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 (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);
+#endif
- return lpszClass;
+#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;
}
//
//
BOOL
FASTCALL
-Real_VersionRegisterClass(
+VersionRegisterClass(
PCWSTR pszClass,
LPCWSTR lpLibFileName,
HANDLE Contex,
HMODULE * phLibModule)
{
- BOOL Ret;
- HMODULE hLibModule;
+ BOOL Ret = FALSE;
+ HMODULE hLibModule = NULL;
PREGISTERCLASSNAMEW pRegisterClassNameW;
UNICODE_STRING ClassName;
WCHAR ClassNameBuf[MAX_PATH] = {0};
RtlActivateActivationContextUnsafeFast(&Frame, Contex);
- Ret = FALSE;
- hLibModule = NULL;
-
_SEH2_TRY
{
hLibModule = LoadLibraryW(lpLibFileName);
{
if (IS_ATOM(pszClass))
{
- ClassName.Buffer = (LPWSTR)&ClassNameBuf;
+ ClassName.Buffer = ClassNameBuf;
ClassName.MaximumLength = sizeof(ClassNameBuf);
if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
{
+ ERR("Error while verifying ATOM\n");
_SEH2_YIELD(goto Error_Exit);
}
- pszClass = (PCWSTR)&ClassNameBuf;
+ pszClass = ClassName.Buffer;
}
Ret = pRegisterClassNameW(pszClass);
}
+ else
+ {
+ WARN("No RegisterClassNameW PROC\n");
+ }
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
SetLastError(save_error);
}
+ RtlDeactivateActivationContextUnsafeFast(&Frame);
return Ret;
}
-//
-// Use wine hack to process extened context classes.
-//
-/***********************************************************************
- * is_comctl32_class
- */
-static BOOL 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 TRUE;
- if (res < 0) max = pos - 1;
- else min = pos + 1;
- }
- return FALSE;
-}
-
-BOOL
-FASTCALL
-VersionRegisterClass(
- PCWSTR pszClass,
- LPCWSTR lpLibFileName,
- HANDLE Contex,
- HMODULE * phLibModule)
-{
- // Should be lpLibFileName.....
- static const WCHAR comctl32W[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0};
- //
- PREGISTERCLASSNAMEW pRegisterClassNameW;
- UNICODE_STRING ClassName;
- WCHAR ClassNameBuf[MAX_PATH] = {0};
- BOOL Ret = FALSE;
- HMODULE hLibModule = NULL;
-
- if (!IS_ATOM(pszClass) && is_comctl32_class( pszClass ))
- {
- _SEH2_TRY
- {
- hLibModule = LoadLibraryW(comctl32W);
- 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))
- {
- ERR("Error while verifying ATOM\n");
- _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);
- }
- TRACE( "%s retrying after loading comctl32\n", debugstr_w(pszClass) );
- return Ret;
- }
- TRACE("NO ComCtl32 Class %S!\n",pszClass);
- return FALSE;
-}
-//
-//
-//
-
/*
* @implemented
*/
LPCSTR pszMenuName;
HMODULE hLibModule = NULL;
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,
IS_ATOM(lpszClass) ? NULL : lpszClass,
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);
}
else
{
- if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
- lpszClass))
+ ConvertedString = TRUE;
+ if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
(LPWSTR *)&pszMenuName,
TRUE);
if (Ret) break;
+ if (!lpLibFileName) 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);
+ ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue;
}
}
// lpwcx->lpszMenuName = pszMenuName;
}
- if (!IS_ATOM(lpszClass))
+ if (ConvertedString)
{
RtlFreeUnicodeString(&ClassName);
}
HMODULE hLibModule = NULL;
DWORD save_error;
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,
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);
}
else
{
- RtlInitUnicodeString(&ClassName,
- lpszClass);
+ RtlInitUnicodeString(&ClassName, lpszClass);
}
if (!RegisterDefaultClasses)
&pszMenuName,
FALSE);
if (Ret) break;
+ if (!lpLibFileName) 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);
+ ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue;
}
}
ATOM Atom;
WNDCLASSEXW WndClass;
UNICODE_STRING ClassName;
+ UNICODE_STRING ClassVersion;
UNICODE_STRING MenuName = {0};
CLSMENUNAME clsMenuName;
ANSI_STRING AnsiMenuName;
- HMODULE hLibModule = NULL;
- DWORD save_error;
- BOOL ClassFound = FALSE;
+ LPCWSTR lpszClsVersion;
if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
}
- clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
- clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
- clsMenuName.pusMenuName = &MenuName;
-
- for(;;)
+ ClassVersion = ClassName;
+ if (fnID == 0)
{
- Atom = NtUserRegisterClassExWOW( &WndClass,
- &ClassName,
- &ClassName, //PUNICODE_STRING ClsNVersion,
- &clsMenuName,
- fnID,
- 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)
+ lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE);
+ if (lpszClsVersion)
{
- save_error = GetLastError();
- FreeLibrary(hLibModule);
- SetLastError(save_error);
- hLibModule = 0;
+ RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
}
- break;
}
+ 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);
{
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);
- if (!IS_ATOM(lpClassName))
+ lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
+ if (lpszClsVersion)
{
- if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
- lpClassName))
+ 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);
+ Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
- if (!IS_ATOM(lpClassName))
+ if (ConvertedString)
RtlFreeUnicodeString(&ClassName);
return Ret;
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);
- if (!IS_ATOM(lpClassName))
+ lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
+ if (lpszClsVersion)
{
- RtlInitUnicodeString(&ClassName,
- lpClassName);
+ RtlInitUnicodeString(&ClassName, lpszClsVersion);
+ }
+ else if (!IS_ATOM(lpClassName))
+ {
+ RtlInitUnicodeString(&ClassName, lpClassName);
}
else
+ {
ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
+ }
- return NtUserUnregisterClass(&ClassName,
- hInstance,
- 0);
+ return NtUserUnregisterClass(&ClassName, hInstance, 0);
}
/* EOF */