Link to home
Start Free TrialLog in
Avatar of PPC022499
PPC022499Flag for Canada

asked on

Can't get SendMessage with WM_VSCROLL and SB_THUMBPOSITION and/or B_THUMBTRACK to work

I am wanting to create and application which sends the smoothest possible scrolling command to another application. This target application is projected on a screen and loads of people will sit in a meeting and read text there for a long time.
My goal is that the user should not have to constantly sit and manually scroll with the mouse, and to have the automatic scrolling more smooth and consistent. The smoothest scrolling I know is made when pushing the middle button which gives the arrow group icon and then panning the mouse down below. Scrolling is down on pixel level then, and using the mouse wheel (not an option) is per line.

The application waits a couple of seconds after a click, then grabs the hWnd of the active window and sends the signals to it.

Here's an extract of my code, which doesn't work.
What needs to be changed/added for it to work? Other solutions with a smooth

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal Wparam As Long, ByRef Lparam As Any) As Long

Public Declare Function GetForegroundWindow Lib "user32" () As Long

Public Const WM_VSCROLL As Integer = &H115
Public Const SB_THUMBPOSITION = 4
Public Const SB_THUMBTRACK = 5
Public Const SB_ENDSCROLL = 8
Public Const WM_MOUSEWHEEL = &H20A 'Works but not used...

Private Sub Send_Click()
  Dim lCurHwnd As Long
  Dim lResult As Long
 
  ' Wait 2 seconds and then grab window
  Sleep 2000
  lCurHwnd = GetForegroundWindow

  'This works but is undesired:
  'SendMessage lCurHwnd, WM_MOUSEWHEEL, WHEEL_DELTA * &H10000, 50

  lResult = SendMessage(lCurHwnd, WM_VSCROLL, MakeLong(SB_THUMBPOSITION, 100), 0)
  Sleep 1000
  lResult = SendMessage(lCurHwnd, WM_VSCROLL, MakeLong(SB_THUMBTRACK, 300), 0)
  Sleep 1000
  lResult = SendMessage(lCurHwnd, WM_VSCROLL, MakeLong(SB_THUMBTRACK, 400), 0)
  Sleep 1000
  lResult = SendMessage(lCurHwnd, WM_VSCROLL, MakeLong(SB_THUMBTRACK, 500), 0)
  Sleep 1000
  lResult = SendMessage(lCurHwnd, WM_VSCROLL, SB_ENDSCROLL, 0)
End Sub
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Try using GetScrollInfo() and SetScrollInfo() isntead.

Some sample code here: (not tailored to your situation)
https://www.experts-exchange.com/questions/21181921/Determining-position-of-horizontal-scroll-bar-in-a-listbox.html#12405392
Avatar of PPC022499

ASKER

I've tried with GetScrollInfo() and SetScrollInfo() now, but GetScrollInfo doesn't return anything.

Here's my proto code, which gives me a message box with 0 for all but cbSize, which I set anyway...

  lCurHwnd = GetFocus
  scrl.cbSize = LenB(scrl)
  scrl.fMask = SIF_POS
 
  lResult = GetScrollInfo(lCurHwnd, SB_VERT, scrl)
  MsgBox Left$(sText, GetWindowText(lCurHwnd, ByVal sText, 255)) & vbCrLf & _
         "Result: " & lResult & vbCrLf & _
         "cb Size: " & scrl.cbSize & vbCrLf & _
         "nPos: " & scrl.nPos & vbCrLf & _
         "TrackPos: " & scrl.nTrackPos & vbCrLf & _
         "Min: " & scrl.nMin & vbCrLf & _
         "Max: " & scrl.nMax & vbCrLf & _
         "Page: " & scrl.nPage

I've also tried the following:
Public Declare Function ScrollWindowEx Lib "user32" (ByVal hWnd As Long, ByVal dx As Long, ByVal dy As Long, lprcScroll As RECT, lprcClip As RECT, ByVal hrgnUpdate As Long, lprcUpdate As RECT, ByVal fuScroll As Long) As Long
lResult = ScrollWindowEx(lCurHwnd, 0, 120, Null, Null, Null, Null, MakeLong(SW_SMOOTHSCROLL, 20))
but I can't even get it to compile, as it complains about the "Null"s, saying they can't be passed as ByRef...
Seems to me ScrollWindowEx is the easier one for me to use.


Sometimes it's not the main window that should receive the message.  For instance, in Notepad, the child "Edit" window is the one that does the gruntwork.

Are you sure it's the main window that has the scrollbars?...it could be a child window displaying those.

Tools such as Spy++ or the free Winspector can be very helpful in figuring out which window belongs to which etc...
I started a C program instead of VB, and got ScrollWindow to work nicely. Yet this scrolls the main window, and as you suggest, it's likely a child window which should receive the command.
Is there a good way of finding the hwnd of the child window which should be under the mouse?

Thanks!

Code:
int APIENTRY WinMain(....blabla..)
  HWND hwnd;
  char buf[BUF_LEN];
  int i;

  Sleep(2000);
  hwnd = GetForegroundWindow();
  GetWindowText(hwnd, buf, BUF_LEN);
  OutputDebugString(buf);
  OutputDebugString("\n");
   
  for (i=0; i<100; i++)
  {
    ScrollWindow(hwnd, 0, 1, (RECT*) NULL, (RECT*) NULL);
    UpdateWindow(hwnd);
    Sleep(50);
  }
Update: If I run Spy++ and watch ALL messages to MS Excel (for example) when I use the middle-button-click-scroll with the 4 arrows, I get no messages while this mode is active. Not even cursor pos.
Tried this too, with no success (attached too):

int MakeLong(int HiWord, int LoWord)
{
  return (HiWord * 0x10000) | (LoWord & 0xFFFF);
}


// MAIN HERE:

 SendMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MakeLong(point.x, point.y));
  Sleep(5000);
  OutputDebugString("Sent right button click\n");

  OutputDebugString("Sending mouse move events\n");
  SendMessage(hwnd, WM_MBUTTONDOWN, MK_MBUTTON, MakeLong(point.x, point.y));
  for (i=0; i<100; i++) {
    point.x += 1;
    point.y += 1;
    SendMessage(hwnd, WM_MOUSEMOVE, MK_MBUTTON, MakeLong(point.x, point.y));
    Sleep(50);
  }
  SendMessage(hwnd, WM_MBUTTONUP, 0, MakeLong(point.x, point.y));
  OutputDebugString("Sent mouse move events\n");

int MakeLong(int HiWord, int LoWord)
{
  return (HiWord * 0x10000) | (LoWord & 0xFFFF);
}


// MAIN HERE:

 SendMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MakeLong(point.x, point.y));
  Sleep(5000);
  OutputDebugString("Sent right button click\n");

  OutputDebugString("Sending mouse move events\n");
  SendMessage(hwnd, WM_MBUTTONDOWN, MK_MBUTTON, MakeLong(point.x, point.y));
  for (i=0; i<100; i++) {
    point.x += 1;
    point.y += 1;
    SendMessage(hwnd, WM_MOUSEMOVE, MK_MBUTTON, MakeLong(point.x, point.y));
    Sleep(50);
  }
  SendMessage(hwnd, WM_MBUTTONUP, 0, MakeLong(point.x, point.y));
  OutputDebugString("Sent mouse move events\n");

Open in new window

This one has been sitting in the bottom of my Inbox for awhile...  =\

Where are you currently at?...have you progressed any further?
I never yet found a solution. I can't find a HWND for the scroll bar. When I use the following command:

ScrollWindowEx(hwnd, 0, -120, &rect, (RECT*) NULL, (HRGN) NULL, (LPRECT) NULL, SW_SCROLLCHILDREN | SW_INVALIDATE);

I can get the window to scroll, but it's incorrect and actually scrolls the whole drawing area of the window which means the drawing area part ways disappears under the frame of the window and the other end of the window doesn't get redrawn...

Still looking for a solution...
When I browse with Spy++, the window does not have any child windows. I can neither through Spy++ or code find any sub or child windows or HWNDs.

This didn't work any better either:
for (i=0; i<100; i++)  {
    ScrollWindow(hwnd, 0, 1, (RECT*) NULL, (RECT*) NULL);
    UpdateWindow(hwnd);
    Sleep(50);
}
Hmmm...I'm at a loss then too.  Wish I had an answer for you.  =\
Is the target app using WPF by chance?
http://en.wikipedia.org/wiki/Windows_Presentation_Foundation

...drawing everything with DirectX and no underlying GDI handles?
RE: ...drawing everything with DirectX and no underlying GDI handles?

I'm not sure. I'm testing it against MS Word, though. Thinking if it works there, it should work with our application too.

I am happy with a solution that emulates the middle button pan function. Where you get the icon with a dot in the middle and 4 arrows to all directions and then when you move out of this icon to any direction it will scroll in that direction. My code above for this doesn't work either, and has no effect. Can't even find a picutre of this icon to post here...

Thanks for trying!
ASKER CERTIFIED SOLUTION
Avatar of ee_auto
ee_auto

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial