Setting a SAFARRAY output parameter in a COM method

0

I'm trying to study and reimplement a (black-box) COM server for an existing (black-box) client. I successfully registered a dummy implementation by importing the type library and creating a .NET class that implements the interface of the server.

I have a problematic signature that does not seem to work when called by the client:

This is the IDL definition:

[id(0x00000007), helpstring("method GetFoo")]
HRESULT GetFoo(VARIANT* vector);

The imported .NET definition:

[DispId(7)]
void GetFoo(ref object vector);

Note: the vector parameter is an output parameter.

The client can successfully call my server which implements this interface. During this call I can see that the vector parameter contains an array of 16 bytes. However, it appears that the data I'm setting in the array is not correctly sent to the client. I have reverse engineered the original server and found the exact VARIANT flags that it expects for the paramter. Using this information I have created a C++ client that gets the data in the output paramter when calling the original server:

const int TABLE_LENGTH = 16;
SAFEARRAY* table = SafeArrayCreateVector(VT_I1, 0, TABLE_LENGTH);

VARIANT val; VariantInit(&val);
val.vt = VT_BYREF | VT_ARRAY | VT_I1 | VT_NULL;
val.pparray = &table;
realServer->GetFoo(&val); 
// now table contains valid data

If I use this client to call my server, I get a SafeArrayTypeMismatchException before the breakpoint in the method would be hit.

My question is: how can I implement the .NET method so that a the above client would get the data I set in the ref parameter?

c#
com
interop
asked on Stack Overflow Sep 5, 2014 by Tamás Szelei • edited May 23, 2017 by Community

1 Answer

1

You have to pass a VARIANT to keep the server happy. That is object in a .NET program. So it has to look like this:

object arg = null;
realServer.GetFoo(ref arg);
byte[] data = (byte[])arg;

The IDL was poorly authored, the argument should have been attributed with [out, retval]. Usually a sign that you'll have some more problems. Another problem with arrays is that they might have their first element at index 1 instead of 0. Something you can see back in the debugger, the arg variable will look like System.Byte[*]. In which case you'll have to cast to Array instead of byte[].

answered on Stack Overflow Sep 5, 2014 by Hans Passant

User contributions licensed under CC BY-SA 3.0