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

标签 c# winapi

我正在尝试创建一个程序,我可以在其中将某个进程(可能是 firefox,即记事本等)的进程 ID 发送到滚动进程窗口的方法。

我一直在尝试使用在 pinvoke 上找到的 GetScrollBarInfo 和 SetScrollPos,但没有成功。我不确定这是否正确。我开始玩 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 是实际位于滚动区域上方的点,而其他程序(如记事本)则不会。

关于c# - 如何使用 Win32API 在其他进程中滚动窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15326718/

相关文章:

winapi - 查找已安装产品的所有组件

c++ - 如何更改 SysDateTimePick32 或 CDateTimeCtrl 的背景颜色?

c# - 针对每个 Web 请求和生命周期范围的 SimpleInjector 混合生活方式

c# - WPF : Adding Border to an image programmatically

c# - c#反编译器是如何工作的

windows - 使用 WinAPI 进行全屏管理

windows - 如何在 Windows 7 Aero 任务预览中创建自己的控件?

c# - 如何像 Vue 一样从父层向 Blazor 组件随机添加 CSS 属性?

c# - 限制在 WPF 中扩展 TreeNode 时 TreeView 的深度

c# - 如何在我的 C# 应用程序中获得类似于 Spy++ 的功能?