How do I retrun a BSTR from C++ to VB.NET

  • Thread starter Michael Tissington
  • Start date
M

Michael Tissington

I have a C++ function in a DLL of the form

BSTR WINAPI DoSomeWork(LPCSTR szConnection, LPCSTR szGUID)

I use SysAllocStringByteLen to return a BSTR.

For the most part this works accept when the calling applicaiton tries to
free the BSTR and I get a RtlFreeHeep error. I'm guessing because the bstr
has been allocated in one dll and it being released in another.

So how do I allocate the bstr that I'm returning ?
 
J

Jeff Partch [MVP]

Michael Tissington said:
I have a C++ function in a DLL of the form

BSTR WINAPI DoSomeWork(LPCSTR szConnection, LPCSTR szGUID)

I use SysAllocStringByteLen to return a BSTR.

For the most part this works accept when the calling applicaiton tries to
free the BSTR and I get a RtlFreeHeep error. I'm guessing because the bstr
has been allocated in one dll and it being released in another.

So how do I allocate the bstr that I'm returning ?

Does the calling app use SysFreeString? Can you show and example of how
determine the byte length to allocate and how you subsequently fill the
BSTR?
 
M

Michael Tissington

I have no idea what the calling app does (it can be either a VB 6 or VB.NET
application) to free the string.

This is how I declare it in VB 6

Public Declare Function DoSomeWork Lib "Work.dll" (ByVal strConnection As
String, ByVal strGUID As String) As String

And this is how I fill it (not that I think this is of much help)

BSTR bstrEntryID = NULL;
......
bstrEntryID = SysAllocStringByteLen(NULL, (sizeof(SQLVIEW_ENTRYID) * 2) +
1);
HexFromBin((LPBYTE)&eid, sizeof(SQLVIEW_ENTRYID), (LPSTR)bstrEntryID);
return bstrEntryID

Both VB and VB.NET seem to get the string correctly and are able to work
with it.

Its just that I get the RtlFreeHeep error in VB.NET when it uses this
funciton.



--
Michael Tissington
http://www.oaklodge.com
http://www.tabtag.com
 
J

Jeff Partch [MVP]

Michael Tissington said:
I have no idea what the calling app does (it can be either a VB 6 or VB.NET
application) to free the string.

This is how I declare it in VB 6

Public Declare Function DoSomeWork Lib "Work.dll" (ByVal strConnection As
String, ByVal strGUID As String) As String

And this is how I fill it (not that I think this is of much help)

BSTR bstrEntryID = NULL;
.....
bstrEntryID = SysAllocStringByteLen(NULL, (sizeof(SQLVIEW_ENTRYID) * 2) +
1);

Try making that +1 a +2, just for the heck of it. :)
 
T

Tom Shelton

I have a C++ function in a DLL of the form

BSTR WINAPI DoSomeWork(LPCSTR szConnection, LPCSTR szGUID)

I use SysAllocStringByteLen to return a BSTR.

For the most part this works accept when the calling applicaiton tries to
free the BSTR and I get a RtlFreeHeep error. I'm guessing because the bstr
has been allocated in one dll and it being released in another.

So how do I allocate the bstr that I'm returning ?

Ok... I believe to deallocate a buffer created with
SysAllocStringByteLen, that you need to deallocate that memory with
SysFreeString. Marshal.FreeBSTR will do this... What you may want to do
is wrap this call in a function that returns a managed string.

Maybe this would work... Though, I'm not sure since I haven't worked a
lot with BSTR in .NET.

Private Declare Function DoSomeWork Lib "whatever" _
(ByVal szConnection As String, _
ByVal szGuid As String) As IntPtr


Public Function DoSomeWorkWrapper _
(ByVal Connection As String, ByVal id As Guid) As String

Dim bstrPtr As IntPtr = IntPtr.Zero
Try

' you might need to manipulate the guid string some what,
' since I'm not sure what format your function needs it in :)
bstrPtr = DoSomeWork (Connection, id.ToString())

// return a managed string from the unmanaged bstr
Return Marshal.PtrToStringBSTR (bstrPtr)

Finally
If Not bstrPtr.Equals (IntPtr.Zero) Then
Marshal.FreeBSTR (bstrPtr)
End If
End Try


End Function

Anyway, that may or may not work. Otherwise, you'll need to pin the
object get the pointer, and then call FreeBSTR that way. But, anyway
you look at it - RtlFreeHeap probably can't deallocate the memory used
by the BSTR.
 
M

Mattias Sjögren

Maybe this would work... Though, I'm not sure since I haven't worked a
lot with BSTR in .NET.

Private Declare Function DoSomeWork Lib "whatever" _
(ByVal szConnection As String, _
ByVal szGuid As String) As IntPtr


The runtime should do the right thing if you declare it as

Private Declare Function DoSomeWork Lib "whatever" _
(ByVal szConnection As String, _
ByVal szGuid As String) As
<MarshalAs(UnmanagedType.AnsiBStr)> String

I don't think Marshal.PtrToStringBSTR would work here as the string
was allocated with SysAllocStringByteLen and contains ANSI characters.




Mattias
 
T

Tom Shelton

The runtime should do the right thing if you declare it as

Private Declare Function DoSomeWork Lib "whatever" _
(ByVal szConnection As String, _
ByVal szGuid As String) As
<MarshalAs(UnmanagedType.AnsiBStr)> String

I don't think Marshal.PtrToStringBSTR would work here as the string
was allocated with SysAllocStringByteLen and contains ANSI characters.

You are most likely correct... I looked up Marshal.FreeBSTR, and it
doesn't mention SysAllocStringByteLen - yet, the documentation for
SysFreeString does.

Oh, well. Like I said - I haven't really had to do much with BSTR since
I moved to .NET. So, take my advice with a grain of salt.

To the OP - listen to Mattias, he is the interop guru :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top