Как прокрутить Окно в другом процессе с Win32API
Я пытаюсь создать программу, в которой я могу отправить некоторый идентификатор процесса (например, firefox, например, блокнот и т. Д.) В метод, который прокручивает окно процесса.
Я пытался с 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
Я не уверен, что я делаю неправильно. Как я могу решить это?
2 ответа
Вы можете отправить сообщение 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 находилась над точкой прокрутки, а другие, такие как блокнот, не будут.
Если вы пытаетесь прокрутить окно другого процесса, вам, по сути, нужно смоделировать щелчки на полосе прокрутки или нажатия клавиш. Самый чистый способ сделать это - использовать UI Automation, который имеет как.NET, так и нативный интерфейс.
Запрашивая информацию о полосе прокрутки, вы просто получаете информацию о том, как отображается полоса прокрутки. Это не даст вам возможность прокручивать содержимое окна. Вы должны заставить целевое приложение прокручивать контент, заставляя его думать, что пользователь использует полосу прокрутки.
http://forums.codeguru.com/showthread.php?446352-How-to-scroll-active-window-SendMessage&p=1686041
Окончательный код
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);
}
}