2009-04-28 64 views
7

Tôi muốn thêm một số chức năng theo dõi các cuộc gọi nhất định vào các phương thức đối tượng ActiveX trong javascript.Mở rộng ActiveXObject trong javascript

Tôi thường tạo đối tượng activeX như sau: var tconn = new ActiveXObject ("Tconnector");

Tôi cần đăng nhập mỗi khi phương thức mở được gọi trên tconn và tất cả các phiên bản khác của điều khiển activeX đó.

Tôi không thể sửa đổi nguyên mẫu của tconn vì nó không có!

Tôi nghĩ rằng tôi có thể tạo một hàm ActiveXObject giả tạo tạo đối tượng proxy cho các cuộc gọi proxy tới cuộc gọi thực. Bạn có thể giúp tôi làm điều đó không?

Lưu ý: viết một trình bao bọc trực tiếp đã hết câu hỏi, vì đã có 1000 cuộc gọi đến activeX này trong ứng dụng.

+1

Tôi không nghĩ rằng điều này sẽ càng tốt. Có nguồn cho Tconnetor không? Bạn có thể phân phối lại các tệp nhị phân cho khách hàng và/hoặc phân phối các tệp nhị phân của riêng bạn nếu bạn không sở hữu nó không? – AnthonyWJones

+0

Tôi không có nguồn, nhưng tôi có một giấy phép cho phép tôi phân phối lại nó một cách tự do. Dù bằng cách nào, tại sao tất cả các vấn đề này nếu tôi thực hiện một đối tượng javascript proxy để gọi proxy đến đối tượng activeX? – mkoryak

+0

@mkoryak: Tôi đã xóa/cập nhật mã trong câu trả lời của mình và tôi đã tạo câu trả lời liên kết trong câu hỏi khác của bạn. – Tomalak

Trả lời

12

Bạn thực tế có thể ghi đè ActiveXObject().

Điều này có nghĩa là bạn có thể thử xây dựng một đối tượng proxy trong suốt xung quanh đối tượng thực tế và móc vào các cuộc gọi phương thức. Điều này có nghĩa là bạn phải xây dựng một proxy xung quanh mọi phương thức và thuộc tính đối tượng ActiveX của bạn, trừ khi bạn hoàn toàn chắc chắn rằng không có mã nào gọi một phương thức hoặc thuộc tính cụ thể.

Tôi đã tạo một trình bao bọc nhỏ cho đối tượng "MSXML2.XMLHTTP". Có lẽ tất cả các loại của các vấn đề bạn có thể gặp phải, vì vậy hãy rằng với một hạt muối:

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: Đặc biệt là việc xử lý async/onreadystatechange lẽ là không đúng, và mã có thể có những vấn đề khác như tốt. Như tôi đã nói, đó chỉ là một ý tưởng. Xử lý cẩn thận.

P.S .: Đối tượng COM phân biệt chữ hoa chữ thường khi nói đến tên phương thức và thuộc tính. Trình bao bọc này (giống như tất cả JavaScript) phân biệt chữ hoa chữ thường. Ví dụ, nếu mã của bạn xảy ra để gọi cả "Send()""send()", bạn sẽ cần một bộ xương "Gửi()" phương pháp trong wrapper cũng như:

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

woah, cách trả lời 100 câu hỏi tiền thưởng của tôi (http://stackoverflow.com/questions/756792/how-to-modify-activexobject-js-constructor). id như để cung cấp cho bạn tiền thưởng kể từ khi điều gần nhất để trả lời tôi đã nhận cho nó. Hãy đến đó và tạo một liên kết đến câu trả lời của bạn ở đây – mkoryak

+0

Trên thực tế việc bao bọc đối tượng XMLHTTP là một tai nạn. Tôi không có kiến ​​thức về câu hỏi khác của bạn. :-) – Tomalak

+0

+1 giải pháp rất đẹp – andi

0

Vấn đề ở đây là nó có vẻ rằng IE sẽ không cho phép tiết kiệm của hàm khởi tạo activXObject ban đầu và sẽ cung cấp tràn ngăn xếp (;-) khi tạo ActualActiveXObject. có vẻ như đây là điều đặc biệt cho ActivX vì nó hoạt động khi thực hiện điều đó với các đối tượng javascript khác.

2

Một sửa chữa nhỏ cho "Các dữ liệu cần thiết để hoàn thành thao tác này chưa có sẵn" trong IE6 - chờ đợi cho đầy đủ trước khi dân số thuộc tính phản ứng:

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

Cảm ơn bạn rất nhiều vì wrapper của bạn. Với sự giúp đỡ của bạn, tôi đã có thể tạo ra một máy dò xmlrequest cho IE và FF và phần còn lại.

Tôi đã thêm một phiên bản (kết hợp từ một ví dụ khác) mà làm việc cho FF, IE và phần còn lại của băng đảng,

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; 
} 
} 
Các vấn đề liên quan