ChangeLog: * include/commctrl.h * dlls/comctl32/commctrl.c * dlls/comctl32/comctl32.h * dlls/comctl32/comctl32.spec Implement {G|S}etWindowSubClass, DefSubclassProc, RemoveWindowSubclass nog.
Index: include/commctrl.h =================================================================== RCS file: /home/wine/wine/include/commctrl.h,v retrieving revision 1.96 diff -u -r1.96 commctrl.h --- include/commctrl.h 17 Sep 2002 01:35:09 -0000 1.96 +++ include/commctrl.h 2 Oct 2002 17:16:57 -0000 @@ -677,6 +677,12 @@ BOOL WINAPI InitializeFlatSB(HWND); HRESULT WINAPI UninitializeFlatSB(HWND); +/* Subclassing stuff */ +typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR); +BOOL WINAPI SetWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); +BOOL WINAPI GetWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR*); +BOOL WINAPI RemoveWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR); +LRESULT WINAPI DefSubclassProc(HWND, UINT, WPARAM, LPARAM); /* Header control */ Index: dlls/comctl32/commctrl.c =================================================================== RCS file: /home/wine/wine/dlls/comctl32/commctrl.c,v retrieving revision 1.55 diff -u -r1.55 commctrl.c --- dlls/comctl32/commctrl.c 17 Sep 2002 01:35:09 -0000 1.55 +++ dlls/comctl32/commctrl.c 2 Oct 2002 17:17:05 -0000 @@ -998,6 +998,259 @@ /*********************************************************************** + * SetWindowSubclass [COMCTL32.@] + * + * Starts a window subclass + * + * PARAMS + * hWnd [in] handle to window subclass. + * pfnSubclass [in] Pointer to new window procedure. + * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass. + * dwRef [in] Reference data to pass to window procedure. + * + * RETURNS + * Success: non-zero + * Failure: zero + * + * BUGS + * If an application manually subclasses a window after subclassing it with + * this API and then with this API again, then none of the previous + * subclasses get called or the origional window procedure. + */ +BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, + UINT_PTR uIDSubclass, DWORD_PTR dwRef) +{ + LPSUBCLASS_INFO stack; + int newnum, n; + + TRACE ("(%x, %p, %x, %x)\n", hWnd, pfnSubclass, uIDSubclass, dwRef); + + /* Since the window procedure that we set here has two additional arguments, + * we can't simply set it as the new window procedure of the window. So we + * set our own window procedure and then calculate the other two arguments + * from there. */ + + /* See if we have been called for this window */ + stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass); + if (!stack) { + /* allocate stack */ + stack = (LPSUBCLASS_INFO)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(SUBCLASS_INFO)); + if (!stack) { + ERR ("Failed to allocate our Subclassing stack"); + return FALSE; + } + SetPropA (hWnd, COMCTL32_aSubclass, (HANDLE)stack); + + /* set window procedure to our own and save the current one */ + if (IsWindowUnicode (hWnd)) + stack->origproc = (WNDPROC)SetWindowLongW (hWnd, GWL_WNDPROC, + (LONG)DefSubclassProc); + else + stack->origproc = (WNDPROC)SetWindowLongA (hWnd, GWL_WNDPROC, + (LONG)DefSubclassProc); + } + + /* Check to see if we have called this function with the same uIDSubClass + * and pfnSubclass */ + for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++) + if ((stack->SubclassProcs[n].id == uIDSubclass) && + (stack->SubclassProcs[n].subproc == pfnSubclass)) { + stack->SubclassProcs[n].ref = dwRef; + return TRUE; + } + + if ((stack->stacknum + stack->stacknew) >= 32) { + ERR ("We have a Subclass stack overflow, please increment size"); + return FALSE; + } + + /* we can't simply increment both stackpos and stacknum because there might + * be a window procedure running lower in the stack, we can only get them + * up to date once the last window procedure has run */ + if (stack->stacknum == stack->stackpos) { + stack->stacknum++; + stack->stackpos++; + } else + stack->stacknew++; + + newnum = stack->stacknew + stack->stacknum - 1; + + stack->SubclassProcs[newnum].subproc = pfnSubclass; + stack->SubclassProcs[newnum].ref = dwRef; + stack->SubclassProcs[newnum].id = uIDSubclass; + + return TRUE; +} + + +/*********************************************************************** + * GetWindowSubclass [COMCTL32.@] + * + * Gets the Reference data from a subclass. + * + * PARAMS + * hWnd [in] Handle to window which were subclassing + * pfnSubclass [in] Pointer to the subclass procedure + * iID [in] Unique indentifier of the subclassing procedure + * pdwRef [out] Pointer to the reference data + * + * RETURNS + * Success: non-sero + * Failure: zero + */ +BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, + UINT_PTR uID, DWORD_PTR *pdwRef) +{ + LPSUBCLASS_INFO stack; + int n; + + TRACE ("(%x, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef); + + /* See if we have been called for this window */ + stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass); + if (!stack) + return FALSE; + + for (n = 0; n <= stack->stacknum + stack->stacknew - 1; n++) + if ((stack->SubclassProcs[n].id == uID) && + (stack->SubclassProcs[n].subproc == pfnSubclass)) { + *pdwRef = stack->SubclassProcs[n].ref; + return TRUE; + } + + return FALSE; +} + + +/*********************************************************************** + * RemoveWindowSubclass [COMCTL32.@] + * + * Removes a window subclass. + * + * PARAMS + * hWnd [in] Handle to the window were subclassing + * pfnSubclass [in] Pointer to the subclass procedure + * uID [in] Unique identifier of this subclass + * + * RETURNS + * Success: non-zero + * Failure: zero + */ +BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID) +{ + LPSUBCLASS_INFO stack; + int n; + + TRACE ("(%x, %p, %x)\n", hWnd, pfnSubclass, uID); + + /* Find the Subclass to remove */ + stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass); + if (!stack) + return FALSE; + + if ((stack->stacknum == stack->stackpos == 1) && !stack->stacknew) { + TRACE("Last Subclass removed, cleaning up\n"); + /* clean up our heap and reset the origional window procedure */ + if (IsWindowUnicode (hWnd)) + SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc); + else + SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc); + HeapFree (GetProcessHeap (), 0, stack); + return TRUE; + } + + for (n = stack->stacknum + stack->stacknew - 1; n >= 0; n--) + if ((stack->SubclassProcs[n].id == uID) && + (stack->SubclassProcs[n].subproc == pfnSubclass)) { + if (n != (stack->stacknum + stack->stacknew)) + /* Fill the hole in the stack */ + memmove (&stack->SubclassProcs[n], &stack->SubclassProcs[n + 1], + sizeof(stack->SubclassProcs[0]) * (stack->stacknew + stack->stacknum - n)); + stack->SubclassProcs[n].subproc = NULL; + stack->SubclassProcs[n].ref = 0; + stack->SubclassProcs[n].id = 0; + + /* If we are currently running a window procedure we have to manipulate + * the stack position pointers so that we don't corrupt the stack */ + if ((n < stack->stackpos) || (stack->stackpos == stack->stacknum)) { + stack->stacknum--; + stack->stackpos--; + } else if (n >= stack->stackpos) + stack->stacknew--; + return TRUE; + } + + return FALSE; +} + + +/*********************************************************************** + * DefSubclassProc [COMCTL32.@] + * + * Calls the next window procedure (ie. the one before this subclass) + * + * PARAMS + * hWnd [in] The window that we're subclassing + * uMsg [in] Message + * wParam [in] WPARAM + * lParam [in] LPARAM + * + * RETURNS + * Success: non-zero + * Failure: zero + */ +LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPSUBCLASS_INFO stack; + int stackpos; + LRESULT ret; + + /* retrieve our little stack from the Properties */ + stack = (LPSUBCLASS_INFO)GetPropA (hWnd, COMCTL32_aSubclass); + if (!stack) { + ERR ("Our sub classing stack got erased for %x!! Nothing we can do\n", hWnd); + return 0; + } + + /* If we are at pos 0 then we have to call the origional window procedure */ + if (stack->stackpos == 0) { + if (IsWindowUnicode (hWnd)) + return CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); + else + return CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); + } + + stackpos = --stack->stackpos; + /* call the Subclass procedure from the stack */ + ret = stack->SubclassProcs[stackpos].subproc (hWnd, uMsg, wParam, lParam, + stack->SubclassProcs[stackpos].id, stack->SubclassProcs[stackpos].ref); + stack->stackpos++; + + if ((stack->stackpos == stack->stacknum) && stack->stacknew) { + stack->stacknum += stack->stacknew; + stack->stackpos += stack->stacknew; + stack->stacknew = 0; + } + + /* If we removed the last entry in our stack while a window procedure was + * running then we have to clean up */ + if (stack->stackpos == stack->stacknum == 0) { + TRACE("Last Subclass removed, cleaning up\n"); + /* clean up our heap and reset the origional window procedure */ + if (IsWindowUnicode (hWnd)) + SetWindowLongW (hWnd, GWL_WNDPROC, (LONG)stack->origproc); + else + SetWindowLongA (hWnd, GWL_WNDPROC, (LONG)stack->origproc); + HeapFree (GetProcessHeap (), 0, stack); + return TRUE; + } + + return ret; +} + + +/*********************************************************************** * COMCTL32_CreateToolTip [NOT AN API] * * Creates a tooltip for the control specified in hwnd and does all Index: dlls/comctl32/comctl32.h =================================================================== RCS file: /home/wine/wine/dlls/comctl32/comctl32.h,v retrieving revision 1.18 diff -u -r1.18 comctl32.h --- dlls/comctl32/comctl32.h 17 Sep 2002 18:30:07 -0000 1.18 +++ dlls/comctl32/comctl32.h 2 Oct 2002 17:17:06 -0000 @@ -260,4 +260,18 @@ DEFINE_TOOLTIPSCREATED_NOTIFICATION(CTRLINFO, hwndSelf) \ struct __forward_dummy_struc_dec_to_catch_missing_semicolon +/* Our internal stack structure of the window procedures to subclass */ +typedef struct +{ + struct { + SUBCLASSPROC subproc; + UINT_PTR id; + DWORD_PTR ref; + } SubclassProcs[31]; + int stackpos; + int stacknum; + int stacknew; + WNDPROC origproc; +} SUBCLASS_INFO, *LPSUBCLASS_INFO; + #endif /* __WINE_COMCTL32_H */ Index: dlls/comctl32/comctl32.spec =================================================================== RCS file: /home/wine/wine/dlls/comctl32/comctl32.spec,v retrieving revision 1.34 diff -u -r1.34 comctl32.spec --- dlls/comctl32/comctl32.spec 16 Aug 2002 01:43:11 -0000 1.34 +++ dlls/comctl32/comctl32.spec 2 Oct 2002 17:17:08 -0000 @@ -188,3 +188,9 @@ @ stdcall PropertySheetW(ptr) PropertySheetW @ stdcall UninitializeFlatSB(long) UninitializeFlatSB @ stdcall _TrackMouseEvent(ptr) _TrackMouseEvent + +# These are only availible in comctrl 6 +@ stdcall SetWindowSubclass(long ptr ptr ptr) SetWindowSubclass +@ stdcall GetWindowSubclass(long ptr ptr ptr) GetWindowSubclass +@ stdcall RemoveWindowSubclass(long ptr ptr) RemoveWindowSubclass +@ stdcall DefSubclassProc(long long ptr ptr) DefSubclassProc