简体   繁体   English

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

[英]How to scroll Window in other process with Win32API

Im trying to create a program where I can send some process id of a process (that may be firefox, ie, notepad etc) to a method that scrolls window of the process. 我试图创建一个程序,我可以将一个进程的进程ID(可能是firefox,即记事本等)发送到滚动进程窗口的方法。

I have been trying with GetScrollBarInfo and SetScrollPos which I found at pinvoke without any success. 我一直在尝试使用GetScrollBarInfo和SetScrollPos,我在pinvoke找到了没有任何成功。 Im not sure if this is the right way or not. 我不确定这是不是正确的方法。 I started playing with GetScrollBarInfo, but it doesn't seem to work. 我开始玩GetScrollBarInfo,但它似乎不起作用。

I tried the code found at http://www.pinvoke.net/default.aspx/user32.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() returns errorcode 122 which means "The data area passed to a system call is too small", according to http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx GetLastWin32Error()返回错误代码122,这意味着“传递给系统调用的数据区域太小”,根据http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs。 85)的.aspx

Im not sure what I do wrong. 我不确定我做错了什么。 How can I solve this? 我怎么解决这个问题?

You could send a WM_MOUSEWHEEL message to do what you want. 您可以发送WM_MOUSEWHEEL消息来执行您想要的操作。 For example, to scroll down once in a new notepad window using C++: 例如,使用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));

To adapt that to C#, you could do something such as this: 要使其适应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);
}

Which could be used to scroll down once in a new notepad window like this: 这可以用于在新的记事本窗口中向下滚动一次,如下所示:

//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);

Some programs will require the lParam sent to be a point that's actually above the scrolled area, while others such as notepad will not. 有些程序要求发送的lParam是一个实际位于滚动区域上方的点,而其他程序如记事本则不会。

If you're trying to scroll the window of another process, you need to, in effect, simulate clicks on the scroll bar or key presses. 如果您正在尝试滚动其他进程的窗口,则需要实际模拟滚动条或按键上的单击。 The cleanest way to do that is to use UI Automation , which has both .NET and native interfaces. 最简洁的方法是使用UI Automation ,它同时具有.NET和本机接口。

By asking for the scrollbar info, you're simply getting information about how the scrollbar is displayed. 通过询问滚动条信息,您只需获取有关滚动条显示方式的信息。 That's not going to give you a way to scroll the window content. 这不会给你一种滚动窗口内容的方法。 You have to get the target application to scroll the content by making it think the user is operating the scrollbar. 您必须让目标应用程序通过让用户认为用户正在操作滚动条来滚动内容。

http://forums.codeguru.com/showthread.php?446352-How-to-scroll-active-window-SendMessage&p=1686041#post1686041 http://forums.codeguru.com/showthread.php?446352-How-to-scroll-active-window-SendMessage&p=1686041#post1686041

Final Code 最终守则

class Program
{
        [DllImport("user32.dll")]
        static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);


        [DllImport("user32.dll")]
        public static extern int SetScrollPos(IntPtr hWnd, System.Windows.Forms.Orientation nBar, int nPos, bool bRedraw);


        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);


        public struct GUITHREADINFO
        {
            public int cbSize;
            public int flags;
            public IntPtr hwndActive;
            public IntPtr hwndFocus;
            public IntPtr hwndCapture;
            public IntPtr hwndMenuOwner;
            public IntPtr hwndMoveSize;
            public IntPtr hwndCaret;
            public System.Drawing.Rectangle rcCaret;
        }


        const Int32 WM_VSCROLL = 0x0115;
        const Int32 SB_LINERIGHT = 1;


        static void Main(string[] args)
        {
            //create process in focus
            Process.Start("notepad++", "Source.cpp");
            Thread.Sleep(1000);
            GUITHREADINFO threadInfo = new GUITHREADINFO();
            threadInfo.cbSize = Marshal.SizeOf(threadInfo);

            GetGUIThreadInfo(0, ref threadInfo);
            SendMessage(threadInfo.hwndFocus, WM_VSCROLL, SB_LINERIGHT, 0);
            //SetScrollPos not work. Change only scrollbar without scroll window
            //SetScrollPos(threadInfo.hwndFocus, System.Windows.Forms.Orientation.Vertical, 10, true);           
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM