Page 1 of 2
Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 7:47 am
by franchsesko
Hi,
Using the SysAllocString() api, we can return a pointer to a BSTR that VBA (32 and 64 bits)
almost understands as one of its strings.
PB DLL sample:
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
ProcedureDLL.i GetVersion()
ProcedureReturn SysAllocString_("This is Version " + #APP_VERSION)
EndProcedure
VBA Calling code in a module (here an Access one):
Code: Select all
Option Compare Database
Option Explicit
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Sub Main()
'Sample in Access VBA, change directory where DLL is or place DLL in PATH
Dim sVersion As String
ChDir CurrentProject.Path
sVersion = GetVersion()
Debug.Print sVersion, Asc(Mid$(sVersion, 2, 1))
Debug.Print StrConv(sVersion, vbFromUnicode)
End Sub
So "almost", because if I don't use StrConv(), each character in the string has an extra 0 (zero) after it.
That's ok with me, but my worry is that the BSTR allocated and returned by SysAllocString(), if not freed by VBA, could cause a difficult to spot memory leak.
Do you know if that is the case or if VBA does the necessary disposal in all cases ?
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 8:04 am
by Kwai chang caine
Hello franchsesko and welcome in the paradise of PureBasic
Do you know COMATEPLUS of the great SROD, for all the thing to do with the OLE and COM ?
viewtopic.php?f=14&t=37214&hilit=comateplus
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 8:12 am
by franchsesko
Hi kwai,
Thanks for jumping into this topic.
Actually yes, I've seen COMate, great work indeed, but I left it aside as I'm writing a non COM Dll (although I rudely borrow SysAllocString() from it).
I'll dig into it, but if you can point me where you know there's some code that can help me, it may save me some headache.
All the best.
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 9:19 am
by Kwai chang caine
Apparently, when i see your last code in the other section, i'm not a big master like you
But me too, one of my interest there is a long time, is talking between PB and VB6
And the great Masters SROD, TSSOFT, KIFFY, MKSOFT (COM specialists) and RENDFIELD (VBFRANCE Moderator) help me numerous time for do that, because CROSOFT have really the talent for complicating the simple things (BSTR, SafeArray, etc ..)
I don't remember if all works, but i have some codes of this period, perhaps one of him help you

This is one
Code: Select all
; http://www.purebasic.fr/english/viewtopic.php?p=295292#p295292
; Edwin Knoppert
ProcedureDLL GetDirectString2()
ProcedureReturn SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20)
EndProcedure
; http://www.purebasic.fr/english/viewtopic.php?p=295295#p295295
; Edwin Knoppert
ProcedureDLL.I GetDirectString3()
Protected tin.s
Protected tout.s
tin = "hello world"
tout = tin + tin
tin = tin + Chr( 0)
PokeS(@tout, tin, Len( tin ), #PB_Unicode )
ProcedureReturn SysAllocString_( tout)
EndProcedure
; http://www.purebasic.fr/english/viewtopic.php?p=295974#p295974
; Edwin Knoppert
ProcedureDLL.I Test2(sText.s)
ProcedureReturn SysAllocStringByteLen_(@sText, Len(sText))
EndProcedure
Code: Select all
VERSION 5.00
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 3195
ClientLeft = 60
ClientTop = 345
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 3195
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Private Declare Function GetDirectString Lib "Envoie BSTR.dll" () As String
Private Declare Function GetDirectString2 Lib "Envoie BSTR.dll" () As String
Private Declare Function GetDirectString3 Lib "Envoie BSTR.dll" () As String
' Edwin Knoppert
Private Declare Function Test2 Lib "Envoie BSTR.dll" (ByVal sText As String) As String
Private Sub Form_Load()
ChDir App.Path
' Edwin Knoppert
MsgBox GetDirectString2
' Edwin Knoppert
MsgBox StrConv(GetDirectString3, vbFromUnicode)
' Edwin Knoppert
Test
End Sub
Sub Test()
Dim x As Long
Dim MyString As String
x = 100
For a = 0 To x
phrase = phrase + Test2("Kcc " + Str(a)) + Chr(13)
Next
MsgBox phrase
End Sub
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 9:21 am
by infratec
Hm...
BSTR SysAllocString(
_In_opt_ const OLECHAR *psz
);
And OLECHAR is wchar_t which is an UTF16 string.
So it is 'normal' that there are 0 bytes after each 'ASCII' character.
One other thing ... you need to free the memory occupied by SysAllocString_()
Bernd
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 10:02 am
by franchsesko
Thanks for the collection and the links Kwai.
I think I've got quite some lessons from the Masters here to go, before even considering myself to be an apprentice
So, basically, I'm doing it the "GetDirectString3()" way, except that I don't do the PokeS() thing as PB is now Unicode (UTF16 hopefully same as VB/A). So I guess there should be no need for that.
To verify that VB/A and PB strings are similar, I've added a function to the DLL to pass a VB/A string to PB.
I use the StrPtr() function to address the unicode character string buffer of the VB/A BSTR and it seems to work well.
That's why I don't understand why returning the string with SysAllocString() needs the extra StrConv() call and I worry for some leak in between.
Here's an updated code.
PB DLL:
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
ProcedureDLL.i GetVersion()
ProcedureReturn SysAllocString_("This is Version " + #APP_VERSION)
EndProcedure
ProcedureDLL.w GimmeAString(psString.s)
MessageRequester("Received string", "The string is :" + #CRLF$ + #CRLF$ + psString)
EndProcedure
VB/A test module:
Code: Select all
Option Compare Database
Option Explicit
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GimmeAString Lib "ReturnStringTest.dll" (ByVal psString As LongPtr) As Integer
Sub Main()
'Sample in Access VBA, change directory where DLL is or place DLL in PATH
Dim sVersion As String
ChDir CurrentProject.Path
sVersion = GetVersion()
Debug.Print sVersion, Asc(Mid$(sVersion, 2, 1))
Debug.Print StrConv(sVersion, vbFromUnicode)
Call GimmeAString(StrPtr("Hello World! here are some accents: éàûü"))
End Sub
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 10:20 am
by franchsesko
Hi bernd,
Thanks for chiming in.
And OLECHAR is wchar_t which is an UTF16 string.
So it is 'normal' that there are 0 bytes after each 'ASCII' character.
I agree with that.
One other thing ... you need to free the memory occupied by SysAllocString_()
That is what I fear.
When I return the (SysAllocString()) string from my PB routine, I loose its pointer.
And VB/A receives it as a (BSTR) string (as declared as the return type of the DLL function GetVersion()), so it would be quite inconvenient, if I were to change the return type to Long (or LongPtr). Then I would have to find a way to copy the string from the pointer to a VB variable and then free it, and I would like to avoid that.
So I'm counting on VB/A to free the string once the variable holding it goes out of scope, or when StrConv() creates one from the received one, as it would do for any other of its own string variables.
And it is this assumption that leaves me uneasy.
Of course I'm trying to avoid having to refactor my PB functions to receive a buffer into which I can copy the string, although I may end up just doing that to avoid any problem at all.
All the best.
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 10:53 am
by franchsesko
Just to follow up on my last resort technique, here's a version where I return a string with a more traditional buffer/copy technique (GetVersionLength/GetVersionV2).
Although there's a Unicode/Ascii(PB)/Unicode(VB/A) conversion in the process, so some potential loss.
PB DLL:
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
ProcedureDLL.i GetVersion()
ProcedureReturn SysAllocString_("This is Version " + #APP_VERSION)
EndProcedure
ProcedureDLL.w GimmeAString(psString.s)
MessageRequester("Received string", "The string is :" + #CRLF$ + #CRLF$ + psString)
EndProcedure
ProcedureDLL.w GetVersionLength()
ProcedureReturn Len("This is Version " + #APP_VERSION)
EndProcedure
ProcedureDLL.w GetVersionV2(*psBuffer)
Protected.s sVersion
sVersion = "This is Version " + #APP_VERSION
PokeS(*psBuffer, sVersion, Len(sVersion), #PB_Ascii)
EndProcedure
VB/A:
Code: Select all
Option Compare Database
Option Explicit
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GimmeAString Lib "ReturnStringTest.dll" (ByVal psString As LongPtr) As Integer
Private Declare PtrSafe Function GetVersionLength Lib "ReturnStringTest.dll" () As Integer
Private Declare PtrSafe Function GetVersionV2 Lib "ReturnStringTest.dll" (ByVal lpBuffer As LongPtr) As Integer
Sub Main()
'Sample in Access VBA, change directory where DLL is or place DLL in PATH
Dim sVersion As String
ChDir CurrentProject.Path
sVersion = GetVersion()
Debug.Print sVersion, Asc(Mid$(sVersion, 2, 1))
Debug.Print StrConv(sVersion, vbFromUnicode)
'Call GimmeAString(StrPtr("Hello World! here are some accents: éàûü"))
Debug.Print "Version length is: "; GetVersionLength()
ReDim abBuffer(1 To GetVersionLength() + 1) As Byte
GetVersionV2 VarPtr(abBuffer(1))
Debug.Print "Version 2: >"; StrConv(abBuffer(), vbUnicode); "<" 'gets the final \0 to strip off
End Sub
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 4:32 pm
by mk-soft
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
Threaded *strGetVersion
ProcedureDLL.i GetVersion()
If *strGetVersion
SysFreeString_(*strGetVersion)
EndIf
*strGetVersion = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn *strGetVersion
EndProcedure
ProcedureDLL.i GetVersionVariant(*text.variant) ; <- parameter text Byref of type variant
If *text
VariantClear_(*text)
*text\vt = #VT_BSTR
*text\bstrVal = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Not testet... Edit
Declare Unicode Function GetVersion Lib "ReturnStringTest.dll" () As String
Declare Unicode Function GetVersionVariant Lib "ReturnStringTest.dll" (Byref Text As Object) As Long
Dim Version as Object
GetVersionVariant(Version)
P.S.
DLL as Unicode...
Re: Returning Strings to VBA - Is this the right way ?
Posted: Mon Jun 11, 2018 11:04 pm
by franchsesko
Hi mk-soft,
Woaw, that is great.
I love the second one that can alter a variant passed by reference (no need to maintain pointers in the library, no need for conversion).
Also wouldn't have thought using "Thread(ed)" variables until now too.
Anyway, here's the updated and tested code (need to use a variant byref or Access crashes):
I've learned a lot today, and as for our other fellows here, thank you too for adding so much value to this conversation.
PB DLL:
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
Threaded *strGetVersion
ProcedureDLL.i GetVersion()
If *strGetVersion
SysFreeString_(*strGetVersion)
EndIf
*strGetVersion = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn *strGetVersion
EndProcedure
ProcedureDLL.i GetVersionVariant(*text.variant) ; <- parameter text Byref of type variant
If *text
VariantClear_(*text)
*text\vt = #VT_BSTR
*text\bstrVal = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Access VB/A module:
Code: Select all
Option Compare Database
Option Explicit
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "ReturnStringTest.dll" (ByRef Text As Variant) As Long
Sub Main()
'Sample in Access VBA, change directory where DLL is or place DLL in PATH
Dim sVersion As String
ChDir CurrentProject.Path
sVersion = GetVersion()
Debug.Print sVersion, Asc(Mid$(sVersion, 2, 1))
Debug.Print StrConv(sVersion, vbFromUnicode)
Dim Version As Variant 'Object = crash
Call GetVersionVariant(Version)
Debug.Print Version
End Sub
Re: Returning Strings to VBA - Is this the right way ?
Posted: Tue Jun 12, 2018 9:30 am
by mk-soft
With VBA, the parameter ByRef is not as it should be.
A copy of the variable is passed. This means that you cannot use them as a return value.
But I found a solution via pointers.
DLL as usual...
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Sub Schaltfläche1_Klicken()
Dim text As Variant
GetVersionVariant (VarPtr(text))
MsgBox text
End Sub
Testing with Excel 2010
Re: Returning Strings to VBA - Is this the right way ?
Posted: Tue Jun 12, 2018 10:38 am
by mk-soft
Array as Result
Code: Select all
EnableExplicit
DisableDebugger
; ***************************************************************************************
; Part of Variant helper
;- Structure SAFEARRAY
CompilerIf Defined(SAFEARRAYBOUND, #PB_Structure) = 0
Structure SAFEARRAYBOUND
cElements.l
lLbound.l
EndStructure
CompilerEndIf
CompilerIf Defined(pData, #PB_Structure) = 0
Structure pData
StructureUnion
llVal.q[0]
lVal.l[0]
bVal.b[0]
iVal.w[0]
fltVal.f[0]
dblVal.d[0]
boolVal.w[0]
bool.w[0]
scode.l[0]
cyVal.l[0]
date.d[0]
bstrVal.i[0]
varVal.VARIANT[0] ; Added ?
Value.VARIANT[0] ; Added ?
*punkVal.IUnknown[0]
*pdispVal.IDispatch[0]
*parray[0]
*pbVal.BYTE[0]
*piVal.WORD[0]
*plVal.LONG[0]
*pllVal.QUAD[0]
*pfltVal.FLOAT[0]
*pdblVal.DOUBLE[0]
*pboolVal.LONG[0]
*pbool.LONG[0]
*pscode.LONG[0]
*pcyVal.LONG[0]
*pdate.DOUBLE[0]
*pbstrVal.INTEGER[0]
*ppunkVal.INTEGER[0]
*ppdispVal.INTEGER[0]
*pparray.INTEGER[0]
*pvarVal.VARIANT[0]
*byref[0]
cVal.b[0]
uiVal.w[0]
ulVal.l[0]
ullVal.q[0]
intVal.l[0]
uintVal.l[0]
*pdecVal.LONG[0]
*pcVal.BYTE[0]
*puiVal.WORD[0]
*pulVal.LONG[0]
*pullVal.QUAD[0]
*pintVal.LONG[0]
*puintVal.LONG[0]
decVal.l[0]
brecord.VARIANT_BRECORD[0]
EndStructureUnion
EndStructure
CompilerEndIf
CompilerIf Defined(SAFEARRAY, #PB_Structure) = 0
Structure SAFEARRAY
cDims.w
fFeatures.w
cbElements.l
cLocks.l
*pvData.pData
rgsabound.SAFEARRAYBOUND[0]
EndStructure
CompilerEndIf
; ***************************************************************************************
Procedure saCreateSafeArray(vartype, Lbound, Elements)
Protected rgsabound.SAFEARRAYBOUND, *psa
rgsabound\lLbound = Lbound
rgsabound\cElements = Elements
*psa = SafeArrayCreate_(vartype, 1, rgsabound)
If *psa
ProcedureReturn *psa
Else
ProcedureReturn 0
EndIf
EndProcedure
; ***************************************************************************************
#APP_VERSION = "1.0.0"
Threaded *strGetVersion
ProcedureDLL.i GetVersion()
If *strGetVersion
SysFreeString_(*strGetVersion)
EndIf
*strGetVersion = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn *strGetVersion
EndProcedure
ProcedureDLL.i GetVersionVariant(*text.variant) ; <- parameter text Byref of type variant
If *text
VariantClear_(*text)
*text\vt = #VT_BSTR
*text\bstrVal = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
ProcedureDLL.i GetVersionsInfo(*info.variant)
Protected *psa.SAFEARRAY
VariantClear_(*info)
*psa = saCreateSafeArray(#VT_VARIANT, 10, 5)
If *psa
*psa\pvData\varVal[0]\vt = #VT_BSTR
*psa\pvData\varVal[0]\bstrVal = SysAllocString_("Version 1.0.0.1")
*psa\pvData\varVal[1]\vt = #VT_BSTR
*psa\pvData\varVal[1]\bstrVal = SysAllocString_("Copyright by mk-soft")
*psa\pvData\varVal[2]\vt = #VT_I4
*psa\pvData\varVal[2]\lVal = 1001
*psa\pvData\varVal[3]\vt = #VT_R4
*psa\pvData\varVal[3]\fltVal = 2.01
*psa\pvData\varVal[4]\vt = #VT_BSTR
*psa\pvData\varVal[4]\bstrVal = SysAllocString_("I Like Purebasic!")
*info\vt = #VT_ARRAY | #VT_VARIANT
*info\parray = *psa
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
VBA
Private Declare PtrSafe Function GetVersion Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Private Declare PtrSafe Function GetVersionsInfo Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Sub Schaltfläche1_Klicken()
Dim text As Variant
GetVersionVariant (VarPtr(text))
MsgBox text
End Sub
Sub Schaltfläche2_Klicken()
Dim info As Variant
Dim text
text = ""
GetVersionsInfo (VarPtr(info))
If IsArray(info) Then
For i = LBound(info) To UBound(info)
text = text & "" & i & ": " & info(i) & vbNewLine
Next
Else
text = "Info is not an array"
End If
MsgBox text
End Sub
Re: Returning Strings to VBA - Is this the right way ?
Posted: Tue Jun 12, 2018 1:39 pm
by franchsesko
@mksoft,
I'll take the Array example as another cool Bonus, thanks
I think you got a problem with the ByRef variant because of extra parenthesis.
You have:
Code: Select all
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Sub Schaltfläche1_Klicken()
Dim text As Variant
GetVersionVariant (VarPtr(text))
MsgBox text
End Sub
As GetVersionVariant is a function to VB/A, you should call it either of these two ways:
Code: Select all
GetVersionVariant VarPtr(text)
or:
Call GetVersionVariant(VarPtr(text))
The extra parenthesis around the VarPtr() call forces VB/A to create the temporary variable (which will hold the result of VarPtr) and then pass the address of this temporary var (PB assuming it's a pointer to a Variant will probably crash the calling app).
The first form is like calling a Sub and the second form forces VB/A to interpret the outer parenthesis as the beginning of function arguments.
Cheers.
Re: Returning Strings to VBA - Is this the right way ?
Posted: Tue Jun 12, 2018 2:20 pm
by mk-soft
It does not matter whether the pointer is passed temporarily or via variable.
It is only important that the variable of type Variant was created.
Dim Text as Variant
If this variable is not created, it leads to a crash.
The cleaning up of the variable 'text' is done automatically by VB.
A function can also be called as a sub. The return value is then ignored by the DLL.
Perhaps is this better...
Private Declare PtrSafe Function GetVersion Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Private Declare PtrSafe Function GetVersionsInfo Lib "D:\Daten\Purebasic5\Ablage\ReturnStringTest.dll" (ByVal pVariant As LongPtr) As Long
Sub Schaltfläche1_Klicken()
Dim text As Variant
Dim pVariant As LongPtr
pVariant = VarPtr(text)
If GetVersionVariant(pVariant) Then
MsgBox text
Else
MsgBox "No result"
End If
End Sub
Sub Schaltfläche2_Klicken()
Dim info As Variant
Dim text
text = ""
If GetVersionsInfo(VarPtr(info)) Then
If IsArray(info) Then
For i = LBound(info) To UBound(info)
text = text & "" & i & ": " & info(i) & vbNewLine
Next
Else
text = "Info is not an array"
End If
Else
text = "DLL can´t allocate SafeArray"
End If
MsgBox text
End Sub
P.S.
I am already very familiar with the variable type variant.
The type variant is always 16 bytes and with the function VarPtr the pointer to this memory area is passed to the DLL.
Re: Returning Strings to VBA - Is this the right way ?
Posted: Tue Jun 12, 2018 2:59 pm
by franchsesko
If this variable is not created, it leads to a crash.
I agree.
A function can also be called as a sub. The return value is then ignored by the DLL.
Agreed too (although it's VB/A ignoring the return code).
The cleaning up of the variable 'text' is done automatically by VB.
That is what I was looking for to know.
I am already very familiar with the variable type variant.
I don't doubt that for a second
I've tested both forms of declaration for the parameter (Byref Variant and Byval LongPtr).
I modified the DLL to show the passed pointer value.
So, both declaration will point to the same memory address, then there's no need to have an extra LongPtr (pVariant in your sample) that carries the VarPtr() for us.
You've got no temporary problem with your extra parenthesis because you pass the argument Byval (see GetVersionVar2() down here).
So there's still an extra temporary variable that is created by VB at call time. It takes the address returned by VarPtr(), but as it's then passed byval the same and correct target Variant address is finally used in the DLL.
Tested in Access and Excel (both 2016).
PB:
Code: Select all
EnableExplicit
DisableDebugger
#APP_VERSION = "1.0.0"
Threaded *strGetVersion
ProcedureDLL.i GetVersion()
If *strGetVersion
SysFreeString_(*strGetVersion)
EndIf
*strGetVersion = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn *strGetVersion
EndProcedure
ProcedureDLL.i GetVersionVariant(*text.variant) ; <- parameter text Byref of type variant
If *text
MessageRequester("GetVersionVariant in DLL", "Variant address="+Hex(*text))
VariantClear_(*text)
*text\vt = #VT_BSTR
*text\bstrVal = SysAllocString_("This is Version " + #APP_VERSION)
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
VB/A:
Code: Select all
Private Declare PtrSafe Function GetVersion Lib "ReturnStringTest.dll" () As String
Private Declare PtrSafe Function GetVersionVariant Lib "ReturnStringTest.dll" (ByRef text As Variant) As Long
Private Declare PtrSafe Function GetVersionVariant2 Lib "ReturnStringTest.dll" _
Alias "GetVersionVariant" (ByVal pVariant As LongPtr) As Long
Sub Main()
'Sample in Access VBA, change directory where DLL is or place DLL in PATH
Dim sVersion As String
ChDir CurrentProject.Path 'Access only, full dll path or dll in PATH for Excel
Dim text As Variant
Dim pVariant As LongPtr
pVariant = VarPtr(text)
Debug.Print "VarPtr(text)="; Hex$(pVariant)
Call GetVersionVariant(text)
Debug.Print text
Call GetVersionVariant2(pVariant)
Debug.Print text
'NO temporary var problem with byval
GetVersionVariant2 VarPtr(text) 'OK
GetVersionVariant2 (VarPtr(text)) 'OK too, same address, but hidden temp var
End Sub