最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - In JScript: Can I enumerate the methods on an object created via new ActiveXObject()? - Stack Overflow

programmeradmin1浏览0评论

This is really a question for Eric Lippert, or someone at Microsoft who's familiar with the implementation of the JScript engine.

Can I do this:

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

?

(supposing the COM type supports IDispatch)

and if so, what does GetMethodsViaMagic() look like?


EDIT - of course, the first thing I tried was the for...in loop, but that does not work for methods and properties defined on ActiveX objects. At least, not for objects I've defined in .NET and exposed via ComVisible.


In C#, I can define IDispatch like this:

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

Then I can do something like this:

    var idispatch = (IDispatch) Object ;
    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));

...and get function (method) names, and the number of arguments, etc.

Can I do something like that in JScript, for an ActiveX (COM IDispatch) object?

This is really a question for Eric Lippert, or someone at Microsoft who's familiar with the implementation of the JScript engine.

Can I do this:

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

?

(supposing the COM type supports IDispatch)

and if so, what does GetMethodsViaMagic() look like?


EDIT - of course, the first thing I tried was the for...in loop, but that does not work for methods and properties defined on ActiveX objects. At least, not for objects I've defined in .NET and exposed via ComVisible.


In C#, I can define IDispatch like this:

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

Then I can do something like this:

    var idispatch = (IDispatch) Object ;
    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));

...and get function (method) names, and the number of arguments, etc.

Can I do something like that in JScript, for an ActiveX (COM IDispatch) object?

Share Improve this question edited Aug 22, 2011 at 12:56 Cheeso asked Aug 21, 2011 at 22:35 CheesoCheeso 193k105 gold badges485 silver badges734 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

First off, keep in mind that I haven't worked on JScript for over a decade now; the engine has changed in that time and my memory has faded.

To the best of my recollection and knowledge: The for-in loop will work if the object implements IDispatchEx, but not if the object just implements IDispatch.

I always wanted to add a mechanism such that JScript programs could use information available from the type info associated with the dispatch object to enumerate the properties, but I don't believe I ever actually wrote the code.

What I found is that I can use the Javascript for...in loop, to enumerate the methods and properties, if I have implemented IReflect on the ComVisible .NET object.

IReflect is marshaled as IDispatch across the CCW.

You should be able to do

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

the methods array will then contain the method names. If the object in question is an instance of some constructor, you might want to drop the hasOwnProperty check, as that restricts everything to only look at properties/methods that are defined on the obj itself, not those in its prototype chain.

As for the number of arguments, you can use (as Domenic points out in the ments) the .length property of the function itself.

So to get both name and number of arguments for every method in obj:

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

And you'll get an array of object literals, each containing the name and the number of arguments of a method from obj.


Edit: I was thinking about getting the names (rather than simply the number) of arguments, when I first wrote this answer, and thus included some fairly hacky code to get those names. In case anyone's interested, here's the code for that, which I just shamelessly stole adapted from 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;
}

Pass a function/method to that function, and it'll give you back the argument names… maybe. If the object you get back is a fully-fledged host object, its methods/functions may not be readable by toString(). Usually, toString() will return the actual source code of the method/function (and the argumentNames function parses that with some regex), but in the case of native code, you may just get the string "native code" or something back, rather than the source code.

发布评论

评论列表(0)

  1. 暂无评论