Solved

Passing strings between VB & C++

Posted on 1998-11-15
6
613 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
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Window placement 17 66
DIR issue 7 48
VB error "Type mismatch" 2 43
Updates not working for MS Windows 7 12 128
Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
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…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

743 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

16 Experts available now in Live!

Get 1:1 Help Now