0

Have a C++ ActiveX OCX with the following ODL declaration:

DISP_FUNCTION(CHellerCommCtrl, "GetRecipePath", GetRecipePath, VT_I4, VTS_PBSTR)

Need to call GetRecipePath from C# program and convert resultant C++ BSTR to C# string. Am aware, from other posts, of the following solution:

string s1 = Marshal.PtrToStringAnsi((IntPtr)outPtr);

Problem is, the prototype for GetRecipePath in C# via interop has argument "ref string" and will not permit me to typecast the resultant "string" to "IntPtr" and then pass that to the Marshal method. How to convert the "string" obtained from GetRecipePath [which is really a BSTR] to a C# string?

NinjaDeveloper
  • 1,620
  • 3
  • 19
  • 51
  • C++ string is a byte[] that terminates with '\0'. Use Encoding.UTF8.GetString(byte[]) to convert to string. – jdweng May 30 '16 at 16:14
  • I will give your suggestion a try, but must note that BSTR is a Unicode string not an [ASCII] byte string. I believe that is what the Marshall method does, convert Unicode to ASCII. –  May 30 '16 at 16:16
  • Don't put words in my mouth. I never used ASCII. If you have two byte characters than use Encoding Unicode instead of UTF8. Ascii removes unprintable characters. – jdweng May 30 '16 at 23:53
  • Tried Encoding.Unicode.GetBytes on string returned from OCX to get byte array. Then applied Encoding.UTF8.GetString on byte array to get what I thought would be a UTF8 string but got a twin byte Unicode string. Then simply did no Encoding whatsoever, instead used the string returned from OCX directly, and apparently that is already a UTF8 string. But the ODL declaration, see above, clearly returns PBSTR. Is the OCX sending a Unicode string or not? Can C# deal with both Unicode and UTF8 strings, and in fact is working directly with a Unicode string? Thanks. –  May 31 '16 at 02:03
  • I never completely understood how a string can both contain both one byte and two byte characters. I know it can but never looked to see how the characters are separated. – jdweng May 31 '16 at 08:22

1 Answers1

-1

A BSTR isn't just a pointer to a unicode string, it's prefixed by the length, allocated and freed with a specific api and comes with an implied change of ownership when passed to another method.

If your outPtr is a, BSTR then you could do the following:

string s1 = Marshal.PtrToStringBSTR(outPtr)

I'm not sure if Marshal.PtrToStringBSTR() frees the BSTR for you (the documentation is not explicit about this), but if it doesn't then you can follow up with a call to Marshal.FreeBSTR(outPtr).

Alternatively, you may be able to use a string in the managed COM interface and decorate it with [MarshalAs(UnmanagedType.BStr)]. Unfortunately, I'm not very familiar with DISP_FUNCTION or IDispatch, but I would guess the method signature in C# to be something like this:

[PreserveSig] 
int GetRecipePath([MarshalAs(UnmanagedType.BSTR)] out string path);

Or better yet:

[return: MarshalAs(UnmanagedType.BSTR)]
string GetRecipePath();
Brian Reichle
  • 2,798
  • 2
  • 30
  • 34