0

我的问题是:“这可以做得更好吗?” 如果是这样,如何?有任何想法吗?

我们需要从一个“不可见的”C# .NET 3.5 应用程序中启动一个捕获的 IE 会话,并在处理某个请求后退出 IE 会话和“父”应用程序。

过去一周左右我一直在处理这个问题......今天早上我终于找到了我认为是一个强大的解决方案;但我有点 C# 菜鸟(虽然我已经做了 10 年的专业程序员),所以我正在寻求第二或第三意见;以及任何其他选项、​​批评、建议或评论......特别是:SHDocVw 仍然是创建“俘虏但不嵌入”Internet Explorer 会话的首选方法吗?

正如我所看到的,棘手的一点是处理非托管InternetExplorerApplicationCOM 对象,所以我将它包装在一个IDisposable名为的类中InternetExplorer

我的基本做法是:

  1. Application.Run MyApp,它是一个ApplicationContext,并且是IQuitable。
    • 我认为在我们等待 IE 请求时需要一个应用程序来保持程序打开?
    • 我想也许(非守护程序)侦听器循环线程也可以工作?
  2. MyApp 的构造函数创建一个新的InternetExporer对象,并传递 (IQuitable)this
  3. InternetExporer的构造函数启动一个新的 IE 会话,并将其导航到一个 URL。
  4. 当请求某个 URL 时,InternetExporer回调“父母”退出方法。

背景:

真实的故事是:我正在为MapInfo(一个GIS客户端)编写一个插件。该插件劫持从 IE 到服务器的“开始提取”HTTP 请求,稍微修改 URL 并在其位置发送 HTTPRequest。我们将 respose XML 解析为MIF 文件[PDF 196K],然后我们将其导入并在 MapInfo 中打开。然后我们退出 IE 会话,并关闭“插件”应用程序。

SSCCE

using System;
using System.Windows.Forms;

// IE COM interface
// reference ~ C:\Windows\System32\SHDocVw.dll 
using SHDocVw; 

namespace QuitAppFromCaptiveIE
{
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyApp());
        }
    }

    interface IQuitable {
        void Quit();
    }

    public class MyApp : ApplicationContext, IQuitable {
        private InternetExplorer ie = null; 

        public MyApp() {
            // create a new Internet Explorer COM component - starts IE application.
            this.ie = new InternetExplorer(this);
            this.ie.Open("www.microsoft.com");
        }

        #region IQuitable Members

        public void Quit() {
            if (ie != null) {
                ie.Dispose();
                ie = null;
            }
            Application.Exit();
        }

        #endregion
    }

    class InternetExplorer : IDisposable, IQuitable
    {
        // allows us to end the parent application when IE is closed.
        private IQuitable parent;
        private bool _parentIsQuited = false;
        private bool _ieIsQuited = false;

        private SHDocVw.InternetExplorer ie; // Old (VB4 era) IE COM component

        public InternetExplorer(IQuitable parent) {
            // lock-onto the parent app to quit it when IE is closed.
            this.parent = parent;
            // create a new Internet Explorer COM component - starts IE application.
            this.ie = new SHDocVw.InternetExplorerClass();
            // hook-up our navigate-event interceptor
            ie.BeforeNavigate2 += new DWebBrowserEvents2_BeforeNavigate2EventHandler(ie_BeforeNavigate2);
        }

        public void Open(string url) {
            object o = null;
            // make the captive IE session navigate to the given URL.
            ie.Navigate(url, ref o, ref o, ref o, ref o);
            // now make the ie window visible
            ie.Visible = true;
        }

        // this callback event handler is invoked prior to the captive IE 
        // session navigating (opening) a URL. Navigate-TWO handles both
        // external (normal) and internal (AJAX) requests. 
        // For example: You could create a history-log file of every page
        // visited by each captive session.
        // Being fired BEFORE the actual navigation allows you to hijack
        // (ie intercept) requests to certain URLs; in this case a request
        // to http://support.microsoft.com/ terminates the Browser session
        // and this program!
        void ie_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) {
            if (URL.Equals("http://support.microsoft.com/")) {
                this.Quit();
            }
        }

        #region IDisposable Members

        public void Dispose() {
            quitIE();
        }

        #endregion

        private void quitIE() {
            // close my unmanaged COM object
            if (ie != null && !_ieIsQuited) {
                _ieIsQuited = true;
                ie.Quit();
                ie = null;
            }
        }

        #region IQuitable Members

        public void Quit() {
            // close my unmanaged COM object
            quitIE();
            // quit the parent app as well.
            if (parent != null && !_parentIsQuited) {
                _parentIsQuited = true;
                parent.Quit();
                parent = null;
            }
        }

        #endregion
    }

}
4

2 回答 2

1

我有理由确定 System.Windows.Forms.WebBrowser 实际上在内部使用 IE Trident 浏览器控件。除非您使用 C# 1.x,否则没有必要进行 COM 互操作。

于 2009-06-06T16:47:23.440 回答
1

总而言之(无论如何,我仍然不是专家)SHDocVw.dll 仍然是启动“俘虏”Internet Explorer 会话的首选方法(相对于嵌入应用程序中的浏览器)。

我之前发布的代码不是最好的解决方案,恕我直言。在最终版本中:

  • IQiable是历史
  • MyAppInternetExplorer类都实现了 IDisposable
  • 如果 *_isDisposed* 为真,则这两个Dispose方法都会返回。

为简洁起见,以下代码包含一些伪代码:

  private volatile bool _isDisposed = false;

  /**
  * _isDisposed stops the two "partners" in the conversation (us and 
  * Internet Explorer) from going into "infinite recursion", by calling 
  * each others Dispose methods within there Dispose methods.
  *
  * NOTE: I **think** that making _isDisposed volatile deals adequately
  * with the inherent race condition, but I'm NOT certain! Comments
  * welcome on this one.
  */
  public void Dispose() {
    if (!_isDisposed) {
      _isDisposed = true;
      try {
        try { release my unmanaged resources } catch { log }
        try {
          IE calls MyApp.Dispose() here // and FALLOUT on failure
          MyApp calls IE.Dispose(); here
        } catch {
          log
        }
      } finally {
        base.Dispose(); // ALLWAYS dispose base, no matter what!
      }
    }
  }

要从 IE 类中退出应用程序,您只需调用它的本地 Dispose 方法,该方法调用 MyApps Dispose,该方法再次调用 IE 的 Dispose,但 isDisposed 为 true,因此它只是返回。然后我们调用 Application.ExitThread() 并退出 MyApp 的 Dispose... 然后我们退出 IE 的 Dispose 方法,事件系统停止;并且应用程序很好地终止。最后!

编辑注意事项:我刚刚将这种方法与 Robo 框架进程一起使用,它是 MyApp 的“俘虏进程”......它是远程控制的。令人费解,但它有效......所以我在这里时用我最新的学习更新了我的“自我回答”。

于 2011-04-30T13:15:51.003 回答