C# - 从 C# 应用程序向 Google Chrome 发送消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/147929/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:35:21  来源:igfitidea点击:

C# - Sending messages to Google Chrome from C# application

提问by Joel

I've been searching around, and I haven't found how I would do this from C#.

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

I was wanting to make it so I could tell Google Chrome to go Forward, Back, Open New Tab, Close Tab, Open New Window, and Close Windowfrom my C# application.

我想这样做,以便我可以告诉 Google Chrome从我的 C# 应用程序前进后退打开新标签关闭标签打开新窗口关闭窗口

I did something similar with WinAmp using

我使用 WinAmp 做了类似的事情

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

and a a few others. But I don't know what message to send or how to find what window to pass it to, or anything.

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

So could someone show me how I would send those 6 commands to Chrome from C#? thanks

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

EDIT: Ok, I'm getting voted down, so maybe I wasn't clear enough, or people are assuming I didn't try to figure this out on my own.

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

First off, I'm not very good with the whole DllImport stuff. I'm still learning how it all works.

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

I found how to do the same idea in winamp a few years ago, and I was looking at my code. I made it so I could skip a song, go back, play, pause, and stop winamp from my C# code. I started by importing:

几年前我发现如何在 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);

Then the code I found to use this used these constants for the messages I send.

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

    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;

I would get the hwnd(the program to send the message to) by:

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

IntPtr hwnd = FindWindow(m_windowName, null);

then I would send a message to that program:

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

SendMessageA(hwnd, WM_COMMAND, WA_STOP, WA_NOTHING);

I assume that I would do something very similar to this for Google Chrome. but I don't know what some of those values should be, and I googled around trying to find the answer, but I couldn't, which is why I asked here. So my question is how do I get the values for:

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

m_windowNameand WM_COMMAND

m_windowNameWM_COMMAND

and then, the values for the different commands, forward, back, new tab, close tab, new window, close window?

然后,不同命令的值,forwardbacknew tabclose tabnew windowclose window

采纳答案by VVS

Start your research at http://dev.chromium.org/developers

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



EDIT: Sending a message to a window is only half of the work. The window has to respond to that message and act accordingly. If that window doesn't know about a message or doesn't care at all you have no chance to control it by sending window messages.

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

You're looking at an implementation detail on how you remote controlled Winamp. Sending messages is just one way to do it and it's the way the Winamp developers chose. Those messages you're using are user defined messages that have a specific meaning onlyto Winamp.

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

What you have to do in the first step is to find out ifChromium supports some kind of remote controlling and what those mechanisms are.

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

回答by Chris S

You can get the window name easily using Visual Studio's Spy++ and pressing CTRL+F, then finding chrome. I tried it and got

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

"Chrome_VistaFrame" for the out window. The actual window with the webpage in is "Chrome_RenderWidgetHostHWND".

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

As far as WM_COMMAND goes - you'll need to experiment. You'll obviously want to send button clicks (WM_MOUSEDOWN of the top off my head). As the back,forward buttons aren't their own windows, you'll need to figure out how to do this with simulating a mouse click at a certain x,y position so chrome knows what you're doing. Or you could send the keyboard shortcut equivalent for back/forward and so on.

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

An example I wrote a while ago does this with trillian and winamp: sending messages to windows via c# and winapi

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

There's also tools out there to macro out this kind of thing already, using a scripting language - autoit is one I've used: autoit.com

还有一些工具可以使用脚本语言来宏化这种东西 - autoit 是我使用过的一种:autoit.com

回答by Joel

Ok, here's what I've got so far... I kinda know what I need to do, but it's just a matter of doing it now...

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

Here's the window from Spy++, I locked onto the Chrome_RenderWidgetHostHWNDand clicked the Back button on my keyboard. Here's what I got: alt text

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

So here's my assumptions, and I've been playing with this forever now, I just can't figure out the values.

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

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

Now, I just don't know what I should make the WM_KEYDOWN/UP values or the VK_BROWSER_BACK/FORWARD values... I tried this:

现在,我只是不知道我应该使 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;

The latter two values I got from the image I just showed, the ScanCodes for those two keys. I don't know if I did it right though. The former two values I got after searching google for the WM_KEYDOWN value, and someone used &H100 and &H101 for the two values. I've tried several other random ideas I've seen floating around. I just can't figure this out.

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

Oh, and here's the SendMessage method

哦,这里是 SendMessage 方法

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, uint lParam);

回答by Chris S

This is a great site for interop constants:

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

pinvoke

电话

Another way of finding the values is to search koders.com, using C# as the language, for WM_KEYDOWN or the constant you're after:

查找值的另一种方法是使用 C# 作为语言在 koders.com 中搜索 WM_KEYDOWN 或您想要的常量:

Koders.com search

Koders.com 搜索

&H values look like that's from VB(6). pinvoke and koders both return results for VK_BROWSER_FORWARD,

&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;

(It's funny how many wrong defintions of VK constants are floating about, considering VK_* are 1 byte 0-255 values, and people have made them uints).

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

Looks slightly different from your consts. I think the function you're after is SendInput (but I haven't tried it) as it's a virtual key.

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

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

Explanation about the parameters:

参数说明:

Parameters

参数

  • nInputs- Number of structures in the pInputs array.
  • pInputs - Pointer to an array of INPUT structures. Each structure represents an event to be inserted into the keyboard or mouse input stream.
  • cbSize - Specifies the size, in bytes, of an INPUT structure. If cbSize is not the size of an INPUT structure, the function fails.
  • nInputs- pInputs 数组中的结构数。
  • pInputs - 指向 INPUT 结构数组的指针。每个结构代表一个要插入键盘或鼠标输入流的事件。
  • cbSize - 指定 INPUT 结构的大小(以字节为单位)。如果 cbSize 不是 INPUT 结构的大小,则函数失败。

This needs a KEYBOARD_INPUT type:

这需要一个 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; 
}

And finally a sample, which I haven't tested if it works:

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

/*
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]));
}

Also you'll need to focus the Chrome window using SetForegroundWindow

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