我有一些实现IReflect接口的代码,用于将IDispatch外观呈现到某些.NET对象上,而无需将所有COM interop goo粘贴到类本身上。

我们之所以使用它,是因为我们有一个脚本客户端想要使用这些类,但是我们不想将所有COM interop东西都放到这些类本身上。

代码几乎是这样的:

[ComVisible(true)]
[ProgId("My.Factory")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MyFactory
{
    public object CreateObject(string type)
    {
        return new AutoWrap(Activator.CreateInstance(Type.GetType(type)));
    }
}


[ProgId("My.AutoWrap")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComVisible(true)]
[Guid("72EAFB10-099F-4e96-A17E-B67E34DACA53")]
public class AutoWrap : IReflect
{
    protected object O = null;
    protected Type T = null;

    public AutoWrap()
    {
    }

    public AutoWrap(object obj)
    {
        O = obj;
        T = O.GetType();
    }

    #region IReflect Members

    public System.Reflection.FieldInfo GetField(string name, System.Reflection.BindingFlags bindingAttr)
    {
        return T.GetField(name, bindingAttr);
    }

    /* SNIP other IReflect methods */


    public object InvokeMember(string name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object target, object[] args, System.Reflection.ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    {
        // Unwrap any AutoWrap'd objects (they need to be raw if a paramater)
        if (args != null && args.Length > 0)
        {
            for (int x = 0; x < args.Length; x++)
            {
                if (args[x] is AutoWrap)
                {
                    args[x] = ((AutoWrap)args[x]).O;
                }
            }
        }


        // Invoke whatever needs be invoked!
        object obj = T.InvokeMember(name, invokeAttr, binder, O, args, modifiers, culture, namedParameters);

        // Wrap any return objects (that are not primative types)
        if (obj != null)
        {
            switch (obj.GetType().ToString())
            {
                case "System.String":
                case "System.DateTime":
                case "System.Boolean":
                case "System.Byte":
                case "System.Char":
                case "System.Decimal":
                case "System.Double":
                case "System.Single": // Float
                case "System.Int32":
                case "System.Int64": // Long
                case "System.SByte":
                case "System.Int16": // Short
                case "System.UInt32":
                case "System.UInt64":
                case "System.UInt16":
                    break; // These Types do not get wrapped
                default:
                    obj = new AutoWrap(obj); // Wrap Type
                    break;
            }
        }

        return obj;

    }

    public object UnderlyingObject
    {
        get
        {
            return O;
        }
    }

    public Type UnderlyingSystemType
    {
        get { return T.UnderlyingSystemType; }
    }

    #endregion
}


然后,脚本客户端具有如下代码来调用对象(VBScript中的示例):

Set factory= CreateObject("My.Factory")
set myObject = factory.CreateObject("MyDotNetType")

myObject.DoSomething ' where DoSomething() is a method on MyDotNetType


使用上面的脚本,将创建包装MyDotNetType实例的实例AutoWrap,并且当客户端调用DoSomething时,将在AutoWrap上调用InvokeMember方法,该方法将转过来并在MyDotNetType上调用DoSomething。

所有这些在VBScript和Javascript中都能很好地工作。

但是,当尝试通过Siebel的eScript脚本语言使用它时,事情会失败,因为eScript始终将[DISPID = somerandomnumber]作为名称传递给InvokeMember,而不是像VBScript那样传递方法名称。

有谁知道一种从.NET代码控制这些DispID的方法吗?我尝试了几种不同的方法,但都没有成功:


从其他IReflect成员返回自定义PropertyInfo / MethodInfo类,这些类将从GetCustomAttributes返回DispIdAttribute
反射。在运行时发出一个包装器类,该包装器类具有向COM公开的必需属性(并不是真的希望它能起作用,但以为我会尝试的)


TIA

最佳答案

我认为您可以在字段上添加[DispId(1234)]来控制什么是dispid。

10-05 19:15