Sunday, 18 September 2011

Get Chrome active tab URL using Delphi

After developing my first Chrome extension to retrieve all URLs from Google chrome, I have been trying to reproduce the same behaviour using Delphi, but it was impossible. Chrome is still adding some new features and extending their extensions for developers. For example, others navigators such as Internet Explorer and Firefox they have a DDE extension to retrieve some of the properties but not available for Chrome.
The best way I found was using FindWindow and SendMessage windows functions to get the text from the tab and get tue URL. It's not a win solution but will help you to retrieve the URL of the active page without copy-paste action, just by switching to the next tab and retrieving data from the tool.

The basic code to achieve this is the following one:

function GetChromeActiveTabURL(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
  urls: TStrings;
  hWndMainWindow, hWndTab: HWND;
  Buffer : array[0..255] of Char;
  res : boolean;
begin
  res := true;
  urls := TStrings(Param);
  SendMessage(Wnd, WM_GETTEXT, Length(Buffer), integer(@Buffer[0]));
  hWndMainWindow := FindWindow('Chrome_WidgetWin_0', Buffer);
  application.ProcessMessages;
  if hWndMainWindow <> 0 then
  begin
    hWndTab := FindWindowEx(hWndMainWindow, 0, 'Chrome_AutocompleteEditView', nil);
    if hWndTab <> 0 then
    begin
      SendMessage(hWndTab, WM_GETTEXT, Length(Buffer), integer(@Buffer));
      urls.Add(Buffer);
      res := false;
    end;
  end;
  Result := res;
end;

procedure TUrlChrome.GetUrl(Sender: TObject);
var
  Urls: TStringList;
begin
  Urls := TStringList.Create;
  try
    EnumWindows(@GetChromeActiveTabURL, LParam(Urls));
    Memo1.Lines.AddStrings(Urls);
  finally
    FreeAndNil(Urls);
  end;
end;

To get the class name window, we can use Winspector to inspect chrome and get the names for the main window and for the tabs:

Chrome_WidgetWin_0:

Chrome_AutocompleteEditView:

And you can get the tool from here: ThundaxChromeURL.


I'm not proud of this solution, but at least it will work for current versions of Chrome. I also recommend to give a go to my chrome extension (It's not been published into Chrome market, it turns out that you have to pay a $5.00 fee), that is much better than the tool as it's able to get all urls.

Related links:

14 comments:

  1. You can try MSAA. Example: http://www.transl-gunsmoker.ru/2009/08/blog-post.html

    ReplyDelete
  2. Hi Torbins,

    Thanks for your comment, but I think that's not the same. I want to automatically get the URL from the active tab and in the example given, the user needs to move the mouse to the text.
    Anyway, the best option is to use my Chrome Extension ;)

    Jordi.

    ReplyDelete
  3. If you want a "win" solution of getting stuff from Chrome to Delphi (and your cool with making extensions) you should prolly look at WebSockets....its all a little beyond me but Im sure someone with your skills would find it trivial. With a quick look around I couldnt find anything working, but thats prolly because Chrome keeps changing the specs (mainly to do with the handshake), but they havent changed it for a while now so maybe its time to have a good look at it.

    Anywayz, great blog, lots of interesting stuff.

    ReplyDelete
  4. Hi PAEz,

    Thans for your comment! I really appreciate it, and I will have a go using WebSockets. As you actually commented Google is changing specs all the time and there is a request on their forum for this topic.

    Jordi.

    ReplyDelete
  5. Good Evening, I wonder if you're the same function for Safari.
    thank you

    ReplyDelete
    Replies
    1. Sorry but only works for Chrome. I have never delved into detail with Safari but I assume it should work in a similar fashion way.

      Delete
  6. As I googled yes, but all the classes I search returned nothing, also tried using the class delphi URLMON, so you do not know which service passes, passing only Safari would be the same with other browsers (Firefox, Internet Explorer) but also did not .

    ReplyDelete
  7. Great post. Helped me a little lot. Thank you, Jordi.

    ReplyDelete
  8. Unfortunately this approach doesn't work with newest version of the Google Chrome. Have you any ideas how to get the URL from the new 29 version of Chrome?

    ReplyDelete
    Replies
    1. This means that they might have changed the approach and maybe it uses the same DDE approach as other browsers are using??

      Delete
    2. Havent had Delphi installed in a long long time so cant make any sample code, but....

      The reason its prolly not working is because I think the class for the window may have changed to...
      Chrome_WidgetWin_1
      ...so you might want to start looking for any window that class starts with Chrome_WidgetWin_
      I just looked with.....
      http://www.nirsoft.net/utils/winexp.html
      ...and thats what it was telling me.

      Spewing you never bit at looking at websockets ;)
      I really want lazarus/delphi code for that...been ages since I looked tho, prolly time for another look.

      Delete
    3. Chrome doesn't support the DDE mechanism. Maybe there is any COM object which can be used to get this information?

      Delete
    4. Thanks for your comments guys. I guess the post needs revisiting to cater for different versions of Chrome as I did my testing with an old version of Chrome and never tested it again.

      Jordi

      Delete