Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Using CallWindowProc for mouse wheel scrolling on a DataGrid 1

Status
Not open for further replies.

NFordtektips

Programmer
Aug 15, 2018
3
US
thread222-902639
I have a Visual Basic 6 project with 4 DataGrids which I want to be able to scroll with a mouse wheel. The DataGrid does not support this, so I am using the code from the thread referenced above, but as written, only one DataGrid can be set to scroll using:
Code:
lpPrevWndProc = SetWindowLong(Grid1(0).hWnd, GWL_WNDPROC, AddressOf WndProc)

I tried using the DataGrid's .MouseMove event to change the above to whichever grid the mouse was over:

Code:
If int_MouseOverGrid <> Index Then
    int_MouseOverGrid = Index
    lpPrevWndProc = SetWindowLong(Grid1(Index).hWnd, GWL_WNDPROC, AddressOf WndProc)
End If

and in the scrolling code from the previous thread, used

Code:
Sub MouseWheel(Travel As Integer, X As Long, Y As Long)
    BBEditor.Grid1(int_MouseOverGrid).Scroll 0, -Travel * 3
End Sub
but when run, VB6 gave me an "Out of stack space" error because the following routine keeps looping:

Code:
Function WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If Msg = WM_MOUSEWHEEL Then
        Dim Delta As Long
        Static Travel As Long
        Delta = HiWord(wParam)
        Travel = Travel + Delta
        MouseWheel Travel \ WHEEL_DELTA, LoWord(lParam), HiWord(lParam)
        Travel = Travel Mod WHEEL_DELTA
    End If
    WndProc = CallWindowProc(lpPrevWndProc, hWnd, Msg, wParam, lParam)
End Function

Thanks for any help.
 
>only one DataGrid can be set to scroll

No reason why multiple controls cannot be subclassed to use the same Wndproc. The way we would normally distinguish between them in the Wndproc would then be by hWnd. Making sure all the plumbing is hooked up correctly can be a pit of a pain, though.

>change the above to whichever grid the mouse was over

Actually that seems to me to be something that should in principle work (although the plumbing can still be an issue)

But to be honest I am surprised it worked reliably in the first place since, I think you will find, the real problem is that the Wndproc should only receive WM_MOUSEWHEEL messages from the datagrid when it does not have any actual data - this is because if there is data, then the control spawns a child edit window (although not immediately …) that eats the WM_MOUSEWHEEL message before it gets to the datagrid's message queue. So what you really need to subclass in each datagrid is that child edit window.But perhaps there is an updated Datagrid control that isn't so selfish with WM_MOUSEWHEEL messages

BTW, also worth pointing out that since many of our more detailed posts concerning subclassing were posted in this forum, back in 2004 or so and earlier, a new, safer, simpler method of subclassing has arisen, thanks to Microsoft documenting some previously 'secret' API functions in the common control library. You might like to Google [tt]SetWindowSubclass[/tt]
 
As long as I only subclass 1 grid, the mousewheel works fine. Maybe...

I don't know if there is any connection, but about the time I started using the mousewheel, I started having a problem that if I hit an error in my code while running it from inside VB6 and clicked End on the error message box to close the program, VB6 would also close. If I can move around the error line and use the program's menu to close it, then VB6 doesn't close.

This doesn't happen with any other programs in which I'm using grids WITHOUT mousewheel, so I'm kinda thinking that the two problems are related.

The data grid control I'm using is MSDATGRD.OCX [AKA: Microsoft DataGrid Control 6.0 (OLEDB)] dated 6/24/1998.

...(Time out.)...

Per your first comment, I just tried moving the lpPrevWndProc = SetWindowLong(Grid1(Index).hWnd, GWL_WNDPROC, AddressOf WndProc) line back to Form_Load and did a loop to subclass each grid. That basically fixed the problem, though the int_MouseOverGrid variable to keep track of which grid the mouse was over was losing its value when the program went to my MouseWheelGridScroller.cls module, so instead of using Public Dim... in my main form, I used Global int_MouseOverGrid as Integer in the class module, it keeps its value, and the scrolling is now working.

Thanks for the help. I won't mark this as Solved just yet (can you even do that here?) in case someone knows what's going on with VB6 crashing as described above. I've Googled it before and could find no help. (I'm not really hijacking my own thread because I still suspect that it is related to the mousewheel thing.)
 
>I started having a problem that if I hit an error in my code while running it from inside VB6 and clicked End on the error message box to close the program, VB6 would also close

A classic problem with standard subclassing in VB6 IDE.

The simplified explanation of the problem is that if we don't close the program cleanly (an example of which would be hitting End after an error, as you have discovered) the subclassed control is still pointing at what it thinks is the subclassing code (the Wndproc in your case), but that code is now terminated and no longer where it was. The location in memory that is being pointed to is in fact now junk (or in perhaps slightly more technical terms: the function pointer in use is now invalid). Which the subclassed control tries to run when it performs its own teardown routines ... At which point, goodbye VB IDE. Same can happen if you make some edits in break mode - that may cause your code to recompile, thus moving WndProc, and thus - again- invalidating the function pointer in the subclassed control(s) ...

 
(BTW, it might be worth pointing out that these days I'd probably use a low level mouse hook for this rather than subclassing)
 
it might be worth pointing out that these days I'd probably use a low level mouse hook for this rather than subclassing

What's a "low level mouse hook"? I've been using VB since version 1, but I've never felt the need to get deep into the real technical stuff.

In the old days, we used to call this "not 30+ years of experience but 1 year of experience 30+ times.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top