Page 2 of 3
Posted: Wed Aug 12, 2009 11:26 pm
by mk-soft
However, i am not going further discussion this specific code.
But read, what is a object by vb.net or variant by vb6.
Posted: Thu Aug 13, 2009 8:41 am
by Edwin Knoppert
That's a point for you yes.
If you want to make a compatible function you may indeed want to go the variant way.
But to make it compatible i suspect you *need* to create an unicode BSTR all the time.
In VB you simply use a variant to obtain the string and move it to a string variable.
But VB may not like it as return value and maybe you'll need to pass a variant byref to be set (maybe you did already).
Posted: Thu Aug 13, 2009 11:14 am
by mk-soft
Ok,
for varianttype vt_bstr using allways "SysAllocString_(...). If successful, returns a BSTR containing the string.
If I give the string directly back, I use the structure vbString. The text memory is then statically in the DLL and that vb the compiler reads and converts this then depending upon declaration. Functioned also perfectly. Is not however because of static text threadsafe.
With vb.net object good method is also array out to exchange. then one must be occupied however still with safearray.
(Sorry, some translated with babelfish)
Modify code now with mutex
Code: Select all
; This procedure is called once, when the program loads the library
; for the first time. All init stuffs can be done here (but not DirectX init)
;
Global mutex
ProcedureDLL AttachProcess(Instance)
mutex = CreateMutex()
EndProcedure
; Called when the program release (free) the DLL
;
ProcedureDLL DetachProcess(Instance)
FreeMutex(mutex)
EndProcedure
; Both are called when a thread in a program call or release (free) the DLL
;
ProcedureDLL AttachThread(Instance)
EndProcedure
ProcedureDLL DetachThread(Instance)
EndProcedure
; Compilermode ansi
;-T_BSTR
Procedure helpSysAllocString(*Value)
ProcedureReturn SysAllocString_(*Value)
EndProcedure
Prototype.l ProtoSysAllocString(Value.p-unicode)
Global T_BSTR.ProtoSysAllocString = @helpSysAllocString()
ProcedureDLL GetString(*var.variant)
Protected temp.s, hr
LockMutex(mutex)
temp = "Hello World"
hr = VariantClear_(*var)
If hr = #S_OK
*var\vt = #VT_BSTR
*var\bstrVal = T_BSTR(temp)
EndIf
UnlockMutex(mutex)
ProcedureReturn hr
EndProcedure
ProcedureDLL GetFloat(*var.variant)
Protected hr
LockMutex(mutex)
hr = VariantClear_(*var)
If hr = #S_OK
*var\vt = #VT_R4
*var\fltVal = 99.8
EndIf
UnlockMutex(mutex)
ProcedureReturn hr
EndProcedure
; direct
Structure vbString
len.l
text.s
EndStructure
ProcedureDLL GetDirectString()
Static result.vbString
Protected temp.s
LockMutex(mutex)
temp = "Hello World"
result\text = temp
result\len = Len(temp)
UnlockMutex(mutex)
ProcedureReturn @result\text
EndProcedure
P.S. Example for object with safearray
http://www.purebasic.fr/english/viewtop ... s&start=15
Posted: Thu Aug 13, 2009 1:13 pm
by Edwin Knoppert
I have little understanding of pb but i am a programmer.
VB.NET likes unicode
VB6 strings obtained via an external dll seems to be ansi.
Variants like to use unicode strings, it's not a must but preferred by me.
The directstring function is a poor situation.
You better avoid that an prepare one situation.
There are two ways, obtain a BSTR or obtain a Variant pointing to a BSTR.
A variant pointing to a BSTR is NOT a safearray, a safarray is not required for this.
A BSTR is simply a handle, obtain it and copy it's data to a local thing and free it.
Posted: Thu Aug 13, 2009 1:35 pm
by mk-soft
That is correct.
If I write with purebasic dll´s also with NET Framework to be used am, one must use the WinAPI automation. Thus ensured that is it to memory leakages does not come. Thus VB.NET can release also duly in the DLL strings and also array put on again.
Property straight once again the example with arrays in the forum updates.
Posted: Sat Aug 15, 2009 3:14 pm
by Ollivier
I thank you for this interesting discussion. However, I didn't see you (Edwin Knoppert and mk-soft) continued it.
And I start to build a DLL with the method of Edwin Knoppert. It's a DLL used by VB6. Visibly, there is different methods for every compiler (VB6, VB2008 et VB.NET, etc...)
What do you think about this couple of code? Is this exact? Or do I do a mistakes if VB6 clears automatically the returned string, for example?
VB6:
Code: Select all
Declare Function InitLib Lib "MaLib.DLL" () As Integer
Declare Function TestLib Lib "MaLib.DLL" () As String
Declare Function CloseLib Lib "MaLib.DLL" () As Integer
Sub Main()
InitLib()
MsgBox TestLib()
CloseLib()
End Sub
DLL PB
Code: Select all
Macro ProcedureReturnSysStringGlobal(VarName)
! mov eax, [v_#VarName]
! mov [esp + 16], eax
ProcedureReturn
EndMacro
Global SPtr.I
ProcedureDLL.I InitLib()
SPtr = SysAllocStringByteLen_(" ", 1)
ProcedureReturn 1
EndProcedure
ProcedureDLL.I TestLib()
SPtr = SysReAllocString_(SPtr, "Petit message ok")
ProcedureReturnSysStringGlobal(SPtr)
EndProcedure
ProcedureDLL.I CloseLib()
SysFreeString_(SPtr)
ProcedureReturn 1
EndProcedure
Posted: Sat Aug 15, 2009 5:04 pm
by Edwin Knoppert
The caller frees.
Thus.. wrong code here..
It's so simple, i showed you..
For VB.NET you'll need to adapt VB.NET
Posted: Sat Aug 15, 2009 5:09 pm
by Edwin Knoppert
The test is easy.
Place a msgbox on each request right after the creation and show your self the value of the BSTR handle.
This should remain the same on multiple requests(as long no other BSTR requests where performed.)
Posted: Sat Aug 15, 2009 5:34 pm
by mk-soft
Is better to use the variant method by my Example "GetString(*result.variant)"
VB6
VB.NET
VB can then order in accordance with the memory of the variable result again release.
Posted: Sat Aug 15, 2009 6:42 pm
by Ollivier
@Edwin Knoppert
I understand your easy test. But I have an other test (which is harder) I can't try myself, because I haven't VB.
Is it possible to make a little PB DLL like you told me page 1 (with SysAllocStringByteLen_() ), and a little VB6 code which calls 1 million times (1 000 000 times). A priori, this test seems to crash... But I am not sure cause I give this exercice to another person: I didn't make it myself. He answered me it crashes. But I think he did a mistake in the test.
Could you publish the two little codes (DLL PB and VB6) here?
Posted: Sat Aug 15, 2009 7:38 pm
by Edwin Knoppert
Depends on your needs, be clear on this:
1)
VB6 returns a 'string' (but is an ansi BSTR handle).
2)
You want the same behaviour in your pb dll as descibed in #1?
3)
What will you do with VB.NET?
Will you allow to receive an ansi string and convert it to a VB.NET string?
(One way, from the dll to VB.NET)
Posted: Sat Aug 15, 2009 7:55 pm
by Ollivier
@Edwin Knoppert
Only for VB6!
Ollivier
Posted: Sat Aug 15, 2009 8:09 pm
by Ollivier
A couple of codes like this...
VB6 code
Code: Select all
Declare Function Test Lib "C:\DOCUME~1\EDWINK~1\LOCALS~1\Temp\PB51A\unsaved.dll" () As String
Sub Main()
MsgBox Test()
End Sub
PB DLL code
Code: Select all
ProcedureDll.I Test()
ProcedureReturn SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20)
EndProcedure
...But without MsgBox (cause it's impossible to click [ok] 1 000 000 times) and with a loop of 1 000 000 iterations in the VB6 code. No change in the PB DLL code. The goal is that VB6 must receive the most great possible quantity of strings without saturation.
Posted: Sat Aug 15, 2009 8:48 pm
by Edwin Knoppert
Try this:
www.hellobasic.com/trials/BSTRVBTest.zip
project1 is the VB6 exe
Pass a value on the commandline for using the loop.
Code: Select all
Declare Function Test Lib "pbdlltest.dll" () As String
Declare Function Test2 Lib "pbdlltest.dll" (ByVal sText As String) As String
Sub Main()
Dim x As Long
x = Val(Command)
'MsgBox Str$(x) & ", " & Test2(Time)
For a = 0 To x
Test
Next
End Sub
pbcode:
Code: Select all
ProcedureDLL.I Test()
ProcedureReturn SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20)
EndProcedure
ProcedureDLL.I Test2(sText.s)
ProcedureReturn SysAllocStringByteLen_(@sText, Len(sText))
EndProcedure
Posted: Sat Aug 15, 2009 10:01 pm
by Ollivier
@Edwin Knoppert
I thank you to prepare all that for me. But what I want is less...
I downloaded it, extracted it and executed it. The program crashes whatever the value is, and with or without slash "/".
I an sorry. I just want to know if, on your computer and with VB6, these two codes work fine:
VB6
Code: Select all
Declare Function Test Lib "pbdlltest.dll" () As String
Sub Main()
Dim x As Long
Dim MyString As String
x = 1000000
For a = 0 To x
MyString = Test
Next
End Sub
PB DLL
Code: Select all
ProcedureDLL.I Test()
ProcedureReturn SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20)
EndProcedure
(It's not a problem if MyString is overwritten every time)
(If there is an error in my VB6 code, you can correct it in order to get a good code)