1

An implementation (here) of a COM filter class adds dependencies on MarshalByRefObject class and IDisposable interface, as follows:

class MessageFilter : MarshalByRefObject, IDisposable, IMessageFilter

The MSDN implementation of the same does not use these:

class MessageFilter : IOleMessageFilter

I have tried both implementations, and they both work. Why does the MSDN implementation not require the dependencies? Are they possibly pulled in due to attributes used by the IOleMessageFilter interface involved? The attributes used are:

[ComImport()]
[Guid("00000016-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

But these are used by both implementations, so I am confused. Both implementations also specify [DllImport("Ole32.dll")], but the MSDN implementation does not include an accompanying [PreserveSig].

Sabuncu
  • 5,095
  • 5
  • 55
  • 89
  • Isn't MarshalByRef exclusively to support (deprecated) Remoting? – 500 - Internal Server Error Mar 21 '15 at 18:07
  • @500-InternalServerError My research on `MarshalByRefObject` indicates it is needed by Remoting, but I did not gather that it's been deprecated. Rather, I read that WCF is now suggested as its replacement. – Sabuncu Mar 21 '15 at 18:08
  • That is what I meant. As far as I know there is no relation to COM, though. – 500 - Internal Server Error Mar 21 '15 at 18:11
  • 1
    @Sabuncu [`MarshalByRefObject`](https://msdn.microsoft.com/en-us/library/system.marshalbyrefobject(v=vs.110).aspx) can(and in some cases should) be still used to interoperate between different [Application Domains](http://stackoverflow.com/questions/1094478/what-is-a-net-application-domain). But whether it is required or not for COM interop I don't know. – Eugene Podskal Mar 21 '15 at 18:42
  • @Sabuncu I am just unsure for what, because I am not very experienced with Interop and haven't provided an answer to the actual question. – Eugene Podskal Mar 21 '15 at 18:48
  • 1
    @EugenePodskal I make the effort to thank everyone who comments, unless the comment completely misses the question. Just my own policy. SO is not necessarily a friendly place, and I think every bit helps. – Sabuncu Mar 21 '15 at 19:02
  • @Sabuncu Understood. – Eugene Podskal Mar 21 '15 at 19:04
  • The code that implements `IDisposable` should actually use a finalizer, for the apparent intent I gather from the source code (restoring the previous handler). As it is, it only restores the previous hander if you call `Dispose` or use the object in a `using` statement. – acelent Mar 27 '15 at 12:21

2 Answers2

1

IMO, there's nothing special in MarshalByRefObject's implementation that would make it stand out vs mere Object for implementing COM IMessageFilter (AKA IOleMessageFilter).

Perhaps, it would be more logical to derive MessageFilter from StandardOleMarshalObject, because (from here):

Only STA (APARTMENT_THREADED) threads may have message filters If CoRegisterMessageFilter is called on a thread which was initialized with COINIT_MULTITHREADED, then the return code is CO_E_NOT_SUPPORTED (0x80004021)

That said, I'm not sure StandardOleMarshalObject would be a requirement, either, because IMessageFilter methods are supposed to be called only on the same STA thread which has registered the COM message filter.

You can read more about StandardOleMarshalObject vs Object here in my recent question:

And here in Andrew Whitechapel's MSDN blog:

Andrew Whitechapel also has an excellent blog post on IMessageFilter itself:

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • Thank you for your answer and for the wealth of useful links that do not otherwise feature prominently in Google searches. – Sabuncu Mar 22 '15 at 09:23
  • @Noseratio, I made some tests on apartment handling, I need to update the referred answer. But to sum it up here: `StandardOleMarshalObject` seems to make the object live in the **main** STA thread (the first thread to enter an STA, explicitly (`CoInitialize`) or implicitly by activating an STA object (`CoCreateInstance`)), and `ServicedComponent` has a lot more implications than just COM marshaling. – acelent Mar 26 '15 at 17:59
  • I'm trying to figure out a way to automatically COM-marshal a .NET object in a COM call, but all I found out until now requires `MarshalAs` on every p/invoke and interface method. As for .NET itself, you should use a proxy object that delegates each method call to the correct apartment, or use COM marshaling for the sake of correctness and support for the neutral apartment. Now that I think of it, a proxy would also work for CCW calls, even if the CCW itself is free-threaded. – acelent Mar 26 '15 at 18:00
  • @PauloMadeira, interesting, thanks for keeping me updated. I'd be very interested in the further results of your research. – noseratio Mar 26 '15 at 19:47
1

COM is a purely interface-based programming paradigm. It is completely unaware what that class looks like, all it cares about is that it implements IMessageFilter. This is not different from the way interfaces work in the C# language.

So if the programmer had a good reason to let the class do more than just receive the message filter callbacks then that's just fine. I'd venture a guess that he implemented IDisposable to restore the old message filter. Explaining MarshalByRefObject gets considerably harder, you'd have to dig through source code to find a good reason.

What is very different in COM is that it completely doesn't care about the name of the interface. You can call it anything you like, the only thing that matters is the [Guid]. IMessageFilter is the name used in MSDN documentation, the Visual Studio guys probably wanted to avoid a collision with the .NET IMessageFilter type, it does something completely different.

So yes, it is entirely normal that your class works fine. Don't add anything you don't need.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536