使用Shdocvw访问Internet Explorer会导致UnauthorizedAccessException

时间:2014-04-17 22:33:48

标签: c# internet-explorer

我正在开发一个具有'finder'工具的应用程序的一部分,该工具允许用户将finder拖放到应用程序或Internet Explorer Web浏览器上,以便我们的程序可以找到它并执行它需要的操作去做。这部分应用程序在过去几年没有进行任何积极的开发(上次我认为IE 7是最新的浏览器),但它适用于IE 9及更低版本。从IE 10开始我们遇到问题,我特意使用的是IE 11。

以下代码查找不同的Internet Explorer窗口(包括选项卡)和文件资源管理器窗口。我们制作了一个快速的VB脚本以进行额外的测试 -

dim objShell
dim objShellWindows

set objShell = CreateObject("shell.application")
set objShellWindows = objShell.Windows

if (not objShellWindows is nothing) then
WScript.Echo objShellWindows.Count

for each win in objShellWindows
wscript.Echo TypeName(win)
WScript.Echo win.LocationUrl
WScript.Echo win.LocationName
WScript.Echo win.HWND
next

end if

set objShellWindows = nothing
set objShell = nothing

上面的代码会毫无错误地执行,它会给出我们打开的所有标签的URL和标题栏名称。

以下是我们的C#代码。它试图获取主IE窗口(而不是选项卡)。 this.Handle是查找器工具在用户放下它时获取的主IE窗口的句柄。我们试图遍历打开的窗口并找到用户选择的Internet Explorer窗口。此特定代码段与我们的原始实现稍有不同,但最终结果是相同的。只要它点击test = window.Item(i),它就会抛出UnauthorizedAccessException

 ShellWindows windows = null;
 IWebBrowser2 shellWindow = null;
 IHTMLDocument2 actualDoc = null;

 Type shellApplicationType = Type.GetTypeFromProgID("Shell.Application");
 Shell32.Shell shellInterface = (Shell32.Shell)Activator.CreateInstance(shellApplicationType);
 windows = (ShellWindows)shellInterface.Windows();
 bool found = false;
 for (int i = 0; i < windows.Count; i++)
 {
     try
     {            
         object test;
         try
         {
             test = windows.Item(i); //Exception here
             shellWindow = (IWebBrowser2)test;
         }
         catch
         {
         }
         if (shellWindow != null && (IntPtr)shellWindow.HWND == this.Handle)
         {
            //the rest of the code gets the correct tab from the main IE window

这是我们第一次重新访问该部分程序时未经编辑的原始代码。

ShellWindows windows = null;
IWebBrowser2 shellWindow =null;
IHTMLDocument2 actualDoc = null;

windows = new SHDocVw.ShellWindowsClass();
bool found = false;
for (int i = 0; i < windows.Count; i++)
{
     try{
         shellWindow = windows.Item(i) as SHDocVw.IWebBrowser2; //Exception here
         if (shellWindow != null && (IntPtr)shellWindow.HWND == this.Handle)
         {

我还要注意,我已经尝试了遵循此语法的for循环,而不是foreach循环

foreach(IWebBrowser2 browser in windows)

foreach(InternetExplorer browser in windows)

在这些情况下,循环会跳过IE窗口。

我查看了IE的安全设置。我已禁用增强保护模式并允许跨域。似乎没有关于这个问题的大量信息,我们尝试的每一种方法似乎总是以UnauthorizedAccessException结束。

编辑:为了回应Hans的回答,我没有在这台机器上运行任何反恶意软件。它是一个具有Windows 7的虚拟机,具有最新的SP和更新(没有微软安全要领)。我尝试在具有类似设置的32位机器上运行应用程序,但也失败了。在IE 11上测试之后,我卸载了IE 11,重新启动,尝试了IE 10(它失败了,同样的错误),卸载了IE 10,重新启动,尝试了IE 9,并且它在没有对系统进行任何其他更改的情况下工作。

以下是汉斯要求的SSCCE。此代码实际上适用于我的目标计算机。我将在第二天或第二天回到这篇文章,同时处理需要我注意的其他任务。

我将其构建为32位控制台应用程序,并在64位计算机上运行。

using System;
using SHDocVw;
using mshtml;

namespace GetBrowserSSCCE
{
    class Program
    {
        static void Main(string[] args)
        {
            ShellWindows windows = null;
            IWebBrowser2 shellWindow = null;

            windows = new SHDocVw.ShellWindowsClass();
            for (int i = 0; i < windows.Count; i++)
            {
                try
                    {
                    shellWindow = windows.Item(i) as SHDocVw.IWebBrowser2;
                    Console.WriteLine(string.Format("Window Found. HWND: {0}\nName: {1}", shellWindow.HWND, shellWindow.Name));
                }
                catch (UnauthorizedAccessException ex)
                {
                    Console.WriteLine("UnauthorizedAccessException caught. Exception Text: " +ex.Message);
                }

            }
            Console.ReadLine();
        }
    }
}

1 个答案:

答案 0 :(得分:4)

这在您的C#程序中失败,但是当您从VBScript解释器强烈将其运行到环境问题时,它就失败了。两者都使用完全相同的shell接口。之前已经在interwebs上报告了特定异常(基础错误代码为0x8007005)但从未诊断过。

当您遇到环境问题(尤其是与访问权限相关的类型)时,您应该首先关注的是计算机上安装的反恶意软件。禁用它然后重试。

您应该关注的第二个问题是与ShellWindows相关的怪癖,它不仅枚举Internet Explorer窗口,还会枚举Windows资源管理器窗口。你一直在寻找足够的IE访问权限,但这还不够,如果你碰巧打开了一个资源管理器窗口并且explorer.exe进程存在访问问题,这段代码也会失败。请注意,您的Activator.CreateInstance()方法调用不等同于VBScript代码,Activator.GetObject()是。因此,如果这是潜在问题,那么您的更改实际上会使问题变得更糟。

值得检查的第三个细节是过程的重要性。默认情况下,VBScript代码将在引导64位版本Windows的计算机上的64位脚本解释器中运行。但是C#项目的默认设置是以32位模式运行。右键单击EXE项目,“属性”,“构建”选项卡,然后使用“平台目标”设置进行修补,如果看到,则选中“首选32位”复选框。这是对错误代码的解释,但它可能会影响反恶意软件侵入的有效性。