23

How can I pass a char * from C dll to VB

Here is sample code:

void Cfunc(char *buffer,int len)
{
  BSTR buf_bstr = SysAllocString((BSTR)buffer);
  VBptr.VBfunc(buf_bstr,len);
}

This function is not working, In actual some other values are sent to the VB rather than the actual value.

Could anyone please suggest a solution?

  • Can you give an example of an original string vs. the wrong value that is being sent? – Aidan Ryan Mar 03 '09 at 11:51
  • Your (original) problem seems to be character width. A BSTR is always wide characters (COM is all Unicode). A cast will not automatically widen the characters, but interpret the bytes as wchar_t*. – Richard Mar 03 '09 at 11:55
  • This pseudocode features a memory leak. You call SysAllocString(), but don't deallocate the string after you no longer need it. – sharptooth Mar 03 '09 at 12:11
  • For what it's worth, a very good rule of thumb is that if you have to cast something to make it work - as is the case here where you are casting the char* buffer to BSTR - then you're probably doing it wrong and should be looking for some other conversion instead. Legitimate uses of casts tend to be fairly rare, so it's a good idea to treat casts with suspicion. – BrendanMcK May 03 '12 at 20:52

5 Answers5

24

Use _bstr_t:

_bstr_t bstrt(buffer);

Here is the holy grail of string conversion articles

Aidan Ryan
  • 11,389
  • 13
  • 54
  • 86
22

Call MultiByteToWideChar(), then either SysAllocString() or SysAllocStringLen().

Don't forget to call SysFreeString() when you no longer need the BSTR.

In detail (SysAllocStringLen() variant – it's shorter and faster):

  1. Call MultiByteToWideChar() and pass 0 as fifth and sixth parameters. It will return the number of characters in the Unicode equivalent of the ANSI string. Remember, ANSI string can contain whatever characters, not only ASCII, so any attempts to manually calculate the number of Unicode characters given the ANSI string length may work in some cases and not work in others.

  2. Allocate a buffer for the BSTR with SysAllocStringLen(). Pass 0 as the first parameter and the number of Unicode characters as the second parameter. You now have a properly allocated but uninitialized BSTR. It already has place for the trailing zero and this trailing zero is properly placed.

  3. Call MultiByteToWideChar() second time and this time pass the allocated BSTR there. The function will convert the string into Unicode and copy the result into the BSTR. Now you have a propely allocated BSTR containing the Unicode equivalent of your ANSI string.

  4. Pass the BSTR into VB. Enjoy.

  5. Call SysFreeString() to deallocate the BSTR.

TAbdiukov
  • 1,185
  • 3
  • 12
  • 25
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Still my code is not working, i have modified like this. void Cfunc(char *buffer,int len) { BSTR buf_bstr; ULONG cCharacters; if (0 == MultiByteToWideChar(0, 0, buffer, cCharacters, buf_bstr, cCharacters)); VBptr.VBfunc(buf_bstr,len); } VB Exe is crashed. –  Mar 03 '09 at 12:47
  • Hi Sharptooth.. i am new to this COM :( –  Mar 03 '09 at 12:51
14

This is the code I wrote using sharptooths answer

    int wslen = MultiByteToWideChar(CP_ACP, 0, str, strlen(str), 0, 0);
    BSTR bstr = SysAllocStringLen(0, wslen);
    MultiByteToWideChar(CP_ACP, 0, str, strlen(str), bstr, wslen);
    // Use bstr here
    SysFreeString(bstr);

Note that using -1 for the length of the string results in the null terminator being included in the result

Community
  • 1
  • 1
David Sykes
  • 48,469
  • 17
  • 71
  • 80
2

I don't have any objection to ajryan's answer, but here's an alternative...

SysAllocString is defined to take a parameter of type OLECHAR *. You're giving it a char *. These are not the same thing. There are certain circumstances when they might be the same thing, but you can't depend on it. So first of all you need to convert your char * into an OLECHAR *. There is a macro called A2OLE that can do this for you, and in those cases where char * and OLECHAR * are the same thing, the macro compiles away to nothing (I think).

See this page for details of A2OLE and its friends.

Oh, and casting your char * to a BSTR doesn't actually change it at all, it is neither a BSTR nor an OLECHAR *.

Martin
  • 5,392
  • 30
  • 39
  • Btw, casting a WCHAR* to BSTR is a bad idea too if the string has not been allocated with one of SysAllocString() family functions. Doing so may cause a crash if the call you pass such pseudo-BSTR calls SysStringLen() on it. – sharptooth Mar 03 '09 at 16:04
1

instead of char* array,try _tchar* array.Because Sysallocstring takes only the Unicode characters in a 32 bit application.

Raams
  • 167
  • 1
  • 7