Return a string from PB to VB

Just starting out? Need help? Post your questions and find answers here.
Ollivier
Enthusiast
Enthusiast
Posts: 281
Joined: Mon Jul 23, 2007 8:30 pm
Location: FR

Return a string from PB to VB

Post by Ollivier »

Hello,

I try to understand how it is possible to return a string from a DLL built by PB to VB6.

I have this code but I haven't VB. Could anybody try to compile it into a DLL and test this function with VB in order to get the string "DLL MESSAGE IS OKAY!" in VB? In the good way, is it possible to post the required VB code?

Thank you!

Code: Select all

ProcedureDLL.I Test()
  Protected *AdresseChaine
  *AdresseChaine = SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20)
  ProcedureReturn *AdresseChaine
EndProcedure 
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

You are close, i don't see the need of using a pointer.
Just return the result from the API, that's all.

What i never understood how the calling app decides if the result is in ansi or unicode.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

I have create a VB6 app and the following works just fine:

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
And used PB code:

Code: Select all

ProcedureDll.I Test() 
  ProcedureReturn SysAllocStringByteLen_("DLL MESSAGE IS OKAY!", 20) 
EndProcedure
Of course when the dll is placed near the exe you won't need the folder in the declare.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

I also tried unicode but i see one character only.
So it can be a VB6 issue or i converted my ansi string to unicode poorly?

Code: Select all

ProcedureDll.I Test() 
    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
Ollivier
Enthusiast
Enthusiast
Posts: 281
Joined: Mon Jul 23, 2007 8:30 pm
Location: FR

Post by Ollivier »

I suppose it's a switch value which set the format (ANSI or Unicode from DLL) in VB6.

I thank you for yours codes. So, with these codes, you can read really "DLL MESSAGE IS OKAY!" in a message box in VB6?

(A other person said me he couldn't read it, but he got numbers instead the the string "DLL MESSAGE IS OKAY!")

Ollivier
Ollivier
Enthusiast
Enthusiast
Posts: 281
Joined: Mon Jul 23, 2007 8:30 pm
Location: FR

Post by Ollivier »

Edwin Knoppert wrote:You are close, i don't see the need of using a pointer.
You are right! It works fine WITHOUT pointor! But, now I don't understand why it doesn't work fine if I add this record... I'll try to find why...
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

I suspect VB6 can not read unicode BSTR's this way.
It also converts its unicode strings to ansi when passed byval.
It may by design.

VB.NET is a different thing, often the mistake is made to use an identical declaration as in VB6.

So.. are you going to bother with unicode or is it for VB6 only?
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Post by mk-soft »

Example for vb6, not threadsafe
http://www.purebasic.fr/german/viewtopic.php?t=14931
:wink:

P.S.
if those was compiled DLL as unicode must with vb also declare unicode be used
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

Imo this code should not be used, you must return a BSTR!

>Eine vorherige Umwandlung nach BSTR(Unicode) ist nicht erforderlich, da dieses von VB selber durchgeführt wird.
What does this mean?

The caller destroys the handle, this is by design!

The VB.NET version is ok i suspect since it does not expect a BSTR this way.
Not sure what it expects though, you should be careful.

If things seems to work it doesn't mean it is correct.
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Post by mk-soft »

Eine vorherige Umwandlung nach BSTR(Unicode) ist nicht erforderlich, da dieses von VB selber durchgeführt wird
Ignore this. That's of no importance.

The result string is static and destroy by release dll

I test another simple method over object (variant)

vbDLL.dll

Code: Select all

; Compileroption unicode or 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
  
  temp = "Hello World"
  VariantClear_(*var)
  *var\vt = #VT_BSTR
  *var\bstrVal = T_BSTR(temp)
  ProcedureReturn Len(temp)
  
EndProcedure

ProcedureDLL GetFloat(*var.variant)

  VariantClear_(*var)
  *var\vt = #VT_R4
  *var\fltVal = 99.8
  ProcedureReturn #True
  
EndProcedure
VB.NET Modul "test.vb"

Code: Select all

Module test

    Declare Unicode Function GetString Lib "vbDLL.dll" (ByRef var As Object) As Int32
    Declare Unicode Function GetFloat Lib "vbDLL.dll" (ByRef var As Object) As Int32

End Module
form1.vb snipped code

Code: Select all

   Private Sub ToolStripMenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItem2.Click

        Dim result As Object

        test.GetString(result)
        Me.ListBox1.Items.Add(result)
        test.GetFloat(result)
        Me.ListBox1.Items.Add(result)

    End Sub
Very easy :wink:
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

This is simply another way and it escapes me where you destroy the BSTR placed into the variant.
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Post by mk-soft »

"VariantClear_(*var)" is your friend :D

By method

Code: Select all

Structure vbString
  len.l
  text.s
EndStructure

ProcedureDLL GetDirectString()

  Static result.vbString
  
  Protected temp.s
  
  temp = "Hello World"
  result\text = temp
  result\len = Len(temp)
  ProcedureReturn @result\text

EndProcedure
not using destroy the string because vb create a copy from the result

P.S
If compiled the dll as ansi you must "declare ansi function ..." by vb
if compiled the dll as unicode use "declare unicode function ..."
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

Then you have a leak..
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Post by mk-soft »

No,
I tested the pointers of string and VariantClear freed bString

MSDN
Comments
Use this function to clear variables of type VARIANTARG (or VARIANT) before the memory containing the VARIANTARG is freed (as when a local variable goes out of scope).

The function clears a VARIANTARG by setting the vt field to VT_EMPTY. The current contents of the VARIANTARG are released first. If the vt field is VT_BSTR, the string is freed. If the vt field is VT_DISPATCH, the object is released. If the vt field has the VT_ARRAY bit set, the array is freed.

If the variant to be cleared is a COM object that is passed by reference, the vt field of the pvarg parameter is VT_DISPATCH | VT_BYREF or VT_UNKNOWN | VT_BYREF. In this case, VariantClear does not release the object. Because the variant being cleared is a pointer to a reference to an object, VariantClear has no way to determine if it is necessary to release the object. It is therefore the responsibility of the caller to release the object or not, as appropriate.

In certain cases, it may be preferable to clear a variant in code without calling VariantClear. For example, you can change the type of a VT_I4 variant to another type without calling this function. Safearrays of BSTR will have SysFreeString called on each element not VariantClear. However, you must call VariantClear if a VT_type is received but cannot be handled. Safearrays of variant will also have VariantClear called on each member. Using VariantClear in these cases ensures that code will continue to work if Automation adds new variant types in the future.

Do not use VariantClear on unitialized variants; use VariantInit to initialize a new VARIANTARG or VARIANT.
"Dim result as Object" isn´t the same as "Dim result as String"

It´s compatible to ole-automation
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

I meant in this part it is worth testing if VB.NET clears the object properly:

Code: Select all

        Dim result As Object 

        test.GetString(result) 
        Me.ListBox1.Items.Add(result) 
        test.GetFloat(result) 
        Me.ListBox1.Items.Add(result)
However, i am not going further discussion this specific code.
You wrote a thread unsafe situation which is really not needed and could avoid all the object code on both sides.

It's simple, the PB dll returns a handle, it's just a long integer.
The caller must clear what's is obtained.
So use the handle received (which can be null) and copy the characters from the BSTR into a local string and free the BSTR.
(If ansi copy to a byte array and convert)
A BSTR is a great vartype, use the things it offers like true length of content, allows chr(0)'s, what do you need more?
Post Reply