I am trying to develop a C# COM server that is accessible to clients only via IDispatch. Some of the methods of my COM objects return an array of interfaces to other COM objects.
When I attempt to do this using early binding, such as via the code provided in this answer, it works with no issues. As soon as I try and decorate my types to use late binding via IDispatch however, the request fails with 0x80020005: Type mismatch. Other non-interface types can be returned via IDispatch without issue, it's just COM interfaces that are failing to be transmitted properly.
Given the following C++ client
CoInitialize(NULL);
IMyRootClassPtr ptr(__uuidof(MyRootClass));
try
{
auto entities = ptr->GetEntities();
}
catch (_com_error &err)
{
wprintf(L"The server throws the error: %s\n", err.ErrorMessage());
wprintf(L"Description: %s\n", (PCWSTR)err.Description());
}
The following code works with early binding
C#:
[ComVisible(true)]
public interface IMyRootClass
{
IEmailEntity[] GetEntities();
}
[ComVisible(true)]
public class MyRootClass : IMyRootClass // some class to start with
{
public IEmailEntity[] GetEntities()
{
List<IEmailEntity> list = new List<IEmailEntity>();
for (int i = 0; i < 10; i++)
{
EmailEntity entity = new EmailEntity();
entity.Body = "hello world " + i;
list.Add(entity);
}
return list.ToArray();
}
}
[ComVisible(true)]
public interface IEmailEntity
{
string Body { get; set; }
}
public class EmailEntity : IEmailEntity
{
public string Body { get; set; }
}
By making the following changes
- Add
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]toIMyRootClass - Add
[ClassInterface(ClassInterfaceType.None)]toMyRootClass
I would think this should now work via IDispatch, but instead I get the Type mismatch error referred to above. I've spent the afternoon debugging into where exactly the error is coming from. The Dispatch call to the .NET Framework appears to succeed, returning a VARIANT of type VT_ARRAY | VT_DISPATCH (2009), which is expected, however the validation of the final result appears to fall down under
main
_com_dispatch_method
_com_invoke_helper
VariantChangeType
VariantChangeTypeEx
I've had a look at the disassembly of where its falling down in oleaut32.dll and at this stage I'm just concluding this must be a bug in Windows. Does anyone potentially have an advice otherwise?
IEmailEntity[] GetEntities()intoobject[] GetEntities()and for the last line change 'list.ToArray()' into 'list.Cast<object>().ToArray()' or don't use Ptr suffixed interfacesobject"properly" that appears to resolve the issue. I can see in the disassembly of_com_invoke_helperit only callsVariantChangeTypebased on some sort of check on the return value, so I guess there must be some metadata in there that said "this is not really anobjectin this array". If you post that you need to return anobject[]non-covariently I can accept that as the answer