views:

1748

answers:

4

I want to add some functionality track certain calls to ActiveX object methods in javascript.

I usually create my activeX object like this: var tconn = new ActiveXObject("Tconnector");

I need to log every time the open method is called on tconn and all other instances of that activeX control.

I cant modify tconn's prototype because it does not have one!

I think that i can create a dummy ActiveXObject function that creates a proxy object to proxy calls to the real one. Can you help me do that?

Note: writing a direct wrapper is out of question, because there are already 1000s of calls to this activeX within the application.

+6  A: 

You can in fact override ActiveXObject().

This means you can try to build a transparent proxy object around the actual object and hook on method calls. This would mean you'd have to build a proxy around every method and property your ActiveX object has, unless you are absolutely sure there is no code whatsoever calling a particular method or property.

I've built a small wrapper for the "MSXML2.XMLHTTP" object. There are probably all kinds of problems you can run into, so take that with a grain of salt:

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

Disclaimer: Especially the async/onReadyStateChange handling probably isn't right, and the code may have other issues as well. As I said, it's just an idea. Handle with care.

P.S.: A COM object is case-insensitive when it comes to method- and property names. This wrapper is (as all JavaScript) case-sensitive. For example, if your code happens to call both "Send()" and "send()", you will need a skeleton "Send()" method in the wrapper as well:

o.Send = function() { return this.send.apply(this, arguments); };
Tomalak
woah, way to answer my 100 bounty question(http://stackoverflow.com/questions/756792/how-to-modify-activexobject-js-constructor). id like to give you the bounty since this the the closest thing to answer i got for it. Please go there and make a link to your answer here
mkoryak
Actually wrapping the XMLHTTP object was more of an accident. I had no knowledge of your other question. :-)
Tomalak
+1 very nice solution
andi
Neat-o.........
ken
A: 

The problem here is that it seems that IE wont allow saving of the original activXObject constructor and will give a stack overflow (;-) upon creating the ActualActiveXObject. it seems that this is special for the ActivX because it is working when doing that with other javascript objects.

A: 

A little fix for "The data necessary to complete this operation is not yet available" in IE6 - waiting for completeness before population of reponse properties:

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();
lfryc
A: 

to Tomalak: I tested you script and it's works perfect with native call. But when i used it with jQuery, it's not working. It rewrite ActiveXObject, Jquery construct AJAX, i get trace from your script, and that's all, data doesn't send to the server.

Do you have any idea why this can happen?

Creotiv
Hey, i found a better script that does this and tested it with jquery. Here is a test page for it. make sure you have your js console up if not in IE to see anything. http://programmingdrunk.com/current-projects/xhrWrapper/
mkoryak
And i made this all work. Here you can test it http://gist.github.com/469941
Creotiv