BSTR to char* Help!

A

Ai

Hi all,

I'm trying to convert a BSTR string pass from VBA to a xll/dll but
without success. I tried the following:

1. WideCharToMultiByte (result is ????, if I replace the bstr with a
hardcoded string say with *bstr = SysAllocString(L"this is BSTR!!!"),
it'll work)

DWORD len, bstrLength;

bstrLength = SysStringLen(*bstr);

len = WideCharToMultiByte(CP_ACP, 0, *bstr, bstrLength, 0, 0, 0, 0);

size_t result;

if(len > 0)
{
result = WideCharToMultiByte(CP_ACP, 0, *bstr, bstrLength, buffer,
len, 0, 0);
buffer[len] = 0;//null-terminated char
}

2. wcstombs (result is empty string)

int len = wcslen(*bstr);
char *dest = (char*)malloc(len);
size_t result = wcstombs(dest, (wchar_t*)bstr, len);

3. Direct casting work but it'll crash the program later

strcat(buffer, (char*)(*bstr));

Anyone have any advise?
 
A

Akihito Yamashiro

Hi.

It depends on how you're passing the VBA string to C++.
Could you write your API declaration here?
 
A

Ai

Hi.

It depends on how you're passing the VBA string to C++.
Could you write your API declaration here?

In my xll/dll:

char* test(BSTR *bstr) {
...
return "ok";
}

BSTR is from WTypes.h

And in my VBA:

Private Declare Function test Lib "test.xll" (message As String) As
String

Public Function MyTest()
{
Dim msg As String
...
MyTest = test(msg);
}

Any idea?
 
L

Lynn McGuire

I'm trying to convert a BSTR string pass from VBA to a xll/dll but
without success. I tried the following:

Did you try the method _bstr_t (Variant bstrVal);

Lynn
 
A

Akihito Yamashiro

There're 2 problems.
a) The dll does not receive a UNICODE buffer pointer.
It receives an ANSI buffer pointer.
This is why 1) and 2) do not work correctly but 3) works.
Using 'As String' causes VBA to automatically UNICODE->ANSI
conversion.
To solve the problem , there're 2ways.
a1) Do not use 'As String' , use 'ByVal ... As Long' instead.
And pass the variable pointer with varptr undocumented
function.
a2) Stop converting UNICODE->ANSI . Let VBA do that.
b) Maybe, VBA recognises the return value as BSTR not char*.
So VBA tries to SysFreeString the char* pointer incorrectly.
This is why 3) crashes.

I have no time now , I'm sorry I cannot send a sample code here.
 
A

Akihito Yamashiro

Here's a smple.
In C++

extern "C" void WINAPI TEST(BSTR* bstr)
{
DWORD len, bstrLength;

// +1 for NULL teminator
bstrLength = SysStringLen(*bstr)+1;

len = WideCharToMultiByte(CP_ACP, 0, *bstr, bstrLength, 0, 0, 0,
0);
size_t result;

if(len > 0)
{
char* buffer = new char[len];
result = WideCharToMultiByte(CP_ACP, 0, *bstr, bstrLength,
buffer,len, 0, 0);
MessageBoxA(NULL, buffer , "MultiByte",0);
delete buffer;
}

};

In VBA

Private Declare Sub TEST Lib "C:\BSTRTEST.dll" (ByVal strIn As Long)
Sub TESTPROC()
Dim s As String
s = "abc"
TEST VarPtr(s)
End Sub

To pass a UNCODE string from C++ to VBA
In VC

extern "C" void WINAPI TEST1(BSTR* strIn, BSTR* strOut)
{
//in: UNICODE , out: UNCODE
wchar_t* conststr = L"abc";
BSTR rt = SysAllocStringLen(NULL, SysStringLen(*strIn) + 3);
wcscat(rt,conststr);
wcscat(rt,*strIn);
if(*strOut !=NULL)
{
SysFreeString(*strOut);
}
*strOut = rt;
};


In VBA

Private Declare Sub TEST1 Lib "C:\BSTRTEST.dll" (ByVal s As Long,
ByVal s2 As Long)
Sub main()
Dim s1 As String
s1 = "aaa"
Dim s2 As String
TEST1 VarPtr(s1), VarPtr(s2)
Debug.Print s2
End Sub

By the way, the problem b) I wrote in the previous post is wrong.
The truth may be , you cannot pass the char* which is allocated in c++
from c++ to VB, since nobody can delete the allocated space and causes
memory leak.
 

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