Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 880
  • Last Modified:

Passing strings between VB & C++

I've created a very simple test app to pass a VB string into a C/C++ dll, copy it to another another, a pass it back to VB. The dll works fine in a C++ test app, but the VB app is always returned an empty string. Can someone tell me what looks wrong with this:

C Dll --------------------------
int CopyString(const char *sIn, int iInLen, char *sOut)
{
      int rc = 0;
      sOut = (char *)malloc(sizeof(iInLen));
      memcpy(sOut, sIn, iInLen);
      sOut = (char *)sIn;
      return rc;
}

VB App ---------------------------
Public Sub Main()
    Dim rc As Long, sResp As String
   
    rc = CIWS_UdtToString("String", Len("String"), sResp)
' sResp is always empty
End Sub
0
cdickerson
Asked:
cdickerson
1 Solution
 
cdickersonAuthor Commented:
Wow, I was really out of it when I posted that. Obviously, the VB app should be calling "CopyString" instead of CIWS_UdtToString.
0
 
MikeP090797Commented:
Try removing the line:
sOut = (char *)malloc(sizeof(iInLen));
instead, use a fixed size string, Dim S as string *256
If this doesn't help, post here the Declare, maybe something is wrong with it. Tell me how it goes
0
 
cdickersonAuthor Commented:
No, that suggestion didn't work. Here's the declare for the dll:

Public Declare Function CopyString Lib "CopyString.DLL" _
   (ByRef inStruct As Any, _
    ByVal inStructLen As Long, _
    ByVal outStruct As String) As Long

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
trilloCommented:
Try passing all VB parameters as ByVal, it worked with me when I made DLL's with Delphi
0
 
schildCommented:
this is chapter no 5 which taken from vb5dll.doc, look for this file, i think you have it on your VB5 disc and i'm wrong you can find it at Microsoft FTP site for sure:

*************************************************
=================================
5:  Passing and Returning Strings
=================================

Visual Basic maintains variable-length strings internally as BSTRs.  BSTRs  are defined in the OLE header files as OLECHAR FAR*. An OLECHAR is a UNICODE character in 32-bit OLE and an ANSI character in 16-bit OLE. A BSTR can contain NULL values because a length is also maintained with the BSTR. BSTRs are also NULL terminated so they can be treated as an LPSTR. Currently this length is stored immediately prior to the string. This may change in the future, however, so you should use the OLE APIs to access the string length. A subtle point is if you use a declare statement as opposed to a typelib in VB, the string is NOT coerced into an ANSI string.  It is left as a UNICODE string. If you use a declare statement, then the string passed is coerced into an ANSI string.  In the below example, please pay special attention to the comments.  Please refer to section 10 for more information.

You can pass a string from Visual Basic to a DLL in one of two ways. You can pass it "by value" (ByVal) or "by reference". When you pass a string ByVal, Visual Basic passes a pointer to the beginning of the string data (i.e. it passes a BSTR).  When a string is passed by reference, Visual Basic passes a pointer to a pointer to the string data (i.e. it passes a BSTR*).  Since VB coerces the UNICODE string to ANSI, it allocates temporary memory to store the ANSI string.  VB recopies the UNICODE version of the string back to the passed in variable.

The following table lists what Visual Basic will pass to a DLL function when passing a string.

Version      By Value      By Reference
------------------------------------
3.0            LPSTR            HLSTR
4.0            BSTR            BSTR*
5.0            BSTR            BSTR*

In  Visual Basic 3.0, you  could use the Visual Basic API routines to access and modify an HLSTR.  In Visual Basic 5.0 you should use the OLE APIs to access a BSTR. The following table lists the Visual Basic 3.0 string-handling APIs, and the OLE equivalents.

Visual Basic API            OLE API
--------------------------------------------------------
VBCreateHlstr            SysAllocString/SysAllocStringLen
VBCreateTempHlstr            SysAllocString/SysAllocStringLen
VBDerefHlstr*            N/A
VBDerefHlstrLen*            N/A
VBDerefZeroTermHlstr      N/A
VBDestroyHlstr            SysFreeString
VBGetHlstrLen            SysStringLen
VBResizeHlstr            SysReAllocStringLen
VBSetHlstr                  SysReAllocString

NOTE:  The  BSTR  is a  pointer  to the  string, so you don't need to
dereference it.

Example
-------

The first function in this example takes a Visual Basic string by reference, and  returns  an  uppercase copy of the string. The second function  takes a Visual Basic  string  by value and also returns an uppercase copy of the string.  This is similar to the UCase function in Visual Basic.  In both cases, the DLL function modifies the passed string, which is  reflected back in VB. This happens even when the VB string is passed "ByVal" because what is passed to the DLL function is a BSTR which is a char far*, and thus, it is possible to directly access the memory buffer pointed to by the BSTR.  The DEF file is not included.

#include <windows.h>

#define CCONV _stdcall

BSTR CCONV UpperCaseByRef(BSTR *pbstrOriginal)
{
    BSTR bstrUpperCase;
    int i;
    int cbOriginalLen;
    LPSTR strSrcByRef, strDst;

    cbOriginalLen = SysStringByteLen(*pbstrOriginal);

//We are planning to return bstrUpperCase if we are using a declare
//statement, we need to use SysAllocStringByteLen instead of SysAllocStringLen
//because of the coercion of ansi back to a unicode string on return of the
//function.  See Note #1 below.
    bstrUpperCase = SysAllocStringByteLen(NULL, cbOriginalLen);

    strSrcByRef = (LPSTR)*pbstrOriginal;
    strDst = (LPSTR)bstrUpperCase;

    for(i=0; i<=cbOriginalLen; i++)
        *strDst++ = toupper(*strSrcByRef++);

    SysReAllocString (pbstrOriginal, (BSTR)"Good Bye");

//On return of this function, bstrUpperCase will be coerced back to
//a Unicode string if we are using a declare statement instead of a
//typelib.  See Note #1 below.
    return bstrUpperCase;
}

BSTR CCONV UpperCaseByVal(BSTR bstrOriginal)
{
    BSTR bstrUpperCase;
    int i;
    int cbOriginalLen;
    LPSTR strSrcByVal, strDst;

    cbOriginalLen = SysStringByteLen(bstrOriginal);

//We are planning to return bstrUpperCase if we are using a declare
//statement, we need to use SysAllocStringByteLen instead of SysAllocStringLen
//because of the coercion of ansi back to a unicode string on return of the
//function.  See Note #1 below.
    bstrUpperCase = SysAllocStringByteLen(NULL, cbOriginalLen);

    strSrcByVal = (LPSTR)bstrOriginal;
    strDst = (LPSTR)bstrUpperCase;

    for(i=0; i<=cbOriginalLen; i++)
        *strDst++ = toupper(*strSrcByVal++);

    SysReAllocString (&bstrOriginal, (BSTR)"Good Bye");
//On return of this function, bstrUpperCase will be coerced back to
//a Unicode string if we are using a declare statement instead of a
//typelib.  See Note #1 below
    return bstrUpperCase;
}


The  following  Visual  Basic  code  calls  the  above  two UpperCase
functions:  

Private Declare Function UpperCaseByRef Lib "vb5dll32.dll" (Str _
      As String) As String
Private Declare Function UpperCaseByVal Lib "vb5dll32.dll" _
      (ByVal Str As String) As String

Private Sub StringTest ()

      Dim Str As String, NewStr As String

      Str = "Hello World!"
      MsgBox "In VB, Before: " & Str
      NewStr = UpperCaseByRef(Str)
      MsgBox "In VB, After: " & Str
      MsgBox "In VB, CapsStr: " & NewStr
   
      Str = "Hello World!"
      MsgBox "In VB, Before: " & Str
      NewStr = UpperCaseByVal(Str)
      MsgBox "In VB, After: " & Str
      MsgBox "In VB, CapsStr: " & NewStr

End Sub

Note #1:  As an example, if we pass in the string abs and we used SysAllocStringLen, then it would allocate a string of length 6.  On return of the function, it will coerce the string into Unicode also changing the prefixed length of the BSTR to 12 which is double the amount, therefore we would get a larger string and potential garbage characters.  By using SysAllocStringByteLen, it allocates a string of length 3.  On return, it coerces the ANSI string back to Unicode string of the proper length 6.

**************************
Good Luck
Schild
0
 
cdickersonAuthor Commented:
Thanks a lot!
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now