2011-08-21 50 views
3

對於Eric Lippert或熟悉JScript引擎實現的Microsoft人員來說,這確實是一個問題。在JScript中:我可以枚舉通過新的ActiveXObject()創建的對象上的方法嗎?

我可以這樣做:

var obj = new ActiveXObject("My.ProgId"); 
var methods = GetMethodsViaMagic(obj); 

(假設COM類型支持的IDispatch)

如果是這樣,什麼是GetMethodsViaMagic()樣子?


編輯 - 當然,我想的第一件事就是for...in循環,但這並不對ActiveX對象定義的方法和屬性的作用。至少,不適用於我在.NET中定義並通過ComVisible公開的對象。


在C#中,我可以這樣定義的IDispatch:

[Guid("00020400-0000-0000-c000-000000000046"), 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IDispatch 
{ 
    int GetTypeInfoCount(); 
    System.Runtime.InteropServices.ComTypes.ITypeInfo 
     GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, 
        [MarshalAs(UnmanagedType.U4)] int lcid); 

    [PreserveSig] 
    int GetIDsOfNames(ref Guid riid, 
         [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames, 
         int cNames, 
         int lcid, 
         [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); 

    [PreserveSig] 
    int Invoke(int dispIdMember, 
       ref Guid riid, 
       [MarshalAs(UnmanagedType.U4)] int lcid, 
       [MarshalAs(UnmanagedType.U4)] int dwFlags, 
       ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, 
       [Out, MarshalAs(UnmanagedType.LPArray)] object[] pVarResult, 
       ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, 
       [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr); 
} 

然後,我可以做這樣的事情:

var idispatch = (IDispatch) comObject ; 
    System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo = 
     idispatch.GetTypeInfo(0, 0); 

    System.Runtime.InteropServices.ComTypes.FUNCDESC funcDesc; 
    string strName, strDocString, strHelpFile; 
    int dwHelpContext; 

    typeInfo.GetFuncDesc(i, out pFuncDesc);// i = 1, 2, 3... 
    funcDesc = (System.Runtime.InteropServices.ComTypes.FUNCDESC) 
     Marshal.PtrToStructure(pFuncDesc, 
           typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC)); 

...並得到函數(方法)的名字,和參數的數量等。

我可以在JScript中爲ActiveX(COM IDispatch)對象做類似的事嗎?

回答

6

首先,請記住,我從未在JScript上工作​​了十多年;那個時候發動機已經改變了,我的記憶已經消失了。

就我的回憶和知識而言:如果對象實現IDispatchEx,則for-in循環將工作,但如果對象僅實現IDispatch,則循環將不起作用。

我一直想要添加一個機制,使JScript程序可以使用與調度對象相關的類型信息中可用的信息來枚舉屬性,但我不相信我實際上寫過代碼。

+0

感謝您的貢獻,Lippert先生。擁有你描述的功能將會很方便。無法想象現在添加該功能會破壞很多程序。我知道Win8會獲得更多的Javascript愛;看起來非常有趣。 – Cheeso

2

你應該能夠做到

var methods = []; 
for(var property in obj) { 
    if(obj.hasOwnProperty(property) && typeof obj[property] === 'function') { 
     methods.push(property); 
    } 
} 

methods數組,然後將包含方法名。如果所討論的對象是某個構造函數的實例,則可能需要刪除hasOwnProperty檢查,因爲這會限制所有內容僅查看在obj本身定義的屬性/方法,而不是其原型鏈中定義的屬性/方法。

至於參數的數量,你可以使用(如Domenic指出的註釋)the .length property函數本身。

所以在obj同時獲得名稱和每個方法參數的個數:

var methods = []; 
for(var property in obj) { 
    if(obj.hasOwnProperty(property) && typeof obj[property] === 'function') { 
     methods.push({ 
      name: property, 
      args: obj[property].length 
     }); 
    } 
} 

,你會得到對象常量數組,每個包含的名稱和方法的參數從數obj


編輯:我想獲得的(而不是簡單的數量)的參數,當我第一次寫這個答案,並因此包括一些相當哈克代碼來獲取那些名字。如果任何人的興趣,下面是該代碼,我只是 無恥偷 Prototype.js改編

function argumentNames(func) { 
    var names = func.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] 
    .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') 
    .replace(/\s+/g, '').split(','); 
    return names.length == 1 && !names[0] ? [] : names; 
} 

傳遞一個函數/方法是功能,這會給你回參數名... 也許。如果您找回的對象是完全成熟的主機對象,則其方法/函數可能無法被toString()讀取。通常,toString()將返回方法/函數的實際源代碼(並且argumentNames函數使用一些正則表達式解析該函數​​),但在本機代碼的情況下,您可能只會得到字符串「本機代碼」或某種東西,而不是源代碼。

+0

您可以通過函數對象的'length'屬性獲取函數的參數個數:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/length – Domenic

+0

Domenic:當然,你是對的 - 我出於某種原因正在考慮參數_names_。我會更新我的答案。謝謝! – Flambino

+0

期待微軟的ActiveX對象實現Netscape的JavaScript或ECMAScript特性正在醞釀之中。不要驚訝它失敗,或拋出一個錯誤。 – RobG

3

我發現什麼是我可以使用JavaScript for...in循環,枚舉的方法和屬性,如果我已經實現了減反射的標記有ComVisible特性.NET對象上。

IReflect被編組爲遍佈CCW的IDispatch。

+0

這似乎並不是這樣。 for..in'循環不適用於com-visible,基於IReflect的類。爲什麼似乎不是埃裏克的回答上面的唯一原因;也就是說,它需要一個IDispatchEx接口(而IReflect僅實現IDispatch,如鏈接中所述)。 – Christian

相關問題