Sending scroll messages to external applications

T

Thomas Wieczorek

Hello!

I am starting and resizing external applications(Microsoft Word/Excel/
Powerpoint Viewer Notepad, Acrobat Reader) to display some documents.
I have to scroll some off those windows, too. I think I need the Win32
API function FindWindowEX to find the scroll control or the Edit
control that implements it with WS_HSCROLL and/or WS_VSCROLL.
My problem is that I have no idea how to get the right handle. I am
using Microsof Managed Spy(http://msdn.microsoft.com/msdnmag/issues/
06/04/ManagedSpy/) to inspect the windows. Process and their windows
are clearly arranged:
exe-name program title [process id]
+ handle [Classes with subclasses]
handle [Just classes]
E.g. notepad.ex looks this
notepad PATH.txt - Editor
+ 655600 [Notepad]
327906 [Edit]
3408122 [msctls_statusbar32]
196948 [MSCTFIME UI]
786688 [IME]

I think that I have to get the _327906_ handle of the Edit class to be
able to do anything with it, but I can't get it with the following
code:

Public Const WM_VSCROLL As Int32 = &H115
Public Const SB_PAGEDOWN As Int32 = 3

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function FindWindowEx(ByVal parentHandle As IntPtr, _
ByVal childAfter As IntPtr, _
ByVal lclassName As String, _
ByVal windowTitle As String) As IntPtr
End Function

<DllImport("user32.dll", SetLastError:=True)> _
Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As
Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As
<MarshalAs(UnmanagedType.Bool)> Boolean
' No code here.
End Function

Public Class File
Private _path As String
Private _scrolltechnik As Scrolltechnik
Private _format As Format
Private _scrolltime As Integer ' in millisekunden
Private _show_always As Boolean
Private _file_viewer As SNK.Application
Friend sInfo As STARTUPINFO
Friend pInfo As PROCESS_INFORMATION

Public Sub New(ByVal path As String, ByVal app As SNK.Application,
Optional ByVal scrolltime As Integer = 2000, Optional ByVal scrolltec
As Scrolltechnik = SNK.Scrolltechnik.Zeilenweise, Optional ByVal form
As Format = SNK.Format.Hochformat)
_path = path
_scrolltechnik = scrolltec
_scrolltime = scrolltime
_format = form
_file_viewer = app
sInfo = New STARTUPINFO
pInfo = New PROCESS_INFORMATION
End Sub
End Class

Public Function Scroll(_current_file as File) As Boolean
Dim retValue As Boolean
Dim si As SCROLLINFO
Dim lRet As Integer
Dim windowHandle As IntPtr
Dim scrollbarHandle As IntPtr


si = New SCROLLINFO
Dim w As Integer = _current_file.pInfo.dwProcessId
'Dim w As Integer = _current_file.pInfo.dwThreadId
Dim h As Integer = 0
Dim lclassname As String = "Edit"
windowHandle = New IntPtr(w)
scrollbarHandle = New IntPtr(h)
scrollbarHandle = FindWindowEx(windowHandle, New IntPtr(0),
lclassname, "")
lRet = GetScrollInfo(scrollbarHandle, ScrollBarDirection.SB_VERT,
si)
If 0 = lRet Then
lRet =
System.Runtime.InteropServices.Marshal.GetLastWin32Error()
MsgBox("Last Win32-Errorcode: " & lRet.ToString)
Else
retValue = SendMessage(scrollbarHandle, WM_VSCROLL, _
New IntPtr(ScrollBarCommands.SB_PAGEDOWN), IntPtr.Zero)
End If

Return retValue
End Function

You can see that I am trying to get the handle of a class(lclassname)
with FindowWindowEx and I am passing the process ID to it. It doesn't
work to get the Edit handle directly, so I tried to get the handle of
the Notepad class instead, but I still don't get anything.
Do you see an error in my code or my thoughts? Do you know another way
to handle the problem?

Another problem occurs, when I grab the Edit handle with Managed Spy.
It can use it in Debug mode to initialize the scrollbar
handle(scrollbarHandle = New IntPtr(h) and skip FindWindowEx), but
nothing happens when I SendMessage the scroll message WM_VSCROLL to
it.
Can you explain that behaviour to me please?

Best Regards,

Thomas
 
T

Thomas Wieczorek

Another problem occurs, when I grab the Edit handle with Managed Spy.
It can use it in Debug mode to initialize the scrollbar
handle(scrollbarHandle = New IntPtr(h) and skip FindWindowEx), but
nothing happens when I SendMessage the scroll message WM_VSCROLL to
it.

I forgot to mention that SendMessage is returning true, when I send
the WM_VSCROLL directly to it, but it doesn't scroll.
 
T

Thomas Wieczorek

I forgot to mention that SendMessage is returning true, when I send
the WM_VSCROLL directly to it, but it doesn't scroll.

It works now! I passed a wrong handle, but I still can't get the Edit
handle programatically. Can you please help me there with FindWindowEx
or another Win32 API function which I missed?
The full question again:
I am starting and resizing external applications(Microsoft Word/Excel/
Powerpoint Viewer Notepad, Acrobat Reader) to display some documents.
I have to scroll some off those windows, too. I think I need the Win32
API function FindWindowEX to find the scroll control or the Edit
control that implements it with WS_HSCROLL and/or WS_VSCROLL.
My problem is that I have no idea how to get the right handle. I am
using Microsof Managed Spy(http://msdn.microsoft.com/msdnmag/issues/
06/04/ManagedSpy/) to inspect the windows. Process and their windows
are clearly arranged:
exe-name program title [process id]
+ handle [Classes with subclasses]
handle [Just classes]
E.g. notepad.ex looks this
notepad PATH.txt - Editor
+ 655600 [Notepad]
327906 [Edit]
3408122 [msctls_statusbar32]
196948 [MSCTFIME UI]
786688 [IME]

I think that I have to get the _327906_ handle of the Edit class to be
able to do anything with it, but I can't get it with the following
code:

Public Const WM_VSCROLL As Int32 = &H115
Public Const SB_PAGEDOWN As Int32 = 3

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function FindWindowEx(ByVal parentHandle As IntPtr, _
ByVal childAfter As IntPtr, _
ByVal lclassName As String, _
ByVal windowTitle As String) As IntPtr
End Function

<DllImport("user32.dll", SetLastError:=True)> _
Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As
Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As
<MarshalAs(UnmanagedType.Bool)> Boolean
' No code here.
End Function

Public Class File
Private _path As String
Private _scrolltechnik As Scrolltechnik
Private _format As Format
Private _scrolltime As Integer ' in millisekunden
Private _show_always As Boolean
Private _file_viewer As SNK.Application
Friend sInfo As STARTUPINFO
Friend pInfo As PROCESS_INFORMATION

Public Sub New(ByVal path As String, ByVal app As SNK.Application,
Optional ByVal scrolltime As Integer = 2000, Optional ByVal scrolltec
As Scrolltechnik = SNK.Scrolltechnik.Zeilenweise, Optional ByVal form
As Format = SNK.Format.Hochformat)
_path = path
_scrolltechnik = scrolltec
_scrolltime = scrolltime
_format = form
_file_viewer = app
sInfo = New STARTUPINFO
pInfo = New PROCESS_INFORMATION
End Sub
End Class

Public Function Scroll(_current_file as File) As Boolean
Dim retValue As Boolean
Dim si As SCROLLINFO
Dim lRet As Integer
Dim windowHandle As IntPtr
Dim scrollbarHandle As IntPtr

si = New SCROLLINFO
Dim w As Integer = _current_file.pInfo.dwProcessId
'Dim w As Integer = _current_file.pInfo.dwThreadId
Dim h As Integer = 0
Dim lclassname As String = "Edit"
windowHandle = New IntPtr(w)
scrollbarHandle = New IntPtr(h)
scrollbarHandle = FindWindowEx(windowHandle, New IntPtr(0),
lclassname, "")
lRet = GetScrollInfo(scrollbarHandle, ScrollBarDirection.SB_VERT,
si)
If 0 = lRet Then
lRet =
System.Runtime.InteropServices.Marshal.GetLastWin32Error()
MsgBox("Last Win32-Errorcode: " & lRet.ToString)
Else
retValue = SendMessage(scrollbarHandle, WM_VSCROLL, _
New IntPtr(ScrollBarCommands.SB_PAGEDOWN), IntPtr.Zero)
End If

Return retValue
End Function

You can see that I am trying to get the handle of a class(lclassname)
with FindowWindowEx and I am passing the process ID to it. It doesn't
work to get the Edit handle directly, so I tried to get the handle of
the Notepad class instead, but I still don't get anything.
Do you see an error in my code or my thoughts? Do you know another way
to handle the problem?

Another problem occurs, when I grab the Edit handle with Managed Spy.
It can use it in Debug mode to initialize the scrollbar
handle(scrollbarHandle = New IntPtr(h) and skip FindWindowEx), but
nothing happens when I SendMessage the scroll message WM_VSCROLL to
it.
Can you explain that behaviour to me please?

Best Regards,

Thomas

Sorry for any trouble. I am very new to API programming.
 
K

kimiraikkonen

I forgot to mention that SendMessage is returning true, when I send
the WM_VSCROLL directly to it, but it doesn't scroll.

It works now! I passed a wrong handle, but I still can't get the Edit
handle programatically. Can you please help me there with FindWindowEx
or another Win32 API function which I missed?
The full question again:






I am starting and resizing external applications(Microsoft Word/Excel/
Powerpoint Viewer Notepad, Acrobat Reader) to display some documents.
I have to scroll some off those windows, too. I think I need the Win32
API function FindWindowEX to find the scroll control or the Edit
control that implements it with WS_HSCROLL and/or WS_VSCROLL.
My problem is that I have no idea how to get the right handle. I am
using Microsof Managed Spy(http://msdn.microsoft.com/msdnmag/issues/
06/04/ManagedSpy/) to inspect the windows. Process and their windows
are clearly arranged:
exe-name program title [process id]
    + handle [Classes with subclasses]
       handle [Just classes]
E.g. notepad.ex looks this
notepad PATH.txt - Editor
    + 655600 [Notepad]
              327906   [Edit]
              3408122 [msctls_statusbar32]
       196948 [MSCTFIME UI]
       786688 [IME]
I think that I have to get the _327906_ handle of the Edit class to be
able to do anything with it, but I can't get it with the following
code:
Public Const WM_VSCROLL As Int32 = &H115
Public Const SB_PAGEDOWN As Int32 = 3
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>_
Public Function FindWindowEx(ByVal parentHandle As IntPtr, _
                  ByVal childAfter As IntPtr, _
                  ByVal lclassName As String, _
                  ByVal windowTitle As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As
Integer, _
    ByVal wParam As IntPtr, ByVal lParam As IntPtr) As
<MarshalAs(UnmanagedType.Bool)> Boolean
    ' No code here.
End Function
Public Class File
    Private _path As String
    Private _scrolltechnik As Scrolltechnik
    Private _format As Format
    Private _scrolltime As Integer ' in millisekunden
    Private _show_always As Boolean
    Private _file_viewer As SNK.Application
    Friend sInfo As STARTUPINFO
    Friend pInfo As PROCESS_INFORMATION
    Public Sub New(ByVal path As String, ByVal app As SNK.Application,
Optional ByVal scrolltime As Integer = 2000, Optional ByVal scrolltec
As Scrolltechnik = SNK.Scrolltechnik.Zeilenweise, Optional ByVal form
As Format = SNK.Format.Hochformat)
        _path = path
        _scrolltechnik = scrolltec
        _scrolltime = scrolltime
        _format = form
        _file_viewer = app
        sInfo = New STARTUPINFO
        pInfo = New PROCESS_INFORMATION
    End Sub
End Class
Public Function Scroll(_current_file as File) As Boolean
    Dim retValue As Boolean
    Dim si As SCROLLINFO
    Dim lRet As Integer
    Dim windowHandle As IntPtr
    Dim scrollbarHandle As IntPtr
    si = New SCROLLINFO
    Dim w As Integer = _current_file.pInfo.dwProcessId
    'Dim w As Integer = _current_file.pInfo.dwThreadId
    Dim h As Integer = 0
    Dim lclassname As String = "Edit"
    windowHandle = New IntPtr(w)
    scrollbarHandle = New IntPtr(h)
    scrollbarHandle = FindWindowEx(windowHandle, New IntPtr(0),
lclassname, "")
    lRet = GetScrollInfo(scrollbarHandle, ScrollBarDirection.SB_VERT,
si)
    If 0 = lRet Then
        lRet =
System.Runtime.InteropServices.Marshal.GetLastWin32Error()
        MsgBox("Last Win32-Errorcode: " & lRet.ToString)
    Else
        retValue = SendMessage(scrollbarHandle, WM_VSCROLL, _
            New IntPtr(ScrollBarCommands.SB_PAGEDOWN), IntPtr.Zero)
    End If
    Return retValue
End Function
You can see that I am trying to get the handle of a class(lclassname)
with FindowWindowEx and I am passing the process ID to it. It doesn't
work to get the Edit handle directly, so I tried to get the handle of
the Notepad class instead, but I still don't get anything.
Do you see an error in my code or my thoughts? Do you know another way
to handle the problem?
Another problem occurs, when I grab the Edit handle with Managed Spy.
It can use it in Debug mode to initialize the scrollbar
handle(scrollbarHandle = New IntPtr(h) and skip FindWindowEx), but
nothing happens when I SendMessage the scroll message WM_VSCROLL to
it.
Can you explain that behaviour to me please?
Best Regards,

Sorry for any trouble. I am very new to API programming.- Hide quoted text-

- Show quoted text -

Look at this sample for listening scrolls:
http://www.vb-tips.com/Scroll.aspx
 
T

Thomas Wieczorek

Look at this sample for listening scrolls:http://www.vb-tips.com/Scroll.aspx

Thank you!
This is not what I am looking for. I don't want to listen to scroll
message, I want to send them to external applications. My problem is
that I cannot get the handle of the control which contains the scroll
bars, e.g. I have started notepad.exe showing a file with
CreateProcess, I have the process and thread information about it
stored in a PROCESSINFO structure and I am trying to use FindWindowEx
to get its window of the "Edit" class.
I have no idea how to get the handle of the Edit. Do you have any
ideas?
 
K

kimiraikkonen

Thank you!
This is not what I am looking for. I don't want to listen to scroll
message, I want to send them to external applications. My problem is
that I cannot get the handle of the control which contains the scroll
bars, e.g. I have started notepad.exe showing a file with
CreateProcess, I have the process and thread information about it
stored in a PROCESSINFO structure and I am trying to use FindWindowEx
to get its window of the "Edit" class.
I have no idea how to get the handle of the Edit. Do you have any
ideas?

Thomas,
you may want to check FindWindowEx and similar functions which you
might need using p/invoke:
http://www.pinvoke.net/default.aspx/user32.FindWindowEx
 
T

Thomas Wieczorek

Thomas,
you may want to check FindWindowEx and similar functions which you
might need using p/invoke:http://www.pinvoke.net/default.aspx/user32.FindWindowEx

Thank you I tried to use FindWindowEx with a handle from the
PROCESS_INFORMATION structure, but I didn't find a way to get the main
window handle of a process. Luckily I found out that the .Net class
Process can return the thread handle for MoveWindow which needs it -
it's in Process.Threads(0).id!
I am using now Process.mainWindowHandle as the starting point for
FindWindowEx.
I still have to find a way to make the Microsoft Word Viewer scroll a
document, but it is no big problem(I _hope_ so :)

Best regards,

Thomas
 
T

Thomas Wieczorek

I still have to find a way to make the Microsoft Word Viewer scroll a
document, but it is no big problem(I _hope_ so :)

Hello, I just ran into a problem with FindWindowEx. I can't get to the
nested scroll bar in the Word Viewer:

WORDVIEW PATH.txt - Microsoft Word Viewer
329270 [OleDdeWndClass]
+ 460298 [OpusApp] <-- I have the handle of that one in
_process.MainWindowHandle
198174 [MsoCommandBarDock]
198178 [MsoCommandBarDock]
198176 [MsoCommandBarDock]
198180 [MsoCommandBarDock]
+ 460294 [_WwF]
+ 460350 [_WwB]
394812 [_WwC]
394768 [ScrollBar] <-- I need that one
198194 [_WwC]
198200 [ScrollBar]
198192 [_WwC]
198190 [_WwC]
525836 [_WwC]
196948 [MSCTFIME UI]
786688 [IME]

I tried it with this code:

Public Overrides Function GetScrollbarHandle() As IntPtr
Dim childHandle As IntPtr

childHandle = New IntPtr(0)
' the vertical scroll bar is nested a few layers
childHandle = FindWindowEx(_process.MainWindowHandle, New
IntPtr(0), "_WwF", "") ' <-- works!

If childHandle.ToInt32 <> IntPtr.Zero.ToInt32 Then

childHandle = FindWindowEx(childHandle, New IntPtr(0), "_WwB",
"") <-- This is returning 0

If childHandle.ToInt32 <> IntPtr.Zero.ToInt32 Then

childHandle = FindWindowEx(childHandle, New IntPtr(0),
"ScrollBar", "")

End If

End If

Return childHandle
End Function

Can you find any errors in my code? I am trying different things, but
it doesn't work.

Kindly,

Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top