Writing DLLs in Delphi
Strings
One of the (many) things that Delphi is limited with respect to VB is the string handling capabilities. In VB we are spoilt with a string size of 64 kbytes and an assortment of manipulation functions (mid$, left$, right$ etc).
Traditional pascal strings can be a maximum or 255 characters long. To 'solve' this limitation Delphi also included null terminated strings, which is the C format. A number of manipulation functions are provided and to translate between the string types.
Null terminated strings is the best way to transfer strings to DLLs as this makes the DLL usable by all applications that can call C DLLs, including VB. To pass a string from VB to a DLL the following declaration is used:
declare sub rg2str lib "Rg2.dll" (byval lpstr as string)
Notice the use of Byval with strings causes VB to turn the string into a null terminated type and pass the address of the first character to the DLL. ie a pointer to the start of the string.
The external DLL cannot create strings to return to VB, only modify existing strings. Therefore to return a string value from the DLL the string space must be reallocated to the maximum possible number of characters that may be returned. This is easily done using the space function. Therefore to use the DLL sub program declared above the following code is used.
dim a$,posn% a$ = space$(255) ' expect a maximum of 255 characters in the string call rg2str(a$)
a$ now holds the string returned by the DLL plus a trailing char$(0) which needs to be stripped off. This can be done by returning the number of characters from the DLL as a parameter or using the VB left$ function. Continuing the code fragment...
posn = instr(a$,chr$(0)) ' look for null character
if posn > 0 then ' check there are some characters
a$ = left(a$,posn-1)
endif
Let's look at the Delphi end. The following code fragment shows some methods for receiving strings from VB and sending strings back. However, I am not going to go into much detail on the vagaries of null-terminated and pascal strings. Do not use var, even if sending strings back to VB as we want the value of the pointer, ie. the address of the variable.
uses
SysUtils,dialogs;
procedure rg2str(ptr2String:pchar);
export; {DO NOT use var}
implementation
procedure rg2str(ptr2String:pchar);
var
s:string;
x:integer;
begin {change text to pascal string}
s := strpas( ptr2String);
showmessage(s);
x:=strlen( ptr2String); {show lengtth of string}
showmessage(inttostr(x)); {send text back to VB}
strPCopy(ptr2String, 'Text from dll');
end;