I am developing an IM provider for Outlook 2010. To do this, I need to implement some of the IMessenger * COM interfaces that load at startup. I want to do this using C # and the out-of-line server for which I followed the MSDN example here .
This is what I have already achieved:
- Register everything (CLSID, enter libraries, etc.) correctly and configure Outlook to try to load my server at startup
- Deploy the COM server as a native ATL / C ++ server and make sure that it works
- Deploy the base interface in C # /. NET and make sure it is loaded
At the moment, I can start my .EXE server, and then start the look and see the console windows of my server, while it displays all the method calls coming from the COM subsystem (I added registration for each method). The problem is that at some point (only in the .NET implementation!) I got an error that looks like this in Outlook logs:
CMsoIMProviderOC20::HrEnsureServiceData !failed! Line: 402 hr = 0x8000FFFF
I know exactly where this happens in my program, but I can not do anything about it (I tried to find a solution for this for several days). Remember that if I implement it using C ++ / ATL, it really works, so I assume that it should have something to do with how .NET Interop marshaling works.
Here are the details:
There are 3 interfaces to this problem: IMessenger, IMessengerServices and IMessengerService:
[ uuid(D50C3186-0F89-48f8-B204-3604629DEE10), // IID_IMessenger helpstring("Messenger Interface"), helpcontext(0x0000), dual, oleautomation ] interface IMessenger : IDispatch { ... [id(DISPID_MUAM_SERVICES), propget, helpstring("Returns services list."), helpcontext(0x0000)] HRESULT Services([out, retval] IDispatch ** ppdispServices); ... }
While I know that this Services property should actually return this information:
[ uuid(2E50547B-A8AA-4f60-B57E-1F414711007B), // IID_IMessengerServices helpstring("Messenger Services Interface"), helpcontext(0x0000), dual, oleautomation ] interface IMessengerServices : IDispatch { ... [id(DISPID_NEWENUM), propget, restricted, helpstring("Enumerates the services."), helpcontext(0x0000)] HRESULT _NewEnum([out, retval] IUnknown **ppUnknown); ... }
This interface, in turn, should return IMesengerService interfaces. However, this is not important for the purpose of this question.
In C ++ / ATL, I implement the Services property as follows:
STDMETHOD(get_Services)(IDispatch ** ppdispServices) { (*ppdispServices) = (IDispatch*)new CComObject<CMessengerServices>(); (*ppdispServices)->AddRef(); return S_OK; }
And here is the C # implementation:
public object Services { get { return new MessengerServices(); } }
Until everything is in order in both implementations! Now the problem begins ...
The first thing that is strange is that in C ++ / ATL, the get__NewEnum(IUnknown **pUnkown) my CMessengerServices class will never be executed. Instead, other functions are called. It's good.
In C #, however, the first member of my MessengerServices class that gets called is the GetEnumerator () method. I can set a breakpoint there and clearly see that this is the last line in C # code (under my control), which is executed before Outlook stops starting and reports error 0x8000FFFF in its log. After that, no other line of code on my .EXE server is called.
The most important parts of implementing the MessengerServices class are:
[ClassInterface(ClassInterfaceType.None)] [ComVisible(true), Guid("DF394E2C-38E2-4B70-B707-9749A4F857B0")] public class MessengerServices : IMessengerServices { IEnumerator IMessengerServices.GetEnumerator() { return messengerServices.GetEnumerator(); } private readonly ArrayList messengerServices; public MessengerServices() { messengerServices = new ArrayList { new MessengerService() }; } ... }
And here is the CCW proxy created by tlbimp.exe:
[ComVisible(true), Guid("2E50547B-A8AA-4F60-B57E-1F414711007B")] public interface IMessengerServices : IEnumerable { [TypeLibFunc(TypeLibFuncFlags.FRestricted)] [DispId(-4)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "System.Runtime.InteropServices.CustomMarshalers.EnumeratorToEnumVariantMarshaler, CustomMarshalers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] new IEnumerator GetEnumerator(); ... }
One final hint if this can be useful: when I set a breakpoint in the implementation of GetEnumerator () and hit F10 to jump, this is the last line in the Visual Studio output window:
Navigating the non-user code 'System.Runtime.InteropServices.CustomMarshalers.EnumeratorToEnumVariantMarshaler.MarshalManagedToNative
Another interesting thing (at least for me) is that if I completely remove the Enumerator object from the Interface declaration and the definition of my class, Outlook still calls my interface, but instead uses a different method (PrimaryService for completeness). but that basically has the same error.
Honestly, I absolutely do not know what to do with this error? Thanks in advance for any help!