[PATCH] user32: Add support for class versions

Ivan Akulinchev ivan.akulinchev at gmail.com
Sat Nov 5 08:36:34 CDT 2016


Signed-off-by: Ivan Akulinchev <ivan.akulinchev at gmail.com>
---
 dlls/comctl32/comctl32.manifest |  1 -
 dlls/comctl32/theming.c         | 15 +++++++--
 dlls/user32/class.c             | 73 +++++++++++++++++++++++++++++++++++++----
 dlls/user32/user_private.h      |  2 ++
 dlls/user32/win.c               |  7 ++--
 5 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/dlls/comctl32/comctl32.manifest b/dlls/comctl32/comctl32.manifest
index 4c86137..5aa55a3 100644
--- a/dlls/comctl32/comctl32.manifest
+++ b/dlls/comctl32/comctl32.manifest
@@ -12,7 +12,6 @@
     <windowClass>NativeFontCtl</windowClass>
     <windowClass>ReBarWindow32</windowClass>
     <windowClass>ScrollBar</windowClass>
-    <windowClass>Static</windowClass>
     <windowClass>SysAnimate32</windowClass>
     <windowClass>SysDateTimePick32</windowClass>
     <windowClass>SysHeader32</windowClass>
diff --git a/dlls/comctl32/theming.c b/dlls/comctl32/theming.c
index 93d6fe6..b78ecc9 100644
--- a/dlls/comctl32/theming.c
+++ b/dlls/comctl32/theming.c
@@ -28,6 +28,7 @@
 #include "comctl32.h"
 #include "uxtheme.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(theming);
 
@@ -124,8 +125,6 @@ void THEMING_Initialize (void)
     static const WCHAR refDataPropName[] = 
         { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 };
 
-    if (!IsThemeActive()) return;
-
     atSubclassProp = GlobalAddAtomW (subclassPropName);
     atRefDataProp = GlobalAddAtomW (refDataPropName);
 
@@ -142,6 +141,18 @@ void THEMING_Initialize (void)
         }
         originalProcs[i] = class.lpfnWndProc;
         class.lpfnWndProc = subclassProcs[i];
+
+        /*
+         * FIXME: The Dialog class ('#32770') should NOT be overridden here.
+         *
+         * Temporarily ignore this issue using the hack below...
+         */
+        if (strcmpiW(subclasses[i].className, dialogClass) != 0)
+        {
+            /* If not a dialog (see above), make the class global */
+            class.style |= CS_GLOBALCLASS;
+            class.hInstance = NULL;
+        }
         
         if (!class.lpfnWndProc)
         {
diff --git a/dlls/user32/class.c b/dlls/user32/class.c
index 0b3582e..5b16008 100644
--- a/dlls/user32/class.c
+++ b/dlls/user32/class.c
@@ -411,6 +411,42 @@ static CLASS *CLASS_RegisterClass( LPCWSTR name, HINSTANCE hInstance, BOOL local
     return classPtr;
 }
 
+/***********************************************************************
+ *           CLASS_GetVersionedName
+ *
+ * Return a versioned class name, like "6.0.2600.2982!Button".
+ */
+LPCWSTR CLASS_GetVersionedName( LPCWSTR name )
+{
+    ACTCTX_SECTION_KEYED_DATA data = { sizeof(data) };
+
+    static const WCHAR staticW[] = { 'S','t','a','t','i','c',0 };
+
+    if (!name)
+        return NULL;
+
+    if (IS_INTRESOURCE( name ))
+        return name;
+
+    /*
+     * FIXME: I disabled the Static class in comctl32.manifest (because it is
+     * not implemented there yet), however I still get "6.0.2600.2982!Static".
+     *
+     * Is it a FindActCtxSectionString bug?
+     */
+    if (strcmpiW( name, staticW ) == 0)
+        return name;
+
+    if (FindActCtxSectionStringW( 0, NULL, 3, name, &data ))
+    {
+        BYTE *res = (BYTE *)data.lpData;
+        ULONG offset = *(ULONG *)(res + sizeof(ULONG) * 2 + sizeof(DWORD));
+        return (LPCWSTR)(res + offset);
+    }
+
+    return name;
+}
+
 
 /***********************************************************************
  *           register_builtin
@@ -576,10 +612,12 @@ ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
 
     if (!IS_INTRESOURCE(wc->lpszClassName))
     {
+        LPCWSTR versioned_name;
         WCHAR name[MAX_ATOM_LEN + 1];
 
         if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, name, MAX_ATOM_LEN + 1 )) return 0;
-        classPtr = CLASS_RegisterClass( name, instance, !(wc->style & CS_GLOBALCLASS),
+        versioned_name = CLASS_GetVersionedName( name );
+        classPtr = CLASS_RegisterClass( versioned_name, instance, !(wc->style & CS_GLOBALCLASS),
                                         wc->style, wc->cbClsExtra, wc->cbWndExtra );
     }
     else
@@ -619,6 +657,7 @@ ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
     ATOM atom;
     CLASS *classPtr;
     HINSTANCE instance;
+    LPCWSTR versioned_name;
 
     GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
 
@@ -630,7 +669,9 @@ ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
     }
     if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
 
-    if (!(classPtr = CLASS_RegisterClass( wc->lpszClassName, instance, !(wc->style & CS_GLOBALCLASS),
+    versioned_name = CLASS_GetVersionedName( wc->lpszClassName );
+
+    if (!(classPtr = CLASS_RegisterClass( versioned_name, instance, !(wc->style & CS_GLOBALCLASS),
                                           wc->style, wc->cbClsExtra, wc->cbWndExtra )))
         return 0;
 
@@ -678,6 +719,7 @@ BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
 {
     CLASS *classPtr = NULL;
+    LPCWSTR versioned_name = CLASS_GetVersionedName( className );
 
     GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
 
@@ -685,7 +727,7 @@ BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
     {
         req->instance = wine_server_client_ptr( hInstance );
         if (!(req->atom = get_int_atom_value(className)) && className)
-            wine_server_add_data( req, className, strlenW(className) * sizeof(WCHAR) );
+            wine_server_add_data( req, versioned_name, strlenW(versioned_name) * sizeof(WCHAR) );
         if (!wine_server_call_err( req )) classPtr = wine_server_get_ptr( reply->client_ptr );
     }
     SERVER_END_REQ;
@@ -1192,10 +1234,15 @@ BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
 
     if (!IS_INTRESOURCE(name))
     {
+        LPCWSTR versioned_name;
         WCHAR nameW[MAX_ATOM_LEN + 1];
         if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ))
             return FALSE;
-        classPtr = CLASS_FindClass( nameW, hInstance );
+        versioned_name = CLASS_GetVersionedName( nameW );
+        classPtr = CLASS_FindClass( versioned_name, hInstance );
+        /* FIXME: I believe we shouldn't fall back to the normal class. Fill
+         * free to remove it if necessary. */
+        if (!classPtr) classPtr = CLASS_FindClass( nameW, hInstance );
     }
     else classPtr = CLASS_FindClass( (LPCWSTR)name, hInstance );
 
@@ -1230,6 +1277,7 @@ BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc
 {
     ATOM atom;
     CLASS *classPtr;
+    LPCWSTR versioned_name;
 
     TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
 
@@ -1241,10 +1289,21 @@ BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc
 
     if (!hInstance) hInstance = user32_module;
 
-    if (!(classPtr = CLASS_FindClass( name, hInstance )))
+    versioned_name = CLASS_GetVersionedName( name );
+
+    classPtr = CLASS_FindClass( versioned_name, hInstance );
+    if (!classPtr)
     {
-        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
-        return FALSE;
+        /*
+         * FIXME: It's not correct to fall back to the normal class, but our
+         * comctl32 implementation depends on it...
+         */
+        classPtr = CLASS_FindClass( name, hInstance );
+        if (!classPtr)
+        {
+            SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
+            return FALSE;
+        }
     }
     wc->style         = classPtr->style;
     wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, TRUE );
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 0b5b2ac..0c212ce 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -281,6 +281,8 @@ extern void SPY_EnterMessage( INT iFlag, HWND hwnd, UINT msg, WPARAM wParam, LPA
 extern void SPY_ExitMessage( INT iFlag, HWND hwnd, UINT msg,
                              LRESULT lReturn, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN;
 
+extern LPCWSTR CLASS_GetVersionedName( LPCWSTR name ) DECLSPEC_HIDDEN;
+
 #include "pshpack1.h"
 
 typedef struct
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index a7be4a3..42676b5 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -1740,9 +1740,11 @@ HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className,
     if (!IS_INTRESOURCE(className))
     {
         WCHAR bufferW[256];
+        LPCWSTR versioned_name;
         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
             return 0;
-        return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
+        versioned_name = CLASS_GetVersionedName( bufferW );
+        return wow_handlers.create_window( (CREATESTRUCTW *)&cs, versioned_name, instance, FALSE );
     }
     /* Note: we rely on the fact that CREATESTRUCTA and */
     /* CREATESTRUCTW have the same layout. */
@@ -1760,6 +1762,7 @@ HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
                                  HINSTANCE instance, LPVOID data )
 {
     CREATESTRUCTW cs;
+    LPCWSTR versioned_name = CLASS_GetVersionedName( className );
 
     cs.lpCreateParams = data;
     cs.hInstance      = instance;
@@ -1774,7 +1777,7 @@ HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
     cs.lpszClass      = className;
     cs.dwExStyle      = exStyle;
 
-    return wow_handlers.create_window( &cs, className, instance, TRUE );
+    return wow_handlers.create_window( &cs, versioned_name, instance, TRUE );
 }
 
 
-- 
2.7.4




More information about the wine-patches mailing list