2012-04-13 32 views
3

如何以编程方式启动IE(iexplore.exe)并在当前运行的实例中导航(通过打开新选项卡或替换当前URL)而不是创建新实例。如何强制Internet Explorer打开它的当前运行实例而不是创建新的实例?

我已经搜索了一个命令行开关,并尝试使用InternetExplorer.Application,无济于事。

这里是什么,我需要(IE6-IE9将是很好的)一个

ShellExecute(Handle, 'open', 'iexplore.exe', 
    '"http://google.com" -single_instance', 
    nil, SW_RESTORE); 

下面是一些代码来证明我的尝试。代码(部分基于How to get IHTMLDocument2 from a HWND):

implementation 

uses ShellApi, ComObj, ActiveX, SHDocVw, MSHTML;   

function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): Boolean; 
type 
    TObjectFromLResult = function(LRESULT: lResult; const IID: TIID; 
    wParam: WPARAM; out pObject): HRESULT; stdcall; 
var 
    hInst: HMODULE; 
    lRes: Cardinal; 
    Msg: UINT; 
    pDoc: IHTMLDocument2; 
    ObjectFromLresult: TObjectFromLresult; 
begin 
    Result := False; 
    hInst := LoadLibrary('oleacc.dll'); 
    if hInst <> 0 then 
    try 
    @ObjectFromLresult := GetProcAddress(hInst, 'ObjectFromLresult'); 
    if @ObjectFromLresult <> nil then 
    begin 
     Msg := RegisterWindowMessage('WM_HTML_GETOBJECT'); 
     if SendMessageTimeOut(WHandle, Msg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes) <> 0 then 
     if ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc) = S_OK then 
     begin 
      (pDoc.parentWindow as IServiceprovider).QueryService(
      IWebbrowserApp, IWebbrowser2, IE); 
      Result := IE <> nil; 
     end; 
     end; 
    finally 
    FreeLibrary(hInst); 
    end; 
end; 

function GetActiveIEServerWindow(const Activate: Boolean=True): HWND; 
var 
    Wnd, WndChild: HWND; 
begin 
    Result := 0; 
    Wnd := FindWindow('IEFrame', nil); // top level IE 
    if Wnd <> 0 then 
    begin 
    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 
     Result := WndChild; 
     if Activate then 
     begin 
      if IsIconic(Wnd) then 
      ShowWindow(Wnd, SW_RESTORE) 
      else 
      SetForegroundWindow(Wnd); 
     end; 
     end; 
    end; 
    end; 
end; 

// Method 1 
procedure TForm1.Button1Click(Sender: TObject); 
const 
    navOpenInNewTab = $800; 
var 
    IEServerWnd: HWND; 
    IE: IWebBrowser2; 
begin 
    IEServerWnd := GetActiveIEServerWindow; 
    if (IEServerWnd <> 0) and GetIEFromHWnd(IEServerWnd, IE) then 
    begin 
    // *** this opens the Default browser, e.g Google Chrome 
    // *** if IE is the Default browser, an empty new window is opened. 
    OleVariant(IE).Navigate('http://www.yahoo.com', Longint(navOpenInNewTab)); 
    end 
    else 
    begin 
    ShellExecute(Handle, 'open', 'iexplore.exe', 
    '"http://google.com"', 
    nil, SW_RESTORE); 
    end; 
end; 

procedure InternetExplorerNavigate(URL: WideString); 
const 
    navOpenInNewTab = $800; 
var 
    IE: OleVariant; 
begin 
    try 
    // *** this always fails (security constraints?) 
    IE := GetActiveOleObject('InternetExplorer.Application'); 
    except 
    IE := CreateOleObject('InternetExplorer.Application'); 
    end; 
    IE.Visible := True; 
    IE.Navigate(URL, Longint(navOpenInNewTab)); 
end; 

// Method 2 
procedure TForm1.Button2Click(Sender: TObject); 
begin 
    InternetExplorerNavigate('http://google.com'); 
end; 
+0

这不应该归结为用户配置吗?如果我将它设置为在新窗口中打开,那么我期望新的窗口。如果我将它设置为在一个窗口中加载所有选项卡,我也会这么想。 – Deanna 2012-04-16 14:20:42

回答

4

您的方法'1'实际工作。这个问题至少在这里是'Shell DocObject View'窗口不是顶层窗口的直接子节点。在IE8中,'Internet Explorer_Server'窗口是'Shell DocObject View'的子项,它是'TabWindowClass'的子项,它是'Frame Tab'的子项。如果您可以确认'方法1中'FindWindowEx'返回0,这就是为什么它失败。下面的是修改为使用EnumChildWindows的代码:

function EnumChilds(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; 
const 
    Server = 'Internet Explorer_Server'; 
var 
    ClassName: array[0..24] of Char; 
begin 
    GetClassName(hwnd, ClassName, Length(ClassName)); 
    Result := ClassName <> Server; 
    if not Result then 
    PLongWord(lParam)^ := hwnd; 
end; 

function GetActiveIEServerWindow(const Activate: Boolean=True): HWND; 
var 
    Wnd, WndChild: HWND; 
begin 
    Result := 0; 
    Wnd := FindWindow('IEFrame', nil); // top level IE 
    if Wnd <> 0 then 
    begin 

// WndChild := FindWindowEx(Wnd, 0, 'Shell DocObject View', nil); 
// if WndChild <> 0 then 
// begin 
//  WndChild := FindWindowEx(WndChild, 0, 'Internet Explorer_Server', nil); 

    WndChild := 0; 
    EnumChildWindows(Wnd, @EnumChilds, LongWord(@WndChild)); 

    if WndChild <> 0 then 
    begin 
     Result := WndChild; 
     if Activate then 
     begin 
     if IsIconic(Wnd) then 
      ShowWindow(Wnd, SW_RESTORE) 
     else 
      SetForegroundWindow(Wnd); 
     end; 
    end; 
// end; 
    end; 
end; 

至于方法“2”,我已经看到声明IE不支持返回其活动对象的参考在网络上的几个链接,但我对此没有任何官方参考。

+0

嗨,谢谢你的回答。我正在测试IE6/XP。所以这里的子窗口可能会有所不同(这不是问题)。什么是您的默认浏览器BTW? – kobik 2012-04-14 15:07:42

+0

但ie6没有标签,800美元对ie6没有意义。我在回答中提到了使用ıe8。 – 2012-04-14 15:44:41

+0

我知道,我希望IE6会忽略这一点(我也试图通过0作为标志),并且由于我获得了活动的'IHTMLDocument2',我应该能够'导航'不? – kobik 2012-04-14 17:20:28

相关问题