19

我一直在四处寻找,但我还没有找到如何从 C# 中做到这一点。

我想这样做,这样我就可以告诉 Google Chrome从我的 C# 应用程序中前进后退打开新选项卡关闭选项卡打开新窗口关闭窗口。

我使用 WinAmp 做了类似的事情

[DllImport("user32", EntryPoint = "SendMessageA")]
private static extern int SendMessage(int Hwnd, int wMsg, int wParam, int lParam);

和其他一些人。但我不知道要发送什么消息或如何找到将其传递到哪个窗口或任何东西。

那么有人可以告诉我如何将这 6 个命令从 C# 发送到 Chrome 吗?谢谢

编辑:好的,我被否决了,所以也许我不够清楚,或者人们认为我没有试图自己解决这个问题。

首先,我对整个 DllImport 的东西不是很好。我仍在学习这一切是如何运作的。

几年前我发现了如何在winamp中做同样的想法,我正在查看我的代码。我这样做是为了让我可以从我的 C# 代码中跳过一首歌曲、返回、播放、暂停和停止 winamp。我从导入开始:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow([MarshalAs(UnmanagedType.LPTStr)] string lpClassName, [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern int SendMessageA(IntPtr hwnd, int wMsg, int wParam, uint lParam);
    [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    public static extern int GetWindowText(IntPtr hwnd, string lpString, int cch);
    [DllImport("user32", EntryPoint = "FindWindowExA")]
    private static extern int FindWindowEx(int hWnd1, int hWnd2, string lpsz1, string lpsz2);
    [DllImport("user32", EntryPoint = "SendMessageA")]
    private static extern int SendMessage(int Hwnd, int wMsg, int wParam, int lParam);

然后我发现使用它的代码将这些常量用于我发送的消息。

    const int WM_COMMAND = 0x111;
    const int WA_NOTHING = 0;
    const int WA_PREVTRACK = 40044;
    const int WA_PLAY = 40045;
    const int WA_PAUSE = 40046;
    const int WA_STOP = 40047;
    const int WA_NEXTTRACK = 40048;
    const int WA_VOLUMEUP = 40058;
    const int WA_VOLUMEDOWN = 40059;
    const int WINAMP_FFWD5S = 40060;
    const int WINAMP_REW5S = 40061;

我将通过以下方式获取hwnd(将消息发送到的程序):

IntPtr hwnd = FindWindow(m_windowName, null);

然后我会向该程序发送一条消息:

SendMessageA(hwnd, WM_COMMAND, WA_STOP, WA_NOTHING);

我假设我会为 Google Chrome 做一些与此非常相似的事情。但我不知道其中一些值应该是什么,我四处搜索试图找到答案,但我做不到,这就是我在这里问的原因。所以我的问题是如何获得以下值:

m_windowNameWM_COMMAND

然后,不同命令的值,前进后退新标签关闭标签新窗口关闭窗口

4

4 回答 4

10

在http://dev.chromium.org/developers开始您的研究


编辑:向窗口发送消息只是工作的一半。窗口必须响应该消息并采取相应措施。如果该窗口不知道消息或根本不在乎,您就没有机会通过发送窗口消息来控制它。

您正在查看有关如何远程控制 Winamp 的实现细节。发送消息只是其中一种方式,也是 Winamp 开发人员选择的方式。您使用的那些消息是用户定义的消息,仅对Winamp 具有特定含义。

第一步你要做的是找出Chromium是否支持某种远程控制以及这些机制是什么。

于 2008-09-29T08:33:26.303 回答
7

您可以使用 Visual Studio 的 Spy++ 并按 CTRL+F 轻松获取窗口名称,然后找到 chrome。我试过了,得到了

外窗的“Chrome_VistaFrame”。包含网页的实际窗口是“Chrome_RenderWidgetHostHWND”。

就 WM_COMMAND 而言 - 您需要进行试验。您显然想要发送按钮点击(我头顶的 WM_MOUSEDOWN)。由于后退,前进按钮不是它们自己的窗口,因此您需要弄清楚如何通过在某个 x,y 位置模拟鼠标单击来做到这一点,以便 chrome 知道您在做什么。或者您可以发送等效于后退/前进等的键盘快捷键。

我前段时间写的一个例子是用 trillian 和 winamp 做的:通过 c# 和 winapi 向 windows 发送消息

还有一些工具可以使用脚本语言来宏处理这种事情——我用过 autoit:autoit.com

于 2008-09-29T09:08:02.367 回答
4

好的,这就是我到目前为止所得到的......我有点知道我需要做什么,但这只是现在做的问题......

这是 Spy++ 的窗口,我锁定了Chrome_RenderWidgetHostHWND并单击了键盘上的后退按钮。这是我得到的: 替代文字

所以这是我的假设,我现在一直在玩这个,我只是无法弄清楚这些

IntPtr hWnd = FindWindow("Chrome_RenderWidgetHostHWND", null);
SendMessage(hWnd, WM_KEYDOWN, VK_BROWSER_BACK, 0);
SendMessage(hWnd, WM_KEYUP,   VK_BROWSER_BACK, 0);

现在,我只是不知道应该使 WM_KEYDOWN/UP 值或 VK_BROWSER_BACK/FORWARD 值做什么......我试过这个:

const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int VK_BROWSER_BACK = 0x6A;
const int VK_BROWSER_FORWARD = 0x69;

我从刚刚展示的图像中获得的后两个值,即这两个键的 ScanCodes。我不知道我是否做得对。我在谷歌搜索 WM_KEYDOWN 值后得到的前两个值,有人使用 &H100 和 &H101 作为这两个值。我尝试了其他几个我见过的随机想法。我就是想不通。

哦,这是 SendMessage 方法

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, uint lParam);
于 2008-09-29T18:59:34.023 回答
4

这是一个很好的互操作常量站点:

呼唤

另一种查找值的方法是搜索 koders.com,使用 C# 作为语言,查找 WM_KEYDOWN 或您所追求的常量:

Koders.com 搜索

&H 值看起来像是来自 VB(6)。pinvoke 和 koders 都返回 VK_BROWSER_FORWARD 的结果,

private const UInt32 WM_KEYDOWN        = 0x0100;
private const UInt32 WM_KEYUP          = 0x0101;

public const ushort VK_BROWSER_BACK = 0xA6;
public const ushort VK_BROWSER_FORWARD = 0xA7;
public const ushort VK_BROWSER_REFRESH = 0xA8;
public const ushort VK_BROWSER_STOP = 0xA9;
public const ushort VK_BROWSER_SEARCH = 0xAA;
public const ushort VK_BROWSER_FAVORITES = 0xAB;
public const ushort VK_BROWSER_HOME = 0xAC;

(有趣的是,考虑到 VK_* 是 1 个字节的 0-255 值,并且人们已经将它们设为 uint,有多少 VK 常量的错误定义在浮动,这很有趣)。

看起来与您的常量略有不同。我认为您所追求的功能是 SendInput (但我没有尝试过),因为它是一个虚拟键。

[DllImport("User32.dll")]
private static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] KEYBOARD_INPUT[] input, int structSize);

参数说明:

参数

  • nInputs - pInputs 数组中的结构数。
  • pInputs - 指向 INPUT 结构数组的指针。每个结构代表一个要插入键盘或鼠标输入流的事件。
  • cbSize - 指定 INPUT 结构的大小(以字节为单位)。如果 cbSize 不是 INPUT 结构的大小,则函数失败。

这需要一个 KEYBOARD_INPUT 类型:

[StructLayout(LayoutKind.Sequential)] 
public struct KEYBOARD_INPUT
{ 
    public uint type; 
    public ushort vk; 
    public ushort scanCode; 
    public uint flags; 
    public uint time; 
    public uint extrainfo; 
    public uint padding1; 
    public uint padding2; 
}

最后是一个样本,我没有测试它是否有效:

/*
typedef struct tagKEYBDINPUT {
    WORD wVk;
    WORD wScan;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;
*/
public static void sendKey(int scanCode, bool press)
{
        KEYBOARD_INPUT[] input = new KEYBOARD_INPUT[1];
        input[0] = new KEYBOARD_INPUT();
        input[0].type = INPUT_KEYBOARD;
        input[0].vk = VK_BROWSER_BACK;

    uint result = SendInput(1, input, Marshal.SizeOf(input[0]));
}

您还需要使用SetForegroundWindow聚焦 Chrome 窗口

于 2008-09-30T09:25:09.900 回答