Я действительно запутался в передаче строк из VBA на С++. Здесь код VBA:
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
И код DLL С++:
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);
}
Я ожидал, что первые два вызова passByBSTRVal и passByBSTRRef будут работать. Зачем? Поскольку строки VBA являются объектами COM BSTR. Однако, переходя через код С++, значение s для обеих этих функций было мусором (кучей кандзи). Кроме того, отображаемое окно сообщения (то же самое). Я действительно удивлен, что первые две функции не работают.
Мое следующее ожидание было для вторых двух вызовов passByNarrowVal и passByNarrowRef, чтобы они не работали, потому что BSTR определяется как "typedef OLECHAR * BSTR", а OLECHAR - это широкий тип символов, а LPCSTR - узкий характер. Однако, вопреки моему ожиданиям, эти две функции действительно работали. Когда я перешагнул код С++, параметр s был именно тем, чего я ожидал. Мое ожидание снова было неправильным.
Наконец, мое ожидание последних двух функций (pass by wide val и ref) состояло в том, что они будут работать, поскольку OLECHAR - это строка с широкими символами, поэтому LPCWSTR должен иметь возможность указывать на BSTR. Но как с случаем № 1 (я думаю, эти два случая идентичны), мое ожидание было неправильным. Параметр s состоял из символов мусора (и MessageBox отображал одни и те же символы мусора).
Почему моя интуиция совершенно неправа? Может кто-нибудь объяснить, что я здесь не понимаю?