I've written some code in C for converting strings passed from VBA, when the C code is called from VBA from a MacOSX dylib. I got some good hints here, and since I only care about ASCII strings I've written the following functions to convert the BSTR
to a simple char*
:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "myheader.h"
size_t vbstrlen(BSTR *vbstr)
{
size_t len = 0U;
while(*(vbstr++)) ++len;
len = len*2;
return len;
}
void vbstochr(BSTR *vbstr, char** out)
{
int len2 = vbstrlen(vbstr);
char str[len+1];
int i;
for(i = 0; i < len; i++)
{
str[i] = (char) (((uint16_t*) vbstr)[i]);
}
str[i] = '\0';
asprintf(out, str);
}
int test(BSTR *arg1)
{
char* convarg;
vbstochr(arg1, &convarg);
return 1;
}
The myheader.h looks like this:
typedef uint16_t OLECHAR;
typedef OLECHAR * BSTR;
. I used uint16_t
because of the 4 byte (not 2 byte) wchar_t in the MacOSX C compiler. I added a breakpoint after vbstochar
is called to look at the content of convarg
, and it seems to work when called from Excel.
So this works, but one thing I don't understand is why I have to multiply my len
in the vbstrlen
function by 2. I'm new to C, so I had to read up on pointers a little bit - and I thought since my BSTR contains 2 byte characters, I should get the right string length without having to multiply by two? It would be great if someone could explain this to me, or post a link to a tutorial?
Also, my functions with string arguments work when called in VBA, but only after the first call. So when I call a function with a BSTR*
argument from a dylib for the first time (after I start the application, Excel in this case), the BSTR*
pointer just points at some (random?) address, but not the string. When I call the function from VBA a second time, everything works just fine - any ideas why this is the case?!