2009-04-28 6 views
7

Quiero agregar algunas funcionalidades para rastrear ciertas llamadas a métodos de objetos ActiveX en javascript.Ampliando un ActiveXObject en javascript

Normalmente creo mi objeto activeX de esta manera: var tconn = new ActiveXObject ("Tconnector");

Necesito iniciar sesión cada vez que se llama al método open en tconn y todas las demás instancias de ese control activeX.

No puedo modificar el prototipo de tconn porque no tiene uno!

Creo que puedo crear una función ficticia ActiveXObject que crea un objeto proxy para llamadas proxy a la real. ¿Puedes ayudarme a hacer eso?

Nota: escribir un contenedor directo está fuera de cuestión, porque ya hay miles de llamadas a este activeX dentro de la aplicación.

+1

no creo que esto va a posible. ¿Tiene fuente para el Tconnetor? ¿Puedes redistribuir los binarios a los clientes y/o distribuir tus propios binarios si no eres el propietario? – AnthonyWJones

+0

No tengo la fuente, pero sí tengo una licencia que me permite redistribuirla libremente. De cualquier manera, ¿por qué todo esto importa si hago un objeto javascript proxy para llamadas proxy al objeto activeX? – mkoryak

+0

@mkoryak: He limpiado/actualizado el código en mi respuesta, y he creado una respuesta de enlace en su otra pregunta. – Tomalak

Respuesta

12

De hecho, puede anular ActiveXObject().

Esto significa que puede tratar de crear un objeto proxy transparente alrededor del objeto real y enganchar las llamadas al método. Esto significa que tendrías que construir un proxy alrededor de cada método y propiedad que tenga tu objeto ActiveX, a menos que estés absolutamente seguro de que no hay un código que llame a un método o propiedad en particular.

He creado una pequeña envoltura para el objeto "MSXML2.XMLHTTP". Probablemente hay todo tipo de problemas que se pueden ejecutar en, por lo que tomar con un grano de sal:

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); 
} 

responsabilidad: Especialmente el manejo asíncrono/onreadystatechange probablemente no está bien, y el código puede tener otros problemas como bien. Como dije, es solo una idea. Tratar con cuidado.

P.S .: Un objeto COM distingue entre mayúsculas y minúsculas cuando se trata de nombres de métodos y propiedades. Este contenedor es (como todo JavaScript) sensible a mayúsculas y minúsculas. Por ejemplo, si su código pasa a llamar tanto "Send()" y "send()", se necesita un esqueleto "Send()" método de la envoltura, así:

o.Send = function() { return this.send.apply(this, arguments); }; 
+0

woah, forma de responder a mi pregunta 100 de generosidad (http://stackoverflow.com/questions/756792/how-to-modify-activexobject-js-constructor). Me gustaría darle la recompensa, ya que esto es lo más cercano a responder que obtuve. Vaya allí y haga un enlace a su respuesta aquí – mkoryak

+0

En realidad, envolver el objeto XMLHTTP fue más un accidente. No tenía conocimiento de tu otra pregunta. :-) – Tomalak

+0

+1 muy buena solución – andi

0

El problema aquí es que parece que el IE no permitirá ahorrar del constructor activXObject original y dará un desbordamiento de la pila (;-) al crear el RealActiveXObject. parece que esto es especial para ActivX porque funciona cuando lo haces con otros objetos de JavaScript.

2

Una pequeña corrección para "Los datos necesarios para completar esta operación todavía no está disponible" en IE6 - la espera de integridad antes de población de propiedades RÉPONSE:

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(); 
3

Gracias mucho por su envoltorio. Con su ayuda, pude crear un detector xmlrequest para IE y FF y el resto.

He añadido una versión (combinado de otro ejemplo) que funciona para FF, IE y el resto de la banda,

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; 
} 
} 
Cuestiones relacionadas