Menu

#1573 Change ListBoxX to using modern control subclassing

Initial
open
5
2025-12-18
2025-12-15
Zufu Liu
No

Quote "Subclassing Controls" document from https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview

Disadvantages of the Old Subclassing Approach

The following list points out some of the disadvantages of using the previously described approach to subclassing a control.

  • The window procedure can only be replaced once.
  • It is difficult to remove a subclass after it is created.
  • Associating private data with a window is inefficient.
  • To call the next procedure in a subclass chain, you cannot cast the old window procedure and call it, you must call it by using the CallWindowProc function.

this avoids call PointerFromWindow() for every message.

Patch replaced old PASCAL with CALLBACK.

1 Attachments

Discussion

  • Zufu Liu

    Zufu Liu - 2025-12-16

    Looking source code for SetWindowSubclass() at https://gitlab.winehq.org/wine/wine/blob/master/dlls/comctl32/commctrl.c, it's just wrap for SubclassWindow() and CallWindowProc(), maybe inefficient (use GetProp() to retrieve callback function and data).

    The change also added comctl32.dll dependency for Scintilla.dll, may not a problem for GUI app/lib.

    With old approach, ListBoxX::ControlWndProc can still be eliminate (to avoid PointerFromWindow(::GetParent(hWnd))) with something like SetWindowLongPtr(lb, DWLP_USER, reinterpret_cast<LONG_PTR>(this)).

     
  • Neil Hodgson

    Neil Hodgson - 2025-12-17

    inefficient (use GetProp() ...

    That is something I'd be worried about as well.

    The change also added comctl32.dll dependency

    Yes, it would need to be in other Win32 build files like win32/makefile/

    g++ -shared -static -mwindows -o ../bin/Scintilla.dll -s AutoComplete.o CallTip.o CaseConvert.o CaseFolder.o CellBuffer.o ChangeHistory.o CharacterCategoryMap.o CharacterType.o CharClassify.o ContractionState.o DBCS.o Decoration.o Document.o EditModel.o Editor.o EditView.o Geometry.o Indicator.o KeyMap.o LineMarker.o MarginView.o PerLine.o PositionCache.o RESearch.o RunStyles.o Selection.o Style.o UndoHistory.o UniConversion.o UniqueString.o ViewStyle.o XPM.o HanjaDic.o PlatWin.o ListBox.o SurfaceGDI.o SurfaceD2D.o ScintillaBase.o ScintillaWin.o ScintillaDLL.o ScintRes.o  -lgdi32 -luser32 -limm32 -lole32 -luuid -loleaut32 -ladvapi32 -lstdc++
    C:/MinGW/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ListBox.o:ListBox.cxx:(.text+0x294): undefined reference to `DefSubclassProc'
    C:/MinGW/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ListBox.o:ListBox.cxx:(.text+0x340): undefined reference to `RemoveWindowSubclass'
    C:/MinGW/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ListBox.o:ListBox.cxx:(.text+0x350): undefined reference to `DefSubclassProc'
    C:/MinGW/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ListBox.o:ListBox.cxx:(.text+0x2771): undefined reference to `SetWindowSubclass'
    collect2.exe: error: ld returned 1 exit status
    mingw32-make: *** [makefile:133: ../bin/Scintilla.dll] Error 1
    

    ... DWLP_USER

    There is a possibility of clashing with application code since they may consider themselves the user.

    https://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc#65876605

     
  • Zufu Liu

    Zufu Liu - 2025-12-17

    I think use GWLP_USERDATA on lb is fine as it's system ListBox control which private to and used by ListBoxX (the wid container).

    Update win32/makefile.

     
    • Zufu Liu

      Zufu Liu - 2025-12-17

      SciTEWin::AboutMessage() (in SciTEWinDlg.cxx) uses GWLP_WNDPROC and GWLP_USERDATA.

       
  • Neil Hodgson

    Neil Hodgson - 2025-12-17

    I'm not seeing a strong benefit here with a simple use of window bytes replaced by a window property. The disadvantages listed above don't seem relevant. Scintilla never removes the subclass and data is stored in the C++ class so is easy to access. Is there some needed function that can be implemented by application code subclassing the listbox instead of the ListBoxX?

    As explained in the above link, SetWindowSubclass uses a UxSubclassInfo property which will be less efficient. Maybe the cost isn't significant.

    The thunk technique mentioned in the linked message isn't a good direction. While it is efficient and widely used by Microsoft code, it generates code then turns on execution for that code. Executing generated code is similar to malware behaviour so would make Scintilla appear more dangerous.

     
    • Zufu Liu

      Zufu Liu - 2025-12-18

      OK, just fell code with SetWindowSubclass is clean.

       
      • Neil Hodgson

        Neil Hodgson - 2025-12-18

        SetWindowSubclass seems to be a better approach in more complex situations in applications where there may be multiple features or code sources (like plug-ins and scripting) that need to subclass a window.

        Applications that use Scintilla will likely be more maintainable if they use SetWindowSubclass since there are often multiple reasons to enhance Scintilla. Once SetWindowSubclass is used for one element, its then more consistent to use it in all cases.

         
  • Neil Hodgson

    Neil Hodgson - 2025-12-18

    s/PASCAL/CALLBACK/ is fine although not significant.

     
    • Neil Hodgson

      Neil Hodgson - 2025-12-18

      Changed to CALLBACK with [94f6bd] [bbbd84] .

       

      Related

      Commit: [94f6bd]
      Commit: [bbbd84]


Log in to post a comment.