Query: Passing strings into/out of PB DLL routines

Just starting out? Need help? Post your questions and find answers here.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by darryl_bartlett.

Hi everybody,

I have already searched through the forums looking for an answer to my query but I haven't spotted anything which answers my question, but please forgive me if this has been answered elsewhere. My query is based on writting a DLL using PureBasic.

I read in the documentation that as well as creating the DLL, it creats a .lib file compatible with Microsoft's Visual C++.

What I want to do is to be able to pass strings into the DLL function (written in PureBasic) and return a resulting string.

As a very simple example, if the function was to concatinate two strings together and return the result in a third string value
e.g.
as pseudocode
ProcedureDLL Catstring(input string 1, input string 2)
output string = input string 1 + input string 2
return output string to calling application
EndProcedure

How would I write that in PureBasic? Would I have to use pointers to pass the strings into DLL function? Would the output string returned have to be passed in as part of the procedure parameters?

Thanks in advance for any help you may be able to offer me

Daz.


Registered PureBasic User
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Rings.

see a possible solution at the resourcesite here:
http://www.reelmediaproductions.com/pb/ ... _PBDLL.zip

Its a long way to the top if you wanna .....CodeGuru
User avatar
waffle
Enthusiast
Enthusiast
Posts: 129
Joined: Mon May 12, 2003 1:34 pm
Location: USA
Contact:

Post by waffle »

the above link is broken

Fred said you need to use a global string.

global FinalString.s

proceduredll ConCat(A.s,B.s)
FinalString=A+B
procedurereturn @FinalString
endprocedure
D'Oldefoxx
User
User
Posts: 30
Joined: Wed Aug 06, 2003 5:52 pm
Location: Florida, USA

Passing String Parameters.

Post by D'Oldefoxx »

PureBASIC uses a string form compatable with C/ C++. That is, you get a pointer to the screen start, and you follow the string until you find a Null byte, or Chr(0). In PowerBASIC, this would be referred to as an ASCIIZ string, or ASCII string terminated by a zero.

PureBASIC strings can only achieve a maximum length of 250 bytes - anything over that would be discarded automatically.

Parameters for procedures are generally passed on the stack. When you define the procedure, such as:

Procedure.s CatString(string1$,string2$), you are telling the compiler to take the first pointer and pass the first string to it, then the second pointer and pass the second string to it. The compiler will actually copy the first string to string1, and the second string to string2, based on their pointers and its ability to move along each string until it finds the Null character.

When you do string2$=string1$+string2$, you create a third local string variable that now holds the concatenated results. When you do a ProcedureReturn string3$, a pointer to the local string, which is again Null terminated, is passed back from the calling routine, but this time by one of the registers in the x87 processor. This will probably be the EAX register, but that depends upon the way the compiler works. On exiting, the whole string is then copied back to the external process that originally called the procedure. So for your understanding, parameters for a function or sub are passed to that function or sub via the stack, and appear on the stack above the return address that is also placed there during the call to the procedure. On exit, the return address is used to get back to the point where the call was made, and this process removes the return address from the stack. The compiler should then remove the parameters from the stack as well, although you will find that this is a task that the programmer has to do expressedly in the C or C++ environment. The actual function result sould still be in the designated register. The the If statement or Assign (=) statement

Of course the mechanism for all this is normally hidden, unless you need to use assembler code for part of your processes.. But since your whole example can be done within PureBASIC, your approach is pretty close to the code I would use:

Code:

Code: Select all

Declare.s CatString(string1.s,string2.s) 

OpenConsole 
s1$="This is string one. " 
s2$="This is string two." 
PrintN(CatString(s1$,s2$) 
Repeat 
Until inkey()>"" 
CloseConsole() 
End 

Procedure.s CatString(strint1,s,string2,s) 
ProcedureReturn string1$+string2$ 
EndProcedure 



Note that since the procedure is positioned after the main part of the program, the compiler will not know what CatString() is when it first sees the term, which causes an error. By putting a Declare statement before the first use of CatString(), the compiler understands the nature of the reference and the type of parameters being passed, so it is able to encode the balance of the program and finish up with the procedure itself.

The languages C and C++ recognize a Main() declarative to show where the main program is. PowerBASIC uses a FUNCTION PBMAIN, FUNCTION WINMAINa(), or FUNCTION MAIN in the same manner, terminated by a END FUNCTION. This indicates where the main body of code is. Some compilers, such as QBASIC, QuickBASIC, and PB/DOS, do not have any code point marking where the main part of the code is, but unless withing a Function or Sub segment of the program, all compiled statements are made a part of the main body in the order they are encountered.

I noted that in PureBASIC, if a procedure comes before the main body, the compiler seems to regard this as an indication that there is no main body. I suspect that you could use a Goto statement before a procedure and jump to a location after the procedures, or do as I have done here, which is to put the procedures last and a Declare for each one first, so that the actrual code for the main section appear before all the procedures.

I'm not going to swear by these findings, as I have only attempted to write three PureBASIC program thus far, and I have not conclusively tested all variations. But this may give you some idea of how some things either work or may need to be done. Without extensive documentation, trial and error or checking out example code may be the best way to go.
Has-been Wanna-be (You may not like what I say, but it will make you think)
User avatar
waffle
Enthusiast
Enthusiast
Posts: 129
Joined: Mon May 12, 2003 1:34 pm
Location: USA
Contact:

Post by waffle »

thanks for the very verbose explanation...
but, DLL procedures are handled somewhat differently than standard procedures in PB which is why my code snip has no main body and is why a global variable is required in this instance. A global vaiable in a DLL will maintain a fixed address (the pointer is a constant for the life of the DLL).
while a pointer inside a DLL function is not reliable as these are discarded upon procedure exit.
Fred
Administrator
Administrator
Posts: 18351
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

String in PB are limited to 64000 bytes, not 250..

About returning a string form a ProcedureDLL, use a global variable so it willn't be discarded when the procedure exits.
LJ
Enthusiast
Enthusiast
Posts: 177
Joined: Wed Apr 30, 2003 4:00 pm

In Tricks and Tips

Post by LJ »

In Tricks and Tips I've done a tutorial on passing information between your main .exe and a .dll, check it out.
Post Reply