Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3197
  • Last Modified:

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
0
PPC022499
Asked:
PPC022499
  • 7
  • 5
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Try using GetScrollInfo() and SetScrollInfo() isntead.

Some sample code here: (not tailored to your situation)
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_21181921.html#12405392
0
 
PPC022499Author Commented:
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.


0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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...
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
PPC022499Author Commented:
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);
  }
0
 
PPC022499Author Commented:
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.
0
 
PPC022499Author Commented:
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

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
This one has been sitting in the bottom of my Inbox for awhile...  =\

Where are you currently at?...have you progressed any further?
0
 
PPC022499Author Commented:
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...
0
 
PPC022499Author Commented:
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);
}
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Hmmm...I'm at a loss then too.  Wish I had an answer for you.  =\
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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?
0
 
PPC022499Author Commented:
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!
0
 
ee_autoCommented:
Question PAQ'd, 500 points refunded, and stored in the solution database.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now