I have download the source code the the Out-of-process COM server in C# from this MS site: https://code.msdn.microsoft.com/windowsapps/CSExeCOMServer-3b1c1054. In that code, there is a definition for a COM object named SimpleObject. The object is define in this way:
[Guid(SimpleObject.InterfaceId), ComVisible(true)]
public interface ISimpleObject
{
float FloatProperty { get; set; }
string HelloWorld();
}
Then where is an events interface:
[Guid(SimpleObject.EventsId), ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISimpleObjectEvents
{
[DispId(1)]
void FloatPropertyChanging(float NewValue, ref bool Cancel);
}
The component iself is defined like this:
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ISimpleObjectEvents))]
[Guid(SimpleObject.ClassId), ComVisible(true)]
public class SimpleObject : ReferenceCountedObject, ISimpleObject
{
internal const string ClassId =
"DB9935C1-19C5-4ed2-ADD2-9A57E19F53A3";
internal const string InterfaceId =
"941D219B-7601-4375-B68A-61E23A4C8425";
internal const string EventsId =
"014C067E-660D-4d20-9952-CD973CE50436";
[EditorBrowsable(EditorBrowsableState.Never)]
[ComRegisterFunction()]
public static void Register(Type t)
{
// Registration bolderplate, ommited
}
[EditorBrowsable(EditorBrowsableState.Never)]
[ComUnregisterFunction()]
public static void Unregister(Type t)
{
// Registration bolderplate, ommited
}
private float fField = 0;
public float FloatProperty
{
get { return this.fField; }
set
{
bool cancel = false;
if (null != FloatPropertyChanging)
FloatPropertyChanging(value, ref cancel);
if (!cancel)
this.fField = value;
}
}
public string HelloWorld()
{
return "HelloWorld";
}
[ComVisible(false)]
public delegate void FloatPropertyChangingEventHandler(float NewValue, ref bool Cancel);
public event FloatPropertyChangingEventHandler FloatPropertyChanging;
}
At the end we have the class factory which is just boilerplate code.
internal class SimpleObjectClassFactory : IClassFactory
{
public int CreateInstance(IntPtr pUnkOuter, ref Guid riid,
out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;
if (pUnkOuter != IntPtr.Zero)
{
// The pUnkOuter parameter was non-NULL and the object does
// not support aggregation.
Marshal.ThrowExceptionForHR(COMNative.CLASS_E_NOAGGREGATION);
}
if (riid == new Guid(SimpleObject.ClassId) ||
riid == new Guid(COMNative.IID_IDispatch) ||
riid == new Guid(COMNative.IID_IUnknown))
{
// Create the instance of the .NET object
ppvObject = Marshal.GetComInterfaceForObject(
new SimpleObject(), typeof(ISimpleObject));
}
else
{
// The object that ppvObject points to does not support the
// interface identified by riid.
Marshal.ThrowExceptionForHR(COMNative.E_NOINTERFACE);
}
return 0; // S_OK
}
public int LockServer(bool fLock)
{
return 0; // S_OK
}
}
Now what I want to do, is to subscribe to the FloatPropertyChanging
event using late binding.
I have tried doing this in the following way:
public void TestMethod3()
{
var type = Type.GetTypeFromProgID("QuasarCOMServer.COMObjects.SimpleObject"); // adjusted namespace hence the name
dynamic instance = Activator.CreateInstance(type);
instance.FloatProperty = 10;
instance.FloatPropertyChanging += new Action<float>(InstanceOnFloatPropertyChanging); // <- this is the problem
}
private void InstanceOnFloatPropertyChanging(float newvalue)
{
Debug.WriteLine("Value changed to " + newvalue);
}
Now the server goes up, I can see the process, and calling instace.FloatProperty
works as expected.
The problem is subscribing to event; the event is of type System.Dynamic.BoundDispEvent
. The source code for this types brings me here: https://searchcode.com/codesearch/view/52696999/. This shows, that this type contains a method Called TryBinaryOperation
which seems to accept "AddAssign" type of expression.
However, executing the line instance.FloatPropertyChanging += new Action<float>(InstanceOnFloatPropertyChanging);
just returns
System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x80040200'
.
How do I do this properly?
User contributions licensed under CC BY-SA 3.0