5

I have a C# function with following signature:

int Get1251Bytes(string source, byte[] result, Int32 lengthOfResult)

I call it from C++. I was informed by compiler that 2-nd param must have SAFEARRAY* type. So I call it in this way:

SAFEARRAY* safeArray = SafeArrayCreateVector(VT_UI1, 0, arrayLength);
char str[] = {'s', 't', 'a', 'c', 'k', '\0'};
converter->Get1251Bytes(str, safeArray, arrayLength);

But safeArray is not updated, it still contains zores. But I tested Get1251Bytes function in C# unit-test. It works properly and updates result array. What am I doing wrong?

Zharro
  • 819
  • 1
  • 11
  • 23
  • I know *zero* about C#, but does the `byte[] result` need to be passed in as a `ref` type (likewise with the `lengthOfResult` if you intend on updating it as well)? – WhozCraig Dec 20 '12 at 09:44
  • I doesn't, I think. Array is a reference type in C# and I don't change array's reference itself (just edit values of elements). In this case it should updates by reference. – Zharro Dec 20 '12 at 09:50
  • Worth a shot. like i said, zilch-knowledge about C#. interesting question. – WhozCraig Dec 20 '12 at 09:51

2 Answers2

3

Your problem is related to Blittable and Non-Blittable Types (Byte is blittable):

As an optimization, arrays of blittable types and classes that contain only blittable members are pinned instead of copied during marshaling. These types can appear to be marshaled as In/Out parameters when the caller and callee are in the same apartment. However, these types are actually marshaled as In parameters, and you must apply the InAttribute and OutAttribute attributes if you want to marshal the argument as an In/Out parameter.

To fix your code you need to apply an [Out] attribute to the result parameter in the C# code:

int Get1251Bytes(string source, [Out] byte[] result, Int32 lengthOfResult)

Also, you don't need to pass lengthOfResult. In .NET you can use the Length property to get the size of the array.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • Thanks for good reference. But I've tried both `[Out]` and `[In, Out]` attributes before `byte[] result` - array is still filled by 0. – Zharro Dec 20 '12 at 13:09
  • @Zharro: I created a sample, reproduced your issue and fixed the issue by applying the `[Out]` attribute. One thing that looks a bit weird to me is the way you pass the string. I would expect the unmanaged parameter type to be `BSTR` and not `char[]` as you seem to be using. In my sample I use `SysAllocString` to create a proper `BSTR` which I then pass. If you enable mixed mode debugging you can have breakpoints also in the managed code to verify that your parameters are passed correctly. – Martin Liversage Dec 20 '12 at 13:18
  • execuse me! I forgot to specify this attribute in Get1251Bytes's signature in interface. Thank you very much! – Zharro Dec 20 '12 at 13:20
-1

Even with Array's you have to use ref or out. And you should use out.

int Get1251Bytes(string source, out byte[] result, Int32 lengthOfResult)
{
    ...
}

For more information about out and ref lokk at the links.

And here the article about arrays

Link
  • 1,307
  • 1
  • 11
  • 23
  • `out` and `ref` keywords use for allowing change reference itself (`new` keyword). My function doesn't change array's reference, it just change element values). – Zharro Dec 20 '12 at 11:45