Расширение ActiveXObject в JavaScript - PullRequest
8 голосов
/ 28 апреля 2009

Я хочу добавить некоторые функции отслеживания определенных вызовов к объектным методам ActiveX в javascript.

Я обычно создаю свой объект ActiveX следующим образом: var tconn = новый ActiveXObject ("Tconnector");

Мне нужно регистрироваться каждый раз, когда метод open вызывается для tconn и всех других экземпляров этого элемента управления activeX.

Я не могу изменить прототип tconn, потому что у него его нет!

Я думаю, что могу создать фиктивную функцию ActiveXObject, которая создает прокси-объект для прокси-вызовов к реальному. Вы можете помочь мне сделать это?

Примечание: о написании прямой оболочки не может быть и речи, поскольку в этом приложении уже есть тысячи вызовов этому activeX.

Ответы [ 4 ]

13 голосов
/ 28 апреля 2009

Вы можете переопределить ActiveXObject().

Это означает, что вы можете попытаться построить прозрачный прокси-объект вокруг фактического объекта и подключить вызовы метода. Это будет означать, что вам придется создавать прокси вокруг каждого метода и свойства, имеющегося у вашего объекта ActiveX, если только вы не уверены, что нет кода, вызывающего конкретный метод или свойство.

Я создал небольшую оболочку для объекта "MSXML2.XMLHTTP". Вероятно, есть все виды проблем, с которыми вы можете столкнуться, поэтому возьмите это с крошкой соли:

var ActualActiveXObject = ActiveXObject;

var ActiveXObject = function(progid) {
  var ax = new ActualActiveXObject(progid);

  if (progid.toLowerCase() == "msxml2.xmlhttp") {
    var o = {
      _ax: ax,
      _status: "fake",
      responseText: "",
      responseXml: null,
      readyState: 0,
      status: 0,
      statusText: 0,
      onReadyStateChange: null
      // add the other properties...
    };
    o._onReadyStateChange = function() {
      var self = o;
      return function() {
        self.readyState   = self._ax.readyState;
        self.responseText = self._ax.responseText;
        self.responseXml  = self._ax.responseXml;
        self.status       = self._ax.status;
        self.statusText   = self._ax.statusText;
        if (self.onReadyStateChange) self.onReadyStateChange();
      }
    }();
    o.open = function(bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword) {
      varAsync = (varAsync !== false);
      this._ax.onReadyStateChange = this._onReadyStateChange
      return this._ax.open(bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword);
    };
    o.send = function(varBody) {
      return this._ax.send(varBody);
    };
    // add the other methods...
  }
  else {
    var o = ax;
  }

  return o;
}

function Test() {
  var r = new ActiveXObject('Msxml2.XMLHTTP');

  alert(r._status);  // "fake"

  r.onReadyStateChange = function() { alert(this.readyState); };
  r.open("GET", "z.xml");
  r.send();

  alert(r.responseText);
}

Отказ от ответственности: особенно обработка async / onReadyStateChange, вероятно, не является правильной, и у кода могут быть и другие проблемы. Как я уже сказал, это просто идея. Обращаться с осторожностью.

P.S .: COM-объект нечувствителен к регистру, когда дело доходит до имен методов и свойств. Эта оболочка (как и весь JavaScript) чувствительна к регистру. Например, если ваш код вызывает как "Send()", так и "send()", вам также потребуется скелетный метод "Send ()" в оболочке:

o.Send = function() { return this.send.apply(this, arguments); };
4 голосов
/ 05 февраля 2012

Большое спасибо за упаковку. С вашей помощью я смог создать детектор xmlrequest для IE, FF и всего остального.

Я добавил версию (в сочетании с другим примером), которая работает для FF, IE и остальных банд,

if(window.XMLHttpRequest)
{
var XMLHttpRequest = window.XMLHttpRequest;

// mystery: for some reason, doing "var oldSend = XMLHttpRequest.prototype.send;" and 
//  calling it at the end of "newSend" doesn't work...
var startTracing = function () {
    XMLHttpRequest.prototype.uniqueID = function() {
        // each XMLHttpRequest gets assigned a unique ID and memorizes it 
        //  in the "uniqueIDMemo" property
        if (!this.uniqueIDMemo) {
            this.uniqueIDMemo = Math.floor(Math.random() * 1000);
        }
        return this.uniqueIDMemo;
    }

    // backup original "open" function reference
    XMLHttpRequest.prototype.oldOpen = XMLHttpRequest.prototype.open;

    var newOpen = function(method, url, async, user, password) {
        console.log("[" + this.uniqueID() + "] intercepted open (" + 
                    method + " , " + 
                    url + " , " + 
                    async + " , " + 
                    user + " , " + 
                    password + ")");
        this.oldOpen(method, url, async, user, password);
    }

    XMLHttpRequest.prototype.open = newOpen;

    // backup original "send" function reference
    XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;

    var newSend = function(a) {
        console.log("[" + this.uniqueID() + "] intercepted send (" + a + ")");
        var xhr = this;
        var onload = function() { 
            console.log("[" + xhr.uniqueID() + "] intercepted load: " + 
                    xhr.status + 
                    " " + xhr.responseText); 
        };

        var onerror = function() { 
            console.log("[" + xhr.uniqueID() + "] intercepted error: " + 
                    xhr.status); 
        };

        xhr.addEventListener("load", onload, false);
        xhr.addEventListener("error", onerror, false);

        this.oldSend(a);
    }
    XMLHttpRequest.prototype.send = newSend;
}


startTracing();
}
else if (window.ActiveXObject) {
var ActualActiveXObject = ActiveXObject;

var ActiveXObject = function(progid) {
    var ax = new ActualActiveXObject(progid);

    if (progid.toLowerCase() == "msxml2.xmlhttp") {

        var o = {
            _ax: ax,
            _status: "fake",
            responseText: "",
            responseXml: null,
            readyState: 0,
            status: 0,
            statusText: 0,
            onReadyStateChange: null
        };
        o._onReadyStateChange = function() {
            var self = o;
            return function() {
            self.readyState   = self._ax.readyState;
            if (self.readyState == 4) {
                self.responseText = self._ax.responseText;
                self.responseXml  = self._ax.responseXml;
                self.status       = self._ax.status;
                self.statusText   = self._ax.statusText;
            }
                if (self.onReadyStateChange) self.onReadyStateChange();
            }
        }();
        o.open = function(bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword) {
            console.log("intercepted open (" + 
                bstrMethod + " , " + 
                bstrUrl + " , " + 
                varAsync + " , " + 
                bstrUser + " , " + 
                bstrPassword + ")");
            varAsync = (varAsync !== false);
            this._ax.onReadyStateChange = this._onReadyStateChange
            return this._ax.open(bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword);
        };
        o.send = function(varBody) {
            return this._ax.send(varBody);
        };
    }
    else
        var o = ax;
    return o;
}
}
2 голосов
/ 07 апреля 2010

Небольшое исправление для «данных, необходимых для выполнения этой операции, еще не доступно» в IE6 - ожидание полноты перед заполнением свойств ответа:

self.readyState   = self._ax.readyState;
 if (self.readyState == 4) {
  self.responseText = self._ax.responseText;
  self.responseXml  = self._ax.responseXml;
  self.status       = self._ax.status;
  self.statusText   = self._ax.statusText;
 }
 if (self.onReadyStateChange) self.onReadyStateChange();
0 голосов
/ 07 июня 2009

Проблема здесь в том, что кажется, что IE не разрешит сохранение исходного конструктора activXObject и вызовет переполнение стека (;-) при создании ActualActiveXObject. кажется, что это специально для ActivX, потому что он работает, когда это делается с другими объектами JavaScript.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...