Ask Learn
Preview
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The CLR supports marshalling of objects that support the IReflect interface as IDispatch COM objects. Similarly, IExpando gets marshalled as IDispatchEx. Here is a sample of a managed type called ManagedIDispatch which is used from VBScript and used in a late-bound way. VBScript just deals with IDispatch, and under the hoods, the CLR routes the calls to the IReflect methods implemented by ManagedIDispatch, and also takes care of providing a stable mapping between method names and dispids.
IReflect.GetMethods gets called every time COM instantiates the managed type. The CLR caches the method names for the given object, and the names are then available to COM from the IDispatch interface. If COM accesses a method name that is not in the cached list, IReflect.GetMethods get called again.
The C# code should be compiled and registered as:
csc /t:library ManagedIDispatch.cs
regasm /codebase ManagedIDispatch.dll
Here is the significant contents of ManagedIDispatch.cs
public class ManagedIDispatch : IReflect {
...
public MethodInfo[] GetMethods(BindingFlags bindingAttr) {
Console.WriteLine("In ManagedIDispatch.GetMethods (_getMethodsDone={0})", _getMethodsDone);
// dynFoo is a method that is not always present
if (_getMethodsDone) {
MethodInfo[] methods = new MethodInfo[_methodInfos.Length + 1];
_methodInfos.CopyTo(methods, 0);
methods[_methodInfos.Length] = new MyMethodInfo("dynFoo");
return methods;
} else {
_getMethodsDone = true;
return _methodInfos;
}
}
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) {
Console.WriteLine("In ManagedIDispatch.InvokeMember({0} : {1})", name, GetArgs(target, args));
switch (name) {
case "[DISPID=0]": return this;
case "raiseException": throw new Exception("raiseException has been invoked");
case "foo": return "foo-return";
case "dynFoo": Debug.Assert(_getMethodsDone); return "dynFoo-return";
default:
if (name == ("bar" + _index)) return "bar-return";
throw Utils.NotImplemented("This is unreachable");
};
}
}
Here is the VBScript used to script the type:
Sub AssertError(errNum, errDescr)
If Err.Number <> errNum Then
MsgBox "Error number is incorrect:" & Err.Number & ", expected " & errNum
End If
If Err.Description <> errDescr Then
MsgBox "Error description is incorrect:" & Err.Description & ", expected " & errDescr
End If
Err.Clear
End Sub
c1 = CreateObject("TestFactory")
m = c1.GetManagedObject()
m.foo()
m.dynFoo()
m.bar0()
On Error Resume Next
m.nonexistent()
AssertError 438, "Object doesn't support this property or method"
m.raiseException()
AssertError -2146233088, "" ' 0x80131500 : CLR exception
The output of the script is:
c:\bugs>cscript vbs1.vbs
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.
In ManagedIDispatch.GetMethods (_getMethodsDone=False)
In MyMethodInfo.Name.get(foo)
In MyMethodInfo.Name.get(bar0)
In MyMethodInfo.Name.get(raiseException)
In ManagedIDispatch.InvokeMember([DISPID=0] : ManagedIDispatch)
In ManagedIDispatch.InvokeMember(foo : ManagedIDispatch)
In ManagedIDispatch.GetMethods (_getMethodsDone=True)
In MyMethodInfo.Name.get(dynFoo)
In ManagedIDispatch.InvokeMember(dynFoo : ManagedIDispatch)
In ManagedIDispatch.InvokeMember(bar0 : ManagedIDispatch)
In ManagedIDispatch.GetMethods (_getMethodsDone=True)
In MyMethodInfo.Name.get(dynFoo)
In ManagedIDispatch.InvokeMember(raiseException : ManagedIDispatch)
Anonymous
May 04, 2008
Nice post, but....
I still can't find a way to have parameters passed by reference...
I've implemented MyMethodInfo.GetParameters method, and, there i create array of ParameterInfo descendants, override their methods, but, no methods of my ParameterInfo descendants gets called!
This is class - descendant of ParameterInfo (excuse me for Delpi.Net)
TMyParamInfo = class(ParameterInfo)
public
constructor Create(...);
///NO ONE OF METHODS BELOW CALLED by CCW IDispatch implementation!
function GetCustomAttributes(AInherit: Boolean): TObjectArr; overload; override;
function GetCustomAttributes(AType: System.Type;
AInherit: Boolean): TObjectArr; overload; override;
function IsDefined(AType: System.Type;
AInherit: Boolean): Boolean; override;
function get_Attributes: ParameterAttributes; override;
function get_ParameterType: System.Type; override;
function get_DefaultValue: System.Object; override;
function get_Member: MemberInfo; override;
function get_Name: string; override;
function get_Position: Integer; override;
end;
//HERE I RETURN MY PARAMETERS BAG.
//They differs by attributes: ParameterAttributes.In/Out/Retval
function TMyMethodInfo.GetParameters: TParameterInfoArr;
var
i: Integer;
begin
SetLength(Result, Length(FParams));
for i := 0 to Length(FParams) - 1 do
begin
Result[i] := TMyParamInfo.Create(...);
end;
end;
I have no idea, why CCW IDispatch implementation ignores my own parameters definition...
Here is call log of my appication:
//IActiveScript.AddNamedItem... TScriptHost added as 'Host' item
//
TScriptHost.GetProperties
TScriptHost.GetFields
TScriptHost.GetMethods, BindingFlags=[Instance, Static, Public]
TMyMethodInfo.get_Name
TMyMethodInfo.get_Name
TScriptHost.GetProperties
TScriptHost.GetFields
TScriptHost.GetMethods, BindingFlags=Instance, Static, Public
TScriptHost.GetProperties
TScriptHost.GetFields
TScriptHost.GetMethods, BindingFlags=Instance, Static, Public
TMyMethodInfo.GetParameters
TMyMethodInfo.GetCustomAttributes System.Runtime.InteropServices.LCIDConversionAttribute
TScriptHost.InvokeMember: Method1(mumu, 12), [InvokeMethod, OptionalParamBinding]
TMyMethodInfo.GetParameters
TMyMethodInfo.GetCustomAttributes System.Runtime.InteropServices.LCIDConversionAttribute
TScriptHost.InvokeMember: Method2(mumu, 12, 1245), [InvokeMethod, OptionalParamBinding]
TScriptHost.InvokeMember: Method1(mumu, 12, 1245), [InvokeMethod, OptionalParamBinding]
TScriptHost.InvokeMember: Method2(mumu, 12, 1245), [InvokeMethod, OptionalParamBinding]
OK
Anonymous
May 04, 2008
On my post above:
i will be very glad, if you will help me to find a way, how to set different attributes (In/Out/Retval) for parameters of methods of application objects exposed to script with AddNamedItem
Anonymous
May 11, 2008
No questions more...
I've fixed the problem.
It was just Delphi.Net bug
Anonymous
May 13, 2008
The DLR aims to enable dynamic languages like IronPython and IronRuby to access and minipulate objects
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign in