Automating IE

Connect to a running instance of Internet Explorer

 

1. Using ObjectFromLResult.

You can use function ObjectFromLResult to obtain an interface to IHtmlDocument2 or IWebbrowser2 from a running instance of IE, if you have a "Internet Explorer_Server" HWND.

The following shows a Spyxx-picture of the structure of a running instance of IE. 

To reach Internet Explorer_Server we need to go from

IEFrame -> Shell DocObject View -> Internet Explorer_server.

In this example there is also another instance you can connect to:

IEFrame -> BaseBar -> RebarWindow32 -> OCHost -> Shell Embeddeding -> Shell DocObject View -> Internet Explorer_server.

It is because the Search Explorer is opened and contain a Webbrowser document.

The following sample will do the following:

If a instance of Internet Explorer is running, we will connct to it - using the ObjectFromLResult function - and direct the browser to IE & Delphi Homepage. 

Then we will open the Search Explorer Bar in the browser and replace the normal content with a different content - using the same function.

ObjectFromLResult is a MSAA function (Microsoft Active Accessibility) and is located in oleacc.dll. In Windows 2000 and Windows NT with Service Pack 6 MSAA is part of the operating system, but on older version you might need to install MSAA runtime components:

MSAA Runtime Components (RDK)

 

                
type
  TObjectFromLResult = function(LRESULT: lResult; const IID: TIID; WPARAM: wParam; out pObject): HRESULT; stdcall;


function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): HRESULT;
var
  hInst: HWND;
  lRes: Cardinal;
  MSG: Integer;
  pDoc: IHTMLDocument2;
  ObjectFromLresult: TObjectFromLresult;
begin
  hInst := LoadLibrary('Oleacc.dll');
  @ObjectFromLresult := GetProcAddress(hInst, 'ObjectFromLresult');
  if @ObjectFromLresult <> nil then begin
    try
      MSG := RegisterWindowMessage('WM_HTML_GETOBJECT');
      SendMessageTimeOut(WHandle, MSG, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes);
      Result := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc);
      if Result = S_OK then
        (pDoc.parentWindow as IServiceprovider).QueryService(IWebbrowserApp, IWebbrowser2, IE);
    finally
      FreeLibrary(hInst);
    end;
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  Wnd: HWND;
  WndChild: HWND;
  x: Olevariant;
  vaClsID, vaEnabled, vaDummy: Olevariant;
  BarIE, IE: iwebbrowser2;
begin
  Wnd := FindWindow('IEFrame', nil);
  if Wnd = 0 then //No running instance of Internet Explorer so stop!
  begin
    showmessage('No Running instance of Internet Explorer');
    exit;
  end;
// walk Shell DocObject View->Internet Explorer_Server
  WndChild := FindWindowEX(Wnd, 0, 'Shell DocObject View', nil);
  if WndChild <> 0 then begin
    WndChild := FindWindowEX(WndChild, 0, 'Internet Explorer_Server', nil);
    if WndChild <> 0 then
    begin
      GetIEFromHWnd(WndChild, IE); //Get Iwebbrowser2 from Handle
      //Navigate to IE & Delphi
      IE.Navigate('http://www.euromind.com/iedelphi', x, x, x, x);
      vaCLSID := '{30D02401-6A81-11D0-8274-00C04FD5AE38}';
      vaEnabled := True;
      vaDummy := 0;
// open Search Explorer Bar
      IE.ShowBrowserBar(vaCLSID, vaEnabled, vaDummy); 
//  find Internet Explorer_Server for Search Explorer Bar
      WndChild := FindWindowEX(Wnd, 0, 'Basebar', nil);
      if WndChild <> 0 then begin
        WndChild := FindWindowEX(WndChild, 0, 'RebarWindow32', nil);
        if WndChild <> 0 then begin
          WndChild := FindWindowEX(WndChild, 0, 'OCHost', nil);
          if WndChild <> 0 then begin
            WndChild := FindWindowEX(WndChild, 0, 'Shell Embedding', nil);
            if WndChild <> 0 then begin
              WndChild := FindWindowEX(WndChild, 0, 'Shell DocObject View', nil);
              if WndChild <> 0 then begin
                WndChild := FindWindowEX(WndChild, 0, 'Internet Explorer_Server', nil);
                if WndChild <> 0 then
                begin
                  GetIEFromHWnd(WndChild, BarIE); //Get Iwebbrowser2 from Handle
                 BarIE.Navigate('www.euromind.com/iedelphi/ie5tools/automate.htm', x, x, x, x); 
//Navigate Search Explorer Bar
                end;
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;
 
                

 

2. Using IShellWindows

Click Button1 to have the locationurls from all running instances of Internet Explorer - including open folders and Windows Explorer - shown in a listbox.

uses
 
shdocvw_tlb;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: Integer;
  Sw: IShellWindows;
begin
  sw := CoShellWindows.Create;
  for x := 0 to SW.Count - 1 do
    Listbox1.Items.Add((Sw.Item(x) as IWebbrowser2).LocationUrl);
end;


Sinking events from IShellWindows.

DShellWindowsEvent has two events OnWindowRegistered (called when a new instance of IE is created) and OnWindowRevoked (called whel an instance of IE is closed).

Drop a DShellWindowEvent-component on your form and connect it to your instance of IShellwindows:

var
 sw : Ishellwindows;

begin

  sw := CoShellWindows.Create;
  DshellwindowsEvents1.Connect(sw);
end;


The following code will keep track of running instances of Internet Explorer - add or remove them from a listbox based on information from OnWindowRegistered and OnWindowRevoked 

uses
shdocvw_tlb;


procedure TForm1.DShellWindowsEvents1WindowRegistered(Sender: TObject;lCookie: Integer);
begin
Listbox1.Items.Add('Instance with Cookie no: '+InttoStr(lCookie));
end;

procedure TForm1.DShellWindowsEvents1WindowRevoked(Sender:   TObject;lCookie: Integer);
begin
 Listbox1.Items.Delete(Listbox1.Items.IndexOf('Instance with Cookie no: '+InttoStr(lCookie)));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 sw : Ishellwindows;
begin
 FormStyle:=fsStayOnTop; 
 sw := CoShellWindows.Create;
 DshellwindowsEvents1.Connect(sw);
end;

 

Sending commands to a running instance of IE

You can obtain an IWebbrowser2-interface from each of the running instances listed in IShellwindows by simple typecasting if 

WB:=Shellwindows.Items(x) as IWebbrowser2; 


The following code will close all running instances of IE when Button1 is clicked:


procedure TForm1.Button1Click(Sender: TObject);
var
  x : Integer;
  sw: Ishellwindows;
  wb: IWebbrowser2;
begin
  sw := CoShellWindows.Create;
  for x := 0 to sw.count do
    begin
      WB := Sw.Item(x) as IWebbrowser2;
      if wb<>nil then WB.Quit;
   end;
end;

 

Sinking Events from a running instance of IE.

Drop a DWebbrowserEvents2-component on your form and connect it to an instance of IE by using

  DWebbrowserEvents21.Connect(IE);

var
 
ShellWin : shdocvw_tlb.IShellWindows;
  IE : IWebbrowser2;

begin
 
IE:=shellwin.Item(Shellwin.Count-1) as IWebbrowser2;
  DWebbrowserEvents21.Connect(IE);
end;


The following code opens a new instance of IE, lets it navigate and captures the statustext-change in a listbox:

uses
shdocvw_tlb;

procedure TForm1.Button1Click(Sender: TObject);
var
x: Olevariant;
sw: Ishellwindows;
wb: IWebbrowser2;
begin
  WB := CoInternetExplorer.Create;
  WB.Visible := True;
  DWebbrowserEvents21.Connect(WB);
  WB.Navigate('http://www.euromind.com/iedelphi', x, x, x, x);
end;

procedure TForm1.DWebBrowserEvents21StatusTextChange(Sender: TObject;const Text: WideString);
begin
  listbox1.items.add(text);
end;

procedure TForm1.DWebBrowserEvents21Quit(Sender: TObject);
begin
  DWebbrowserEvents21.DisConnect;
end;

 

The demo LogView demonstrates how to log events from all running instances of IE to a common log-listbox. The demo uses DWebbrowserEvents2 and ShellWindowEvents:

 


var
  ShellWin: IShellWindows; //NB!!
  Connection: Integer;

procedure InterfaceConnect(const Source: IUnknown; const IID: TIID;
  const Sink: IUnknown; var Connection: Longint);
var
  CPC: IConnectionPointContainer;
  CP: IConnectionPoint;
begin
  Connection := 0;
  if Succeeded(Source.QueryInterface(IConnectionPointContainer, CPC)) then
    if Succeeded(CPC.FindConnectionPoint(IID, CP)) then
      CP.Advise(Sink, Connection);
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  X: Integer;
begin
  ShellWin := CoShellWindows.Create;
  ShellWinEvents.Connect(ShellWin);
  for x := 0 to ShellWin.Count - 1 do
    InterfaceConnect(ShellWin.Item(x) as IWebbrowser2, DwebbrowserEvents2, WBevents, Connection);
end;

procedure TForm1.ShellWinEventsWindowRegistered(Sender: TObject;  lCookie: Integer);
begin
  InterfaceConnect(ShellWin.Item(ShellWin.Count - 1) as IWebbrowser2, DwebbrowserEvents2, WBevents, Connection);
end;

procedure TForm1.WBEventsBeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
begin
  listbox1.items.add(url);
end;


Links:

Q176792 - HOWTO- Connect to a Running Instance of Internet Explorer

Q249232 - HOWTO- Get IHTMLDocument2 from a HWND

 

Download Logview demo

Logview demo  for Delphi 4/5