Мой вопрос: "Можно ли это сделать лучше?" и если да, то как? Есть идеи?
Нам нужно запустить незаполненный сеанс IE из «невидимого» приложения C # .NET 3.5 и выйти из сеанса IE и «родительского» приложения после обработки определенного запроса.
Я обдумывал эту проблему в течение прошлой недели или около того ... и сегодня утром я наконец достиг того, что я считаю надежным решением; но я немного Noob (хотя я был профессиональным программистом в течение 10 лет), поэтому я ищу второе или третье мнение; и любые другие варианты, критические замечания, предложения или комментарии ... В частности: является ли SHDocVw по-прежнему предпочтительным методом создания «пленного, но не встроенного» сеанса Internet Explorer?
Как я вижу, сложность заключается в удалении неуправляемого InternetExplorerApplication
COM-объекта, поэтому я обернул его в IDisposable
класс с именем InternetExplorer
Мой основной подход:
- Application.Run MyApp, который является ApplicationContext и является IQuitable.
- Я думаю, что приложение необходимо для того, чтобы программа оставалась открытой, пока мы ожидаем запроса IE?
- Я полагаю, что (не-демон) поток цикла слушателя также может работать?
- Конструктор MyApp создает новый InternetExporer объект, передающий (IQuitable) этот
InternetExporer
запускает новый сеанс IE и перемещает его по URL-адресу.
- Когда запрашивается определенный 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
}
}