Закрыть приложение из незапланированной сессии IE - PullRequest
0 голосов
/ 06 июня 2009

Мой вопрос: "Можно ли это сделать лучше?" и если да, то как? Есть идеи?

Нам нужно запустить незаполненный сеанс IE из «невидимого» приложения C # .NET 3.5 и выйти из сеанса IE и «родительского» приложения после обработки определенного запроса.

Я обдумывал эту проблему в течение прошлой недели или около того ... и сегодня утром я наконец достиг того, что я считаю надежным решением; но я немного Noob (хотя я был профессиональным программистом в течение 10 лет), поэтому я ищу второе или третье мнение; и любые другие варианты, критические замечания, предложения или комментарии ... В частности: является ли SHDocVw по-прежнему предпочтительным методом создания «пленного, но не встроенного» сеанса Internet Explorer?

Как я вижу, сложность заключается в удалении неуправляемого InternetExplorerApplication COM-объекта, поэтому я обернул его в IDisposable класс с именем InternetExplorer

Мой основной подход:

  1. Application.Run MyApp, который является ApplicationContext и является IQuitable.
    • Я думаю, что приложение необходимо для того, чтобы программа оставалась открытой, пока мы ожидаем запроса IE?
    • Я полагаю, что (не-демон) поток цикла слушателя также может работать?
  2. Конструктор MyApp создает новый InternetExporer объект, передающий (IQuitable) этот
  3. InternetExporer запускает новый сеанс IE и перемещает его по URL-адресу.
  4. Когда запрашивается определенный URL-адрес InternetExporer вызывает метод «родительского» выхода.

Справочная информация:

Реальная история такова: я пишу плагин для MapInfo (A GIS Client). Плагин перехватывает HTTP-запрос «Start Extraction» от IE к серверу, слегка изменяет 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
    }

}

Ответы [ 2 ]

1 голос
/ 30 апреля 2011

Похоже, что, несмотря ни на что (я все еще НЕ эксперт), SHDocVw.dll по-прежнему является предпочтительным методом для запуска "пленного" сеанса Internet Explorer (в соответствии с встроить браузер в ваше приложение).

Код, который я разместил ранее, не лучшее решение, ИМХО. В окончательной версии:

  • IQuitable - это история
  • Оба MyApp и InternetExplorer классы реализуют IDisposable
  • Оба Методы Dispose просто возвращают, если * _isDisposed * равен true.

Для краткости в следующем коде есть псевдокод:

  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 () и выпадают из Dispose MyApp ... и затем выпадают из метода Dispose IE, и система событий останавливается; и приложение красиво завершается. Наконец-то!

ПРИМЕЧАНИЕ ПО РЕДАКТИРОВАНИЮ: Я только что повторно использовал этот подход с процессом фреймворка Robo, который является «невольным процессом» MyApp ... вещь, которой он управляет удаленно. Свернутый, но это работает ... Так что я обновляю свой "ответ на себя" своими последними знаниями, пока я был здесь.

1 голос
/ 06 июня 2009

Я вполне уверен, что System.Windows.Forms.WebBrowser фактически использует браузерный элемент управления IE Trident для внутреннего использования. Взаимодействие с COM не требуется, если вы не используете C # 1.x.

...