I'm really confused about passing strings from VBA to C++. Here's the VBA code:
Private Declare Sub passBSTRVal Lib "foo.dll" (ByVal s As String)
Private Declare Sub passBSTRRef Lib "foo.dll" (ByRef s As String)
Private Declare Sub passByNarrowVal Lib "foo.dll" (ByVal s As String)
Private Declare Sub passByNarrowRef Lib "foo.dll" (ByRef s As String)
Private Declare Sub passByWideVal Lib "foo.dll" (ByVal s As String)
Private Declare Sub passByWideRef Lib "foo.dll" (ByRef s As String)
Sub foobar()
Dim s As String, str As String
str = "Hello There, World!"
s = str
Call passByBSTRVal(s)
s = str
Call passByBSTRRef(s)
s = str
Call passByNarrowVal(s)
s = str
Call passByNarrowRef(s)
s = str
Call passByWideVal(s)
s = str
Call passByWideRef(s)
End Sub
And the C++ DLL code:
void __stdcall passByBSTRVal( BSTR s )
{
MessageBox(NULL, s, L"Pass BSTR by value", MB_OK | MB_ICONINFORMATION);
}
void __stdcall passByBSTRRef( BSTR *s )
{
MessageBox(NULL, *s, L"Pass BSTR by ref", MB_OK | MB_ICONINFORMATION);
}
void __stdcall passByNarrowVal( LPCSTR s )
{
USES_CONVERSION;
MessageBox(NULL, A2W(s), L"Pass by Narrow Val", MB_OK | MB_ICONINFORMATION);
}
void __stdcall passByNarrowRef( LPCSTR* s )
{
USES_CONVERSION;
MessageBox(NULL, A2W(*s), L"Pass by Narrow Ref", MB_OK | MB_ICONINFORMATION);
}
void __stdcall passByWideVal( LPCWSTR s )
{
MessageBox(NULL, s, L"Pass by Wide Val", MB_OK | MB_ICONINFORMATION);
}
void __stdcall passByWideRef( LPCWSTR* s )
{
MessageBox(NULL, *s, L"Pass by Wide Ref", MB_OK | MB_ICONINFORMATION);
}
My expectation was that the first two calls to passByBSTRVal and passByBSTRRef would work. Why? Because VBA strings are COM BSTR objects. However, while stepping through the C++ code, the value of s for both of these functions was garbage (a bunch of kanji). Additionally, the displayed message box was (the same). I'm really surprised the first two functions didn't work.
My next expectation was for the second two calls to passByNarrowVal and passByNarrowRef to not work because a BSTR is defined as "typedef OLECHAR *BSTR", and an OLECHAR is a wide character type, while LPCSTR is a narrow character type. However, contrary to my expectation, these two functions actually did work. When I stepped through the C++ code, the parameter s was exactly what i was expecting it to be. My expectation was wrong again.
Lastly, my expectation for the final 2 functions (pass by wide val and ref) was that they would work, since an OLECHAR is a string of wide characters, so a LPCWSTR should be able to point to a BSTR. But as with case #1 (I guess these two cases are identical) my expectation was wrong. The parameter s was made up of garbage characters (and the MessageBox displayed the same garbage characters.)
Why was my intuition completely wrong? Can someone please explain what I'm not understanding here?