=================================
4:  Passaggio e restituzione di stringhe
=================================

Le stringhe a lunghezza variabile vengono mantenute all'interno di Visual Basic
come BSTR. Nei file di intestazione OLE, i BSTR vengono definiti come
OLECHAR FAR *. Un OLECHAR corrisponde ad un carattere UNICODE
nell'OLE a 32 bit e ad un carattere ANSI nell'OLE a 16 bit. Un BSTR può
contenere valori NULL, in quanto nel BSTR viene mantenuto, tra gli altri,
un'attributo che specifica la lunghezza della variabile. I BSTR contengono
un valore NULL come valore terminale e possono pertanto essere trattati
come LPSTR. L'attributo relativo alla lunghezza viene attualmente
memorizzato nella posizione che precede immediatamente la stringa.
Questa caratteristica, tuttavia, potrebbe essere modificata in futuro
in modo da consentire di accedere alla lunghezza della stringa
utilizzando le API OLE.

Il passaggio di una stringa da Visual Basic ad una DLL può essere
eseguito in due modi. È possibile passare la stringa "per valore"
(ByVal) o "per riferimento". Se si passa una stringa ByVal,
Visual Basic passa un puntatore che fa riferimento all'inizio dei dati
della stringa, ovvero passa un BSTR. Quando una stringa viene passata
per riferimento, Visual Basic passa un puntatore al puntatore
che fa riferimento ai dati della stringa, ovvero passa un BSTR *.

La seguente tabella indica quali attributi vengono passati da Visual Basic
ad una DLL durante il passaggio di una stringa.

Versione	   Per valore	Per riferimento
------------------------------------
3.0	   LPSTR	HLSTR
4.0	   BSTR         BSTR *

In Visual Basic 3.0, era possibile utilizzare le routine API di Visual Basic
per accedere ad un HLSTR e modificarlo. In Visual Basic 4.0, è necessario
utilizzare le API OLE per accedere ad un BSTR. Nella seguente tabella
vengono riportate le API per la gestione delle stringhe in Visual Basic
3.0 e gli equilvalenti OLE.


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

NOTA: Il BTSR è un puntatore che fa riferimento alla stringa,
pertanto non è necessario eliminare i riferimenti contenuti in tale puntatore.


Esempio per le versioni a 16\32 bit
-----------------

La prima funzione considerata in questo esempio accetta una stringa
Visual Basic per riferimento e restituisce una copia a lettere maiuscole
di tale stringa. La seconda funzione accetta una stringa Visual Basic per
valore e restituisce, analogamente, una copia a lettere maiuscole di tale
stringa. Queste funzioni sono dunque simili alla funzione UCase di
Visual Basic. In entrambi i casi, la funzione della DLL modifica la stringa
passata, che viene quindi restituita a VB. Ciò accade inoltre quando la
stringa di VB viene passata "ByVal", in quanto alla funzione DLL viene
passato un BSTR che corrisponde ad un char far *. Sarà pertanto possibile
accedere direttamente al buffer della memoria a cui punta il BTSR.


#include <windows.h>
#include <ole2.h>

#ifdef _WIN32
  #define CCONV _stdcall
  #define NOMANGLE
#else
  #define CCONV FAR PASCAL _export
  #define NOMANGLE EXTERN_C
  #include <stdlib.h>
  #include <compobj.h>
  #include <dispatch.h>
  #include <variant.h>
  #include <olenls.h>
#endif

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

    #if !defined(_WIN32)
	cbOriginalLen = SysStringLen(*pbstrOriginal);
    #else
    	cbOriginalLen = SysStringByteLen(*pbstrOriginal);
    #endif

    bstrUpperCase = SysAllocStringLen(NULL, cbOriginalLen);

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

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

    SysReAllocString (pbstrOriginal, (BSTR)"Arrivederci");

    return bstrUpperCase;
}

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

    #if !defined(_WIN32)
	cbOriginalLen = SysStringLen(bstrOriginal);
    #else
    	cbOriginalLen = SysStringByteLen(bstrOriginal);
    #endif

    bstrUpperCase = SysAllocStringLen(NULL, cbOriginalLen);

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

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

    SysReAllocString (&bstrOriginal, (BSTR)"Arrivederci");

    return bstrUpperCase;
}


Il seguente codice Visual Basic richiama le due funzioni UpperCase illustrate
in precedenza:


#If Win32 Then

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

#Else

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

#End If


Private Sub StringTest ()

	Dim Str As String, NewStr As String

	Str = "Salve gente!"
	MsgBox "In VB, Prima: " & Str
	NewStr = UpperCaseByRef(Str)
	MsgBox "In VB, Dopo: " & Str
	MsgBox "In VB, StrMaiuscola: " & NewStr

	Str = "Salve gente!"
	MsgBox "In VB, Prima: " & Str
	NewStr = UpperCaseByVal(Str)
	MsgBox "In VB, Dopo: " & Str
	MsgBox "In VB, StrMaiuscola: " & NewStr

End Sub
