我的问题是:“这可以做得更好吗?” 如果是这样,如何?有任何想法吗?
我们需要从一个“不可见的”C# .NET 3.5 应用程序中启动一个捕获的 IE 会话,并在处理某个请求后退出 IE 会话和“父”应用程序。
过去一周左右我一直在处理这个问题......今天早上我终于找到了我认为是一个强大的解决方案;但我有点 C# 菜鸟(虽然我已经做了 10 年的专业程序员),所以我正在寻求第二或第三意见;以及任何其他选项、批评、建议或评论......特别是:SHDocVw 仍然是创建“俘虏但不嵌入”Internet Explorer 会话的首选方法吗?
正如我所看到的,棘手的一点是处理非托管InternetExplorerApplication
COM 对象,所以我将它包装在一个IDisposable
名为的类中InternetExplorer
我的基本做法是:
- Application.Run MyApp,它是一个ApplicationContext,并且是IQuitable。
- 我认为在我们等待 IE 请求时需要一个应用程序来保持程序打开?
- 我想也许(非守护程序)侦听器循环线程也可以工作?
- MyApp 的构造函数创建一个新的InternetExporer对象,并传递 (IQuitable)this
InternetExporer
的构造函数启动一个新的 IE 会话,并将其导航到一个 URL。- 当请求某个 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
}
}