0

I am trying to call a function which allocates memory for the string and then does something with the string. Here is the basic example which illustrates the problem:

C++:

    STDMETHODIMP CFunctionsCollection::Function2 (  
        BSTR leftString, BSTR rightString, BSTR * conString
    )
{
    int leftLen = lstrlen(leftString);
    int rightLen = lstrlen(rightString);

    *conString = new TCHAR[leftLen+rightLen+1];

    for (int i=0 ; i<leftLen ; ++i)
        (*conString)[i] = leftString[i];
    for (int i=0 ; i<rightLen ; ++i)
        (*conString)[leftLen+i] = rightString[i];
    (*conString)[leftLen+rightLen] = 0;

    return S_OK;
}

The following call from C++ program works just fine:

BSTR leftString = SysAllocString(L"Left String");
BSTR rightString = SysAllocString(L"Right String");
BSTR conString;
hr = pFunctionsCollection->Function2 ( leftString, rightString, & conString);

C# declaration:

Int32 Function2([In, MarshalAs(UnmanagedType.BStr)] String leftString,
                [In, MarshalAs(UnmanagedType.BStr)] String rightString,
                [In, Out] ref IntPtr conStr);

C# call:

try
{
    String leftString = "Left String"; 
    String rightString = "Right String";
    IntPtr outStr = IntPtr.Zero;
    pFunctionsCollection.Function2(leftString, rightString, ref outStr);
    String outString = Marshal.PtrToStringUni(outStr);
    Console.WriteLine("Out String = {0}", outString);
}
catch (Exception e)
{
    Console.WriteLine("Call to Function2 failed with {0}", e.Message);
}

The program fails with

Call to Function2 failed with Insufficient memory to continue the execution of the program.

Does anyone knows how to make such a calls from C#?

Vladimir
  • 1
  • 1
  • 1
  • That's horrible. Why not change the C# interface to just return a string by reference? – sharptooth Nov 10 '10 at 09:01
  • I tried this but hit exactly the same error. Int32 Function2([In, MarshalAs(UnmanagedType.BStr)] String leftString, [In, MarshalAs(UnmanagedType.BStr)] String rightString, [In, Out] ref String conStr); String leftString = "Left String"; String rightString = "Right String"; String outString = String.Empty; pFunctionsCollection.Function2(leftString, rightString, ref outString); Console.WriteLine("Out String = {0}", outString); The error was the same – Vladimir Nov 10 '10 at 09:14

1 Answers1

1

conString is a BSTR, and must be treated as such. See http://msdn.microsoft.com/en-us/library/ms221069.aspx

  1. You should use SysStringLen to get the length of the BSTRs
  2. You last parameter in C# should be an out string marshalled as a BSTR

    [In, Out, MarshalAs(UnmanagedType.BStr)] out string conStr

  3. You need to allocate the memory for conStr with SysAllocString or SysAllocStringLen

  4. List item

You cannot allocate memory using 'new' and cast it to a BSTR. BSTR's have specific requirements for memory management and layout that you are not satisfying. You must follow these conventions always. The interop fails because it expects you are following the conventions for BSTRs, but you are not.

joncham
  • 1,584
  • 10
  • 14