tags:

views:

33

answers:

2

I need to marshal an array of String^ to call a unmanaged function that expects an array of BSTRs.

On MSDN I found the article

How to: Marshal COM Strings Using C++ Interop

with this code sample:

// MarshalBSTR1.cpp
// compile with: /clr
#define WINVER 0x0502
#define _AFXDLL
#include <afxwin.h>

#include <iostream>
using namespace std;

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma unmanaged

void NativeTakesAString(BSTR bstr) {
   printf_s("%S", bstr);
}

#pragma managed

int main() {
   String^ s = "test string";

   IntPtr ip = Marshal::StringToBSTR(s);
   BSTR bs = static_cast<BSTR>(ip.ToPointer());
   pin_ptr<BSTR> b = &bs;

   NativeTakesAString( bs );
   Marshal::FreeBSTR(ip);
}

So I created a new BSTRs' array and called the Marshal::StringToBSTR() for every String of the array. Then I created a managed pin_ptr array.

array<pin_ptr<BSTR> >^ gcDummyParameters = gcnew array<pin_ptr<BSTR> >(asParameters->Length);

but I receved the error:

Error   2   error C2691: 'cli::pin_ptr<Type>' : a managed array cannot have this element type

I tried also with a native array:

pin_ptr<BSTR> dummyParameters[100000];

but even in this case I got an error:

Error   1   error C2728: 'cli::pin_ptr<Type>' : a native array cannot contain this managed type 

What else can I do?

+2  A: 

Microsoft sample looks strange: there is no need to pin BSTR type because it is unmanaged. Just create BSTR array and fill every member using Marshal::StringToBSTR. Don't use pin_ptr.

Alex Farber
Yup, the sample snippet is completely bogus. Just use BSTR array[].
Hans Passant
http://stackoverflow.com/questions/1105010/necessary-to-pin-ptr-on-c-clr-value-types-why Made me think there may be some Microsoft's obscure reason to pin_point a BSTR. I would prefer to stay on the safe side, if possible :)
sergiom
I beleive that Hans Passant's confirmation leaves you on the safe side :) BSTR is just unmanaged pointer, GC doesn't touch unmanaged memory. Otherwise, simple C++/CLI code like int* p = new int[1]; *p = 1; can crash.
Alex Farber
Don't pay any attention to that other question, it starts with a false assumption "Since .NET Value types (managed C++ structs) are stored on the Stack..." This is not true in the general case.
Ben Voigt
+2  A: 

pin_ptr should be removed from this sample. bs is a local variable and will not be moved by the garbage collector, also it is passed to the native function by value so there would be no problem if it did move.

The BSTR content to which it points is natively allocated by the system's BSTR allocator, it also will not be moved by the garbage collector.

Ben Voigt