如何在IE兼容模式下调试注入的javascript代码?

How to debug injected javascript code in IE compatibility mode?

我需要向 IE 注入一些 Javascript 脚本,然后调用一些方法。

我尝试了以下简单的 C# 代码(Javascript 代码是从已知的 HTML 元素构建 xpath)。

string xpath = @"
(function(win) {
    ""use strict"";
    var doc = win.document;

    if (doc._xpath_installed) return;
    doc._xpath_installed = true;

    doc.createXPath = function (node, optimized) {
        if (node.nodeType === Node.DOCUMENT_NODE) {
            return '/';
        }

        var steps = [];
        var contextNode = node;
        while (contextNode) {
            var step = _xPathValue(contextNode, optimized);
            if (!step) {
                break;
            }  // Error - bail out early.
            steps.push(step);
            if (step.optimized) {
                break;
            }
            contextNode = contextNode.parentNode;
        }

        steps.reverse();

        var stepvalues = [];
        steps.forEach(function (step) {
            stepvalues.push(_steptostring(step));
        });
        return (steps.length && steps[0].optimized ? '' : '/') + stepvalues.join('/');
    };

    var _xPathValue = function (node, optimized) {
        var ownValue;
        var ownIndex = _xPathIndex(node);
        if (ownIndex === -1) {
            return null;
        }  // Error.

        switch (node.nodeType) {
            case Node.ELEMENT_NODE:
                if (optimized && node.getAttribute('id')) {
                    return _stepnew('//*[@id=""' + node.getAttribute('id') + '""]', true);
                }
                ownValue = node.localName;
                break;
            case Node.ATTRIBUTE_NODE:
                ownValue = '@' + node.nodeName;
                break;
            case Node.TEXT_NODE:
            case Node.CDATA_SECTION_NODE:
                ownValue = 'text()';
                break;
            case Node.PROCESSING_INSTRUCTION_NODE:
                ownValue = 'processing-instruction()';
                break;
            case Node.COMMENT_NODE:
                ownValue = 'comment()';
                break;
            case Node.DOCUMENT_NODE:
                ownValue = '';
                break;
            default:
                ownValue = '';
                break;
        }

        if (ownIndex > 0) {
            ownValue += '[' + ownIndex + ']';
        }

        return _stepnew(ownValue, node.nodeType === Node.DOCUMENT_NODE);
    };

    var _xPathIndex = function (node) {
        // Returns -1 in case of error, 0 if no siblings matching the same expression,
        // <XPath index among the same expression-matching sibling nodes> otherwise.
        function areNodesSimilar(left, right) {
            if (left === right) {
                return true;
            }

            if (left.nodeType === Node.ELEMENT_NODE && right.nodeType === Node.ELEMENT_NODE) {
                return left.localName === right.localName;
            }

            if (left.nodeType === right.nodeType) {
                return true;
            }

            // XPath treats CDATA as text nodes.
            var leftType = left.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left.nodeType;
            var rightType = right.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right.nodeType;
            return leftType === rightType;
        }

        var siblings = node.parentNode ? node.parentNode.children : null;
        if (!siblings) {
            return 0;
        }  // Root node - no siblings.
        var hasSameNamedElements;
        for (var i = 0; i < siblings.length; ++i) {
            if (areNodesSimilar(node, siblings[i]) && siblings[i] !== node) {
                hasSameNamedElements = true;
                break;
            }
        }
        if (!hasSameNamedElements) {
            return 0;
        }
        var ownIndex = 1;  // XPath indices start with 1.
        for (var i = 0; i < siblings.length; ++i) {
            if (areNodesSimilar(node, siblings[i])) {
                if (siblings[i] === node) {
                    return ownIndex;
                }
                ++ownIndex;
            }
        }
        return -1; 
    };


    var _stepnew = function(value, optimized) {
        return {
            value: value,
            optimized: optimized || false
        }
    };

    var _steptostring = function(step) {
        return step[""value""];
    };
})(window);
";

然后我尝试注入 xpath 字符串并调用一个方法,

// doc is the html document (type: mshtml.IHTMLDocument2)
// element is the html element (type: mshtml.IHTMLElement)

doc.parentWindow.execScript(xpath, "JScript");
    
object[] args = new object[2];
args[0] = element;
args[1] = 1;
object result = doc.GetType().InvokeMember("createXPath", BindingFlags.Instance | BindingFlags.InvokeMethod, null, doc, args);

它在 Internet Explorer 11 (Windows 10) 中工作正常。

但是,当我将网站添加到兼容性视图(设置-> 兼容性视图设置)时,InvokeMember 调用抛出异常“Exception from HRESULT: 0x80020101”,这意味着 Javascript代码。

我的问题是,在上述情况下,有没有办法调试这段 Javascript 代码?不调试,仅根据0x80020101信息,几乎不可能找到根本原因。

如果你的 JS 代码中有脚本错误,为什么不使用 console.log()console.debug() 跟踪 client-side 代码的执行,以便你知道你的代码中发生了什么申请 ?

如果只想在Edge IE模式下调试代码,可以使用IEChooser打开Internet Explorer DevTools,如下:

  1. 在Windows中打开运行对话框。例如,按 Windows logo key + R.
  2. 输入%systemroot%\system32\f12\IEChooser.exe,然后点击确定。
  3. 在 IEChooser 中,select IE 模式选项卡的条目。

更多的细节,你也可以参考这个文档:Open DevTools on a tab in IE mode.