views:

1088

answers:

1

Hi,

how can one use a Safearray to pass an array of custom types (a class containing only properties) from C++ to C#? Is using the VT_RECORD type the right way to do it?

I am trying in the following way, but SafeArrayPutElement returns an error when trying to fill the safearray the reference to the array of classes gets to the managed code as a NULL.

I have something like the following in the managed world:

[ComVisible(true)]
public interface IStatistics
{
    double Mean { get; set; } 
    double StdDev { get; set; } 
}

[Serializable]
[ComVisible(true)]
public class Statistics : IStatistics
{
    public Mean { get; set; }
    public double StdDev { get; set; } 
}

Unmanaged world:

HRESULT hr = CoInitialize(NULL);
...
SAFEARRAY *pEquationsStatistics;

// common dimensions for all arrays
SAFEARRAYBOUND dimensions[1];  
dimensions[0].cElements = 2;   
dimensions[0].lLbound = 0;    

pEquationsStatistics = SafeArrayCreate(VT_RECORD, 1, dimensions);
...

for (long i = 0; i < dimensions[0].cElements; i++)
{
    long indices[1];
    indices[0] = 0;

    ... 

    // Equation statistics
    IStatisticsPtr pIStatistics(__uuidof(Statistics)); 
    pIStatistics->PutMean(1.0); // so far so good

    result = SafeArrayPutElement(pEquationsStatistics, indices, pIStatistics);

    ...
    indices[0]++;
}

Please note that the I am able use the SafeArray to pass other arrays of BSTR with no problems between the two applications. So this is something peculiar to passing a structure.

Stefano

+1  A: 

I'm not really sure if I understand your question right, but maybe you need VT_DISPATCH? I think if you want it to work with VT_RECORD, then your struct should actually be a struct (not a class) and also needs the [StructLayout(LayoutKind.Sequential)] attribute.

Edit: Can it be that the error you first got was DISP_E_BADINDEX? What exactly is indices in your code? What does it contain? (You know that the signature of SafeArrayPutElement requires it to be a pointer, right?)

fretje
Anything that gets the job done is ok with me ;) Juddging only from the name, VT_RECORD seemed to be closest option to what I am trying to accomplish. I just need to be able to expose this structure/class to the unmanaged code to populate it.
Stefano Ricciardi
Can you elabore on HOW your current solution exactly fails? An error message maybe?
fretje
*elaborate off course ;-)
fretje
When I posted this question, I was getting a negative return value from the SafeArrayPutElement. For some reason, this is not happening anymore (not sure what has caused this, maybe jet another clean/rebuild cycle?); now when I run the debugger and step into the managed code, the reference to the class (which I pass via an API) appears to be NULL.
Stefano Ricciardi
Actually, the reference to the array of classes is null.
Stefano Ricciardi
I have added a bit more context in the code. Note that inside the for loop I am able to succesfully populate and pass to the managed code 2 array of strings. It's just the array of classes which doesn't work for me. Thank you for your help! :)
Stefano Ricciardi
This looks good to me... Have you tried VT_DISPATCH? or making the class a struct in stead? Otherwise, I don't think I can help any more :(
fretje
I have just tried the VT_DISPATCH seems to do the trick. Thank you a lot!
Stefano Ricciardi