6

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.

I have been trying with GetScrollBarInfo and SetScrollPos which I found at pinvoke without any success. Im not sure if this is the right way or not. I started playing with GetScrollBarInfo, but it doesn't seem to work.

I tried the code found at 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

Im not sure what I do wrong. How can I solve this?

4

3 に答える 3

6

WM_MOUSEWHEEL メッセージを送信して、必要なことを行うことができます。たとえば、C++ を使用して新しいメモ帳ウィンドウで下に 1 回スクロールするには、次のようにします。

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 が実際にスクロールされた領域の上にあるポイントに送信される必要がありますが、メモ帳などのプログラムではそうではありません。

于 2013-03-11T09:54:33.000 に答える
3

別のプロセスのウィンドウをスクロールしようとしている場合は、事実上、スクロール バーのクリックまたはキーの押下をシミュレートする必要があります。これを行う最もクリーンな方法は、.NET とネイティブ インターフェイスの両方を持つUI Automationを使用することです。

スクロールバー情報を要求することで、スクロールバーがどのように表示されるかについての情報を取得しているだけです。これでは、ウィンドウのコンテンツをスクロールする方法が得られません。ユーザーがスクロールバーを操作していると思わせることで、ターゲット アプリケーションにコンテンツをスクロールさせる必要があります。

于 2013-03-10T22:09:04.237 に答える