COM based .net plugin framework

0

I have an ASP.NET MVC3 website which has to work with COM plugins. In order to do that I need to define an interface somehow. As far as I understand(I'm not a COM expert) this can be done either in .NET and export it with tlbexp.exe or idl->midl->tlbimp.

I have gone the first way(with tlbexp). I tried IDL too but to no avail(for some reason could cast the implementing COM object back to the tlbimp'ed interface in .NET).

This scenario would be simple if my interface didn't have an event on it:

[ComVisible(true)]
[Guid("EFCFB783-0225-4D45-94CB-9A26B7CC19AF")]
public delegate void ItemStatusChanged(string itemGuid, string itemStatus);

[ComVisible(true)]
[Guid("35202AE5-392D-4015-993D-29966DA5DE31")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICOMOutputPlugin
{
    void Method1(string arg);
    void Method2(string arg);
    event ItemStatusChanged ItemStatusChanged;
}

[ComVisible(true)]
[Guid("93862C43-503C-4C96-9BAE-944F1087AB77")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICOMOutputPluginEvents
{
    void ItemStatusChanged(string itemGuid, string itemStatus);
}

I export this to tlb with tlbexp.exe and register the .tlb with regtlibv12. Only this type library will be used by the plugin developers to import the interfaces.

Now I have a C++ project which will be a plugin, I add in VS2010 new simple ATL object and change the IDL to:

importlib("stdole2.tlb");
importlib("MyExp.tlb");

[
    uuid(E09BC67A-4192-4CA3-8FD0-5CBFC69B43AC)      
]
coclass DumpToFileOutputPlugin
{
    [default] interface ICOMOutputPlugin;
    [default, source] dispinterface ICOMOutputPluginEvents;
};

My first problem here was that for some reason I couldn't add the connection point the 'normal way' via class wizard. It simply doesn't show any source interfaces when I direct it to my MyExp.tlb. So I did that manually(used another .tlb and renamed everything).

So now I have the COM object with these 2 methods:

STDMETHOD(add_ItemStatusChanged)(_ItemStatusChanged* value);
STDMETHOD(remove_ItemStatusChanged)(_ItemStatusChanged* value);

On the .NET side the plugin manager instantiates the plugins like this:

Type type = Type.GetTypeFromProgID(progID);
comObject = Activator.CreateInstance(type) as ICOMOutputPlugin;
comObject.ItemStatusChanged += (guid, status) => ItemStatusChanged(guid, status);

the last line miraculously calls the add_ItemStatusChanged method on my COM object.

Here I'm stuck, what should I don in this method? my current implementation is:

HRESULT CDumpToFileOutputPlugin::add_ItemStatusChanged(_ItemStatusChanged* value)
{
        DWORD cookie;
        HRESULT ret = Advise(value, &cookie);
        _com_error err(ret);
        LPCTSTR errMsg = err.ErrorMessage();
        return ret;
}

ret = CONNECT_E_CANNOTCONNECT(0x80040202) and errMsg says "IDispatch error #2". Apparently Advise expects the COM object passed to implement the connection point interface ICOMOutputPluginEvents which the delegate passed object does not... what can I do?

Am I doing the subscription to the event on the .NET side wrong or the add handler?

Any help how to solve this would be appreciated.

c#
.net
com
com-interop
asked on Stack Overflow Jul 4, 2012 by Ventsyslav Raikov • edited Jul 4, 2012 by Ventsyslav Raikov

1 Answer

-1

Don't use "events" in a COM plugin for ASP.Net, just have methods that you call. I.e. a method called OnEventName rather than an event.

COM events are just not the right kind of thing for handling web form postbacks.

answered on Stack Overflow Jul 4, 2012 by Ben

User contributions licensed under CC BY-SA 3.0