Solved

Passing strings between VB & C++

Posted on 1998-11-15
6
695 Views
Last Modified: 2008-02-26
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
Comment
Question by:cdickerson
6 Comments
 

Author Comment

by:cdickerson
ID: 1444949
Wow, I was really out of it when I posted that. Obviously, the VB app should be calling "CopyString" instead of CIWS_UdtToString.
0
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1444950
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
 

Author Comment

by:cdickerson
ID: 1444951
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
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 
LVL 2

Expert Comment

by:trillo
ID: 1444952
Try passing all VB parameters as ByVal, it worked with me when I made DLL's with Delphi
0
 
LVL 2

Accepted Solution

by:
schild earned 100 total points
ID: 1444953
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
 

Author Comment

by:cdickerson
ID: 1444954
Thanks a lot!
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
VB6 Compile Compatibility Issue 4 116
to transfer string from C lanaguage to VBA 4 72
VB 6 error 5 in windows 10 but not in XP 7 63
Formula problem with Excel attachment 6 39
I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question