views:

4621

answers:

4

I've been searching around, and I haven't found how I would do this from 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 Window from my C# application.

I did something similar with WinAmp using

[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

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.

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:

 [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:

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:

m_windowName and WM_COMMAND

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

+6  A: 

Start your research at 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 only to Winamp.

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

VVS
I'm looking through, and I don't see anything that will help me accomplish what I'm trying to do. I don't want to recompile Chrome or anything. I want to just beable to send Chrome a little message saying "go back" or whatever. I don't want to change Chrome at all. Do it all from C#
Joel
+5  A: 

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

"Chrome_VistaFrame" for the out window. The actual window with the webpage in is "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.

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

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

Chris S
So I've been playing with this for an hour or two.I want to send the keyboard shortcuts. Right now I'm trying to figure out how to send Chrome the message for the WM_KEYDOWN and WM_KEYUP for the VK_BROWSER_BACK key. But I can't figure out the int values for them.
Joel
+2  A: 
Joel
+3  A: 

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:

Koders.com search

&H values look like that's from VB(6). pinvoke and koders both return results for 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).

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.

[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.

This needs a KEYBOARD_INPUT type:

[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

Chris S