8

How can I get the url from a running instance of Chrome using Delphi?

I'm trying to do a Delphi application that gets the url of the active tab of the browser (IE, Mozilla, etc.). I'm using this code that works for IE:

 procedure TForm1.GetCurrentURL (var URL, Title : string);
 var
   DDEClient : TDDEClientConv;
   s : string;
 begin
   s := '';
   try
     DDEClient := TDDEClientConv.Create(self);
     with DDEClient do
     begin
       if SetLink('IExplore','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle')
       else
       if SetLink('Netscape','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle')
       else
       if SetLink('Mosaic','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle')
       else
       if SetLink('Netscp6','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle')
       else
       if SetLink('Mozilla','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle')
       else
       if SetLink('Firefox','WWW_GetWindowInfo') then
         s := RequestData('0xFFFFFFFF,sURL,sTitle');
     end;
     if s <> '' then
     begin
       delete(s,1,1);
       URL := copy(s,1,pos('","',s)-1);
       delete(s,1,pos('","',s)+2);
       Title := copy(s,1,pos('"',s) - 1);
     end;
     exit;
   except
     MessageDlg('URL attempt failed!',mtError,[mbOK],0);
   end;
 end;

But this code doesn't work with Chrome.

Thanks.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
razonasistemas
  • 371
  • 1
  • 4
  • 11
  • Where did you get that code? It has a memory leak — doesn't free the DDE client. – Rob Kennedy Mar 07 '11 at 16:50
  • 3
    FYI, Chrome's lack of DDE support is tracked by [issue 70184](http://code.google.com/p/chromium/issues/detail?id=70184). – Rob Kennedy Mar 07 '11 at 16:52
  • 1
    This surely looks like the `reuse by copy-paste anti pattern` to me. – Jeroen Wiert Pluimers Mar 07 '11 at 18:06
  • @Rob Kennedy: `Owner` is `self`? – Ian Boyd Mar 07 '11 at 19:05
  • 1
    @Ian: Well, but `Self` is going to be around for quite some time... – Andreas Rejbrand Mar 07 '11 at 19:30
  • 1
    Ah, I see, @Ian. Not exactly a leak in the usual sense, but not appreciably different from a real leak, either. If it were really a leak, it would be the OS that cleaned up the memory at the end of the program. In this case, it's the main form that cleans up the memory a moment before the end of the program. But either way, the object far outlives its usefulness because it will never be accessed outside this function. (It *could* be accessed, but we all know it won't be.) – Rob Kennedy Mar 07 '11 at 20:44

3 Answers3

3

Here is how I have done it before for retrieving the URL from the active tab. You could probably extend this to include all of Chrome's tabs.

One other note, as you can see this grabs the first handle to chrome.exe that it finds. To have this accommodate multiple instances of Chrome running, you would need to adjust this to get a handle to each Chrome instance.

I put this together pretty quick, so don't consider this "production" quality. Just create a new vcl application and drop a TMemo and a TButton on the form and assign the Button1Click to TButton's OnClick event.

unit main;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Classes,
  Controls,
  Forms,
  StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function GetActivePageUrlFromChrome(Handle: HWnd; Param: LParam): Bool; stdcall;

var
  Form1             : TForm1;

implementation

{$R *.dfm}

function GetActivePageUrlFromChrome(Handle: HWnd; Param: LParam): Bool; stdcall;
var
  List: TStrings;
  hWndChrome, hWndChromeChild: HWND;
  Buffer            : array[0..255] of Char;
begin
  List := TStrings(Param);
  //get the window caption
  SendMessage(Handle, WM_GETTEXT, Length(Buffer), integer(@Buffer[0]));
  //look for the chrome window with "Buffer" caption
  hWndChrome := FindWindow('Chrome_WidgetWin_0', Buffer);
  if hWndChrome <> 0 then
  begin
    hWndChromeChild := FindWindowEx(hWndChrome, 0, 'Chrome_AutocompleteEditView', nil);
    if hWndChromeChild <> 0 then
    begin
      SendMessage(hWndChromeChild, WM_GETTEXT, Length(Buffer), integer(@Buffer));
      List.Add(Buffer);
    end;
  end;
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  slChromeUrl      : TStringList;
begin
  slChromeUrl := TStringList.Create;
  try
    EnumWindows(GetActivePageUrlFromChrome, LParam(slChromeUrl));
    Memo1.Lines.AddStrings(slChromeUrl);
  finally
    FreeAndNil(slChromeUrl);
  end;
end;

end.
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Mick
  • 13,248
  • 9
  • 69
  • 119
  • Needless to say, this might not work in future versions of Google Chrome. Still, +1. – Andreas Rejbrand Mar 07 '11 at 20:17
  • 1
    Your `GetProcessHandle` function is peculiar. Despite its name, it doesn't actually get a process handle. It gets a toolhelp snapshot handle. It leaves that handle open for the caller to close even though the caller never uses the handle. It also returns a process ID, but the caller never uses that, either. I suspect you were keeping the snapshot handle open under the mistaken impression that doing so would prevent the Chrome process from being destroyed while `Button1Click` attempted to interact with it, but that's not how snapshot handles work. – Rob Kennedy Mar 07 '11 at 20:55
  • @Rob - Actually, the GetProcessHandle function is something I pulled off the web for this example. The code to grab the Chrome URL came from a project of mine that obtains handles to processes in a different manner. Thats why I say this is not "production" quality code, but just meant to serve as an example for pulling the URL from Chrome's active tab. – Mick Mar 07 '11 at 21:34
  • @Mick: I hope you asked the author of `GetProcessHandle` for permission to copy the code and display it here without any attribution or source at all... – Andreas Rejbrand Mar 07 '11 at 22:52
  • @Andreas Yeah, time for me to stop. I must say though, I don't really approve of posting such low quality code. It's not hard to do it right. – David Heffernan Mar 07 '11 at 22:55
  • @Andreas - no I didn't even check. I'll remove it from the code sample. – Mick Mar 07 '11 at 23:03
  • @David - feel free to down vote or vote for deletion. You won't hurt my feelings. – Mick Mar 07 '11 at 23:04
  • @Mick I think the code is valuable and would be better if it was tidied up along the lines that Rob outlined. – David Heffernan Mar 07 '11 at 23:05
  • You said this is the code you use, but it's clearly not, if GetProcessHandle is something you just found today for this example. Since it doesn't do what it says it does, and its effects aren't used in the example anyway, I've removed it entirely. Let's keep things simple. I've also made the callback function match the documented signature. If you don't use the `@` operator when you call EnumWindows, the compiler can help find declaration mistakes for you. – Rob Kennedy Mar 07 '11 at 23:46
  • Thanks Rob. As for the function in question, it did come from the web, I just modified it to return the handle instead of the pid (which it originally only did). The code came from this site, http://bit.ly/dURgIW, which was one of the first hits that came up in Google. Either way, thanks for the modifications to the snippet, it should help the person that asked the question. – Mick Mar 08 '11 at 01:15
  • Chrome may soon get rid of its URL bar. Any thoughts on how to solve this problem then? DDE is, unfortunately, still not supported. – Marten May 26 '11 at 16:47
1

Error:

try
    EnumWindows(GetActivePageUrlFromChrome, LParam(slChromeUrl));
    Memo1.Lines.AddStrings(slChromeUrl);

Works:

try
    EnumWindows(@GetActivePageUrlFromChrome, LParam(slChromeUrl));
    Memo1.Lines.AddStrings(slChromeUrl);
sth
  • 222,467
  • 53
  • 283
  • 367
Ivan
  • 11
  • 1
0

Apparently there's an issue open to request DDE support by chrome/chromium, keep a look-out there if a future version would provide it:

http://code.google.com/p/chromium/issues/detail?id=70184

Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67