Problem combining a visual basic app, c++ dll, and callback methods

The short of my question is this: How do I create a VB callback that is invoked from within a c++ dll which passes a character string from the c++ dll to the VB callback method.

Specifically, my VB app loads a dll I created in c++.  This dll needs to notify the app of certain events created by the user.  One of these events requires that a character message be sent from the c++ dll to the VB app.  

The pointer to the callback function:
(CALLBACK* AddEntityFunc)(short index, float x, float y, short type, BSTR text);

in C++ the exported function to receive the callback method looks like this.
void __declspec(dllexport) CALLBACK AddEntityFunc(long address)
    AddEntityFunc = (void (CALLBACK*)(short index, float x, float y, short type, BSTR text))address;
in vb the method to callback looks like
Public Sub AddEntityCallback(ByVal index As Integer, ByVal x As Single, ByVal y As Single, ByVal t As Integer, ByVal str As String)

frm.label = str                      'Just to see if we get the correct data.

End Sub

When I invoke the vb callback method I use something like:
short id = 2;
float x = 3.2;
float y = 5.39;
short type = 1;
and data is a previously filled char array of up to 50 characters.
AddEntityFunc(index, x,y,type, data);

I've tried createing an array of unsigned shorts to pass in, but it crashes the program,
I've tried casting the char array to a BSTR, but that crashes the program.
I would prefer not to use MFC as the dll has not been built with MFC.
Can anyone give me some direction on this?  I am stuck.  

Thanks in advance,
Who is Participating?
drichardsConnect With a Mentor Commented:
As I was out biking this morning, I realized it is not surprising that you can call back into the VB once the C/C++ dll is loaded into the VB process.  It is only calling from C/C++ executable into VB that is problematic.  Also, as I reread your initial problem, you say you 'tried casting the char array to a BSTR'.  Do you really mean cast, or did you actually create a BSTR? A BSTR has a 4 bytes length preceding the character pointer, so casting will most definitely crash your program even if the characters are UNICODE which is the other property of a BSTR.

Starting with a char array, you need to do something like:

    wchar_t wideChar[256]; // use appropriate size
    mbstowcs(wideChar, charArray, 256); // charArray is your original string:  char charArray[];
    BSTR myBSTR = SysAllocString(wideChar);

Then you can try passing myBSTR back to VB.  If you already did this, then I do not now what else to try.
As far as I know, you cannot call directly into VB from C++.  You need to use COM if you want to do that.
curtisnAuthor Commented:
Actually, you can. I am doing it plenty with my program, I am able to send back single characters, shorts, and longs to VB from c++. even whole parameter lists.  The one part I am struggling with is sending the string at the end.  I imagine there are a few lines to convert a char * to a BSTR, but for the life of me I can't figure it out.  I can send a String from VB to c++.  But not the other way.
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

curtisnAuthor Commented:
additionally, sometimes the dll will need to send the empty string.  Clearly I could solve this by writting another callback, but I am interested in solving both of these with the same callback method.

>>  I can send a String from VB to c++.  
Yes, but the VB runtime does a bit of magic to make that work.  You'll notice that even though VB uses BSTR's internally, a call out to a function with a char* parameter will succeed.  Once the call has passed the VB boundary, the runtime doesn't case any more.  I assume that the 'Declare' statements produce some kind of marshaling code.  This doesn't exist for the callback on the raw pointer you handed out to the C function.  I'll be curious to see if someone knows the bit of magic to make it work.

It's interesting that you can do a callback from C to VB with basic types, though.  I'll definitely add that to my bag of tricks.
curtisnAuthor Commented:
This sounds like it might work, I will try it when I get to work Monday morning.  Thanks for the better understanding of BSTR, I thought it was simply a pointer to an array of unsigned shorts.  I am very new at the VB end of things, and that is why I am having so much grief.

I guess you should try to pass the string by reference.

In VB:
Public Sub AddEntityCallback(ByVal index As Integer, ByVal x As Single, ByVal y As Single, ByVal t As Integer, ByRef str As String)

In C++:
(well, i'm not very experienced with C)
But you should try to pass the address of the string directly to VB (as a long)..
as long as i know: byval causes troubles with strings (especially in a call back function)

If this doestn't work:
I had similar proplems with this in assembly, and i used to pass strings to visual basic with a trick
try to change the string parameter into two parameters, the first is a long with the address, and the
second is the length of the file, in VB you should use CopyMemory to copy them into a byte array.
Then use strConv to convert the byte array into a unicode String.
One more thing, you should pass the parameter of the CHAR, as is without conversion or any thing.
str = Strconv(StringArray, vbUnicode)

If i can help with anything please reach me at:

Best regards..
curtisnAuthor Commented:
Thanks, that was exactly the answer I was looking for, it works perfectly now.  I didn't know about the mbstowcs function!

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.