在 JScript 中:我可以枚举通过 new ActiveXObject() 创建的对象的方法吗?

发布于 2024-11-30 17:06:11 字数 2343 浏览 2 评论 0原文

这确实是 Eric Lippert 或熟悉 JScript 引擎实现的 Microsoft 人员的问题。

我可以这样做吗:

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) 对象?

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

...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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

人事已非 2024-12-07 17:06:11

首先,请记住,我已经十多年没有使用 JScript 了;那时引擎已经改变,我的记忆也逐渐消失。

据我所知和所知:如果对象实现 IDispatchEx,for-in 循环将起作用,但如果对象仅实现 IDispatch,则不起作用。

我一直想添加一种机制,以便 JScript 程序可以使用与调度对象关联的类型信息中提供的信息来枚举属性,但我不相信我实际上编写过代码。

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.

肩上的翅膀 2024-12-07 17:06:11

我发现,如果我在 ComVisible .NET 对象上实现了 IReflect,我可以使用 Javascript for...in 循环来枚举方法和属性。

IReflect 在 CCW 中被封送为 IDispatch。

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.

溺深海 2024-12-07 17:06:11

您应该能够执行

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

methods 数组,然后将包含方法名称。如果有问题的对象是某个构造函数的实例,您可能需要删除 hasOwnProperty 检查,因为这会限制所有内容仅查看 obj 本身定义的属性/方法,而不是它的原型链。

至于参数的数量,您可以使用(正如 Domenic 在评论中指出的那样) 函数本身的 .length 属性

因此,要获取 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 中方法的名称和参数数量。


编辑:当我第一次写这个答案时,我正在考虑获取参数的名称(而不仅仅是数量),因此包含了一些相当hacky的代码来获取这些名称。如果有人感兴趣,这里是我刚刚无耻地窃取的代码,改编自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 函数使用一些正则表达式来解析它),但在本机代码的情况下,您可能只得到字符串“本机代码”或其他内容,而不是源代码。

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 comments) 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文