如何使用Win32API在其他进程中滚动窗口

问题描述:

我试图创建一个程序,我可以将进程的进程ID(可能是firefox,即记事本等)发送到滚动进程窗口的方法。如何使用Win32API在其他进程中滚动窗口

我一直在尝试GetScrollBarInfo和SetScrollPos,我发现在pinvoke没有任何成功。我不知道这是否正确。我开始玩GetScrollBarInfo,但它似乎没有工作。

我试图在http://www.pinvoke.net/default.aspx/user32.getscrollbarinfo找到的代码

[StructLayout(LayoutKind.Sequential)] 
public struct SCROLLBARINFO 
{ 
    public int cbSize; 
    public Rectangle rcScrollBar; 
    public int dxyLineButton; 
    public int xyThumbTop; 
    public int xyThumbBottom; 
    public int reserved; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 
    public int[] rgstate; 
} 

private const uint OBJID_HSCROLL = 0xFFFFFFFA; 
private const uint OBJID_VSCROLL = 0xFFFFFFFB; 
private const uint OBJID_CLIENT = 0xFFFFFFFC; 

private int Scroll(int ProcessID) 
{ 
    IntPtr handle = Process.GetProcessById(ProcessID).MainWindowHandle; 
    SCROLLBARINFO psbi = new SCROLLBARINFO(); 
    psbi.cbSize = Marshal.SizeOf(psbi); 
    int nResult = GetScrollBarInfo(handle, OBJID_CLIENT, ref psbi); 
    if (nResult == 0) 
    { 
     int nLatError = Marshal.GetLastWin32Error(); 
    } 
} 

GetLastWin32Error()返回错误代码122,这意味着“传递给系统调用的数据区域太小”,根据http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx

林不知道我做错了什么。我该如何解决这个问题?

你可以发送WM_MOUSEWHEEL消息来做你想做的。例如,要倒一次在一个新的记事本窗口中使用C++滚动:

HWND hwnd = FindWindowEx(FindWindow(NULL, "Untitled - Notepad"), NULL, "Edit", NULL); 
RECT r; 
GetClientRect(hwnd, &r); 
SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA * -1), MAKELPARAM(r.right/2, r.bottom/2)); 

适应,为C#中,你可以做一些像这样的:

[DllImport("user32.dll", CharSet = CharSet.Auto)] 
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, ref Point lParam); 

private void ScrollWindow(IntPtr hwnd, Point p, int scrolls = -1) 
{ 
    SendMessage(hwnd, WM_MOUSEWHEEL, (WHEEL_DELTA * scrolls) << 16, ref p); 
} 

这可能是用来向下滚动一次在一个新的记事本窗口是这样的:

//Imports 
[DllImport("user32.dll", SetLastError = true)] 
static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

[DllImport("user32.dll", SetLastError = true)] 
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 
... 
//Actual code 
IntPtr hwnd = FindWindowEx(FindWindow(null, "Untitled - Notepad"), IntPtr.Zero, "Edit", null); 
Point p = new Point(0, 0); 
ScrollWindow(hwnd, p); 

有些程序会要求lParam的发送是一个点,实际上是在滚动区域上方,而其他如记事本不会。

+0

谢谢。我会稍后再试! :) – 2013-03-12 09:21:12

+0

寻找这方面的信息似乎有点难。你的例子很好用。既然你似乎是我所知道的少数人知道的事情之一,你从哪里得到这些信息?我想进一步概括这个,所以它不仅仅是记事本。我不知道“编辑”来自哪里。那是什么?我怎样才能找到其他程序的等价物? – 2013-03-13 22:56:16

+0

“编辑”是记事本中需要将滚动发送到的控件。许多浏览器不会要求它被发送到控件 - 例如,我只用FindWindow尝试(null,“当前页面名称 - Opera”);和滚动工作正常。我过去使用过WM_MOUSEWHEEL,并且知道在低级别的鼠标钩子中使用它需要什么。如果你想得到一个需要发送到其他窗口的控件,可以查看EnumChildWindows或者使用WinSpy ++。 欲了解更多信息: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx – Jammerx2 2013-03-14 20:26:44

如果您要滚动另一个进程的窗口,实际上需要模拟滚动条或按键上的点击。最简单的方法是使用UI Automation,它具有.NET和本机接口。

通过询问滚动条信息,您只需获取有关如何显示滚动条的信息。这不会给你一种滚动窗口内容的方法。您必须让目标应用程序通过让用户认为用户正在操作滚动条来滚动内容。

+0

这听起来像一个更通用的方式来做到这一点。肯定会研究它。谢谢!! :) – 2013-03-12 09:22:10