[PATCH 1/7] Use subclass chain for internally used controls

Nikolay Sivov bunglehead at gmail.com
Wed Dec 23 13:50:26 CST 2009


---
 dlls/comctl32/comboex.c       |   94 ++++++++++++++++-------------------------
 dlls/comctl32/tests/comboex.c |   25 +++++++++++
 2 files changed, 61 insertions(+), 58 deletions(-)

diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c
index a2361fd..62178f1 100644
--- a/dlls/comctl32/comboex.c
+++ b/dlls/comctl32/comboex.c
@@ -67,8 +67,6 @@ typedef struct
     HWND         hwndNotify;       /* my parent hwnd */
     HWND         hwndCombo;
     HWND         hwndEdit;
-    WNDPROC      prevEditWndProc;  /* previous Edit WNDPROC value */
-    WNDPROC      prevComboWndProc; /* previous Combo WNDPROC value */
     DWORD        dwExtStyle;
     INT          selected;         /* index of selected item */
     DWORD        flags;            /* WINE internal flags */
@@ -121,17 +119,15 @@ typedef struct
 /* Offset between image and text */
 #define CBE_SEP			4
 
-static const WCHAR COMBOEX_SUBCLASS_PROP[] = {
-    'C','C','C','o','m','b','o','E','x','3','2',
-    'S','u','b','c','l','a','s','s','I','n','f','o',0
-};
+#define COMBO_SUBCLASSID  1
+#define EDIT_SUBCLASSID   2
 
 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0))
 
-
-/* Things common to the entire DLL */
-static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                                             UINT_PTR uId, DWORD_PTR ref_data);
+static LRESULT CALLBACK COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                                              UINT_PTR uId, DWORD_PTR ref_data);
 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr);
 typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR);
 
@@ -1039,16 +1035,10 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
      *  GetCurrentProcessId()
      */
 
-    /*
-     * Setup a property to hold the pointer to the COMBOBOXEX
-     * data structure.
-     */
-    SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd);
-    infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo,
-	                        GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc);
+    SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID,
+                      (DWORD_PTR)hwnd);
     infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
 
-
     /*
      * Now create our own EDIT control so we can position it.
      * It is created only for CBS_DROPDOWN style
@@ -1067,14 +1057,9 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
 	 *  GetWindowThreadProcessId(hwndEdit, &???)
 	 *  GetCurrentProcessId()
 	 */
+	SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID,
+	                  (DWORD_PTR)hwnd);
 
-	/*
-	 * Setup a property to hold the pointer to the COMBOBOXEX
-	 * data structure.
-	 */
-        SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd);
-	infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit,
-				 GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc);
 	infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0);
     }
 
@@ -1604,7 +1589,10 @@ static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr)
 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
 {
     if (infoPtr->hwndCombo)
-	DestroyWindow (infoPtr->hwndCombo);
+        RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
+
+    if (infoPtr->hwndEdit)
+        RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
 
     Free (infoPtr->edit);
     infoPtr->edit = 0;
@@ -1729,11 +1717,11 @@ static LRESULT COMBOEX_WindowPosChanging (const COMBOEX_INFO *infoPtr, WINDOWPOS
     return 0;
 }
 
-static LRESULT WINAPI
-COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                     UINT_PTR uId, DWORD_PTR ref_data)
 {
-    HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
-    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
     NMCBEENDEDITW cbeend;
     WCHAR edit_text[260];
     COLORREF obkc;
@@ -1753,8 +1741,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	    /* handle (ignore) the return character */
 	    if (wParam == VK_RETURN) return 0;
 	    /* all other characters pass into the real Edit */
-	    return CallWindowProcW (infoPtr->prevEditWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
 	case WM_ERASEBKGND:
 	    /*
@@ -1766,8 +1753,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
 	    ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
             SetBkColor (hDC, obkc);
-	    return CallWindowProcW (infoPtr->prevEditWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
 	case WM_KEYDOWN: {
 	    INT_PTR oldItem, selected, step = 1;
@@ -1889,16 +1875,14 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 		    SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
 	    	return 0;
 	    default:
-		return CallWindowProcW (infoPtr->prevEditWndProc,
-				       hwnd, uMsg, wParam, lParam);
+		return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 	    }
 	    return 0;
             }
 
 	case WM_SETFOCUS:
 	    /* remember the focus to set state of icon */
-	    lret = CallWindowProcW (infoPtr->prevEditWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    lret = DefSubclassProc(hwnd, uMsg, wParam, lParam);
 	    infoPtr->flags |= WCBE_EDITFOCUSED;
 	    return lret;
 
@@ -1921,17 +1905,16 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	    /* fall through */
 
 	default:
-	    return CallWindowProcW (infoPtr->prevEditWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
     }
 }
 
 
-static LRESULT WINAPI
-COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                      UINT_PTR uId, DWORD_PTR ref_data)
 {
-    HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
-    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
     NMCBEENDEDITW cbeend;
     NMMOUSE nmmse;
     COLORREF obkc;
@@ -1956,8 +1939,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	     * that ComboEx knows this is listbox.
 	     */
 	    ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
-	    return CallWindowProcW (infoPtr->prevComboWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_ERASEBKGND:
 	    /*
@@ -1969,8 +1951,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
 	    ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
             SetBkColor (hDC, obkc);
-	    return CallWindowProcW (infoPtr->prevComboWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_SETCURSOR:
 	    /*
@@ -1984,8 +1965,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	    nmmse.pt.y = 0;
 	    nmmse.dwHitInfo = lParam;
 	    COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
-	    return CallWindowProcW (infoPtr->prevComboWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_LBUTTONDOWN:
 	    GetClientRect (hwnd, &rect);
@@ -1995,16 +1975,16 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	    pt.x = (short)LOWORD(lParam);
 	    pt.y = (short)HIWORD(lParam);
 	    if (PtInRect(&rect, pt))
-		return CallWindowProcW (infoPtr->prevComboWndProc,
-				        hwnd, uMsg, wParam, lParam);
+		return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
 	    infoPtr->flags |= WCBE_MOUSECAPTURED;
 	    SetCapture(hwnd);
 	    break;
 
     case WM_LBUTTONUP:
 	    if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
-		return CallWindowProcW (infoPtr->prevComboWndProc,
-				        hwnd, uMsg, wParam, lParam);
+		return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
 	    ReleaseCapture();
 	    infoPtr->flags &= ~WCBE_MOUSECAPTURED;
 	    if (infoPtr->flags & WCBE_MOUSEDRAGGED) {
@@ -2021,8 +2001,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 		COMBOEX_NotifyDragBegin(infoPtr, edit_text);
 		infoPtr->flags |= WCBE_MOUSEDRAGGED;
 	    }
-	    return CallWindowProcW (infoPtr->prevComboWndProc,
-			            hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_COMMAND:
 	    switch (HIWORD(wParam)) {
@@ -2166,8 +2145,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 		break;
 	    }/* fall through */
     default:
-	    return CallWindowProcW (infoPtr->prevComboWndProc,
-				   hwnd, uMsg, wParam, lParam);
+	    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
     }
     return 0;
 }
diff --git a/dlls/comctl32/tests/comboex.c b/dlls/comctl32/tests/comboex.c
index 8a1e253..a8d7f79 100644
--- a/dlls/comctl32/tests/comboex.c
+++ b/dlls/comctl32/tests/comboex.c
@@ -27,6 +27,8 @@ static HWND hComboExParentWnd;
 static HINSTANCE hMainHinst;
 static const char ComboExTestClass[] = "ComboExTestClass";
 
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+
 #define MAX_CHARS 100
 static char *textBuffer = NULL;
 
@@ -356,6 +358,8 @@ static int init(void)
     iccex.dwICC  = ICC_USEREX_CLASSES;
     pInitCommonControlsEx(&iccex);
 
+    pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410);
+
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
@@ -390,6 +394,26 @@ static void cleanup(void)
     UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
 }
 
+static void test_comboboxex_subclass(void)
+{
+    HWND hComboEx, hCombo, hEdit;
+
+    hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+    hCombo = (HWND)SendMessage(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
+    ok(hCombo != NULL, "Failed to get internal combo\n");
+    hEdit = (HWND)SendMessage(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
+    ok(hEdit != NULL, "Failed to get internal edit\n");
+
+    if (pSetWindowSubclass)
+    {
+        ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+        ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+    }
+
+    DestroyWindow(hComboEx);
+}
+
 START_TEST(comboex)
 {
     if (!init())
@@ -398,6 +422,7 @@ START_TEST(comboex)
     test_comboboxex();
     test_WM_LBUTTONDOWN();
     test_CB_GETLBTEXT();
+    test_comboboxex_subclass();
 
     cleanup();
 }
-- 
1.5.6.5


--=-RBTJ18suSuL3Vi76iMQV--




More information about the wine-patches mailing list