Solved

Passing strings between VB & C++

Posted on 1998-11-15
6
643 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Macro: print each sheet to pdf using ExportAsFixedFormat 11 40
vb6 connector to SQL Server 2 34
Copy a row 12 57
VBA Shell can't Find Word document 11 75
Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

911 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

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now