Are strings fixed in memory or can they change address?
Posted: Fri Jan 17, 2025 12:34 am
I have been trying to get Index Data's YAZ dll to work from a Pure Basic program. I have had very little luck with this, and even recently resorted to the dreaded ChatGPT. One of the things it objected to is the way strings are passed via CallFunction. I thought strings were fixed in memory in a PB program but ChatGPT insists they are not.
An example of my code was:
YAZ_DLL$="D:\BMV10\yaz5.dll" ;64-bit version
Server$ = "z3950.loc.gov:7090/voyager" ; Connection address
YAZ = OpenLibrary(#PB_Any, YAZ_DLL$)
ServerPtr = Ascii(Server$).
Connection = CallFunction(YAZ, "ZOOM_connection_new", ServerPtr, Port)
ChatGPT said:
"While this can work for a quick reference to a string's memory address, it may lead to issues if the string changes or is not null-terminated. It is safer to allocate memory explicitly for such pointers when interfacing with a DLL."
It insisted I use AllocateMemory + PokeS
; Convert the server string to ASCII and allocate memory
Server$ = "z3950.loc.gov:7090/voyager"
ServerPtr = AllocateMemory(StringByteLength(Server$, #PB_Ascii) + 1)
If ServerPtr
PokeS(ServerPtr, Server$, -1, #PB_Ascii)
EndIf
Again, ChatGPT objected with the same reason.
I thought strings were fixed memory and zero-byte delimited.
Is this correct or not?
For anyone curious, the entire test program's code, mostly generated by ChatGPT, is:
(The 64-bit version of yaz5.dll is needed from IndexData.)
An example of my code was:
YAZ_DLL$="D:\BMV10\yaz5.dll" ;64-bit version
Server$ = "z3950.loc.gov:7090/voyager" ; Connection address
YAZ = OpenLibrary(#PB_Any, YAZ_DLL$)
ServerPtr = Ascii(Server$).
Connection = CallFunction(YAZ, "ZOOM_connection_new", ServerPtr, Port)
ChatGPT said:
"While this can work for a quick reference to a string's memory address, it may lead to issues if the string changes or is not null-terminated. It is safer to allocate memory explicitly for such pointers when interfacing with a DLL."
It insisted I use AllocateMemory + PokeS
; Convert the server string to ASCII and allocate memory
Server$ = "z3950.loc.gov:7090/voyager"
ServerPtr = AllocateMemory(StringByteLength(Server$, #PB_Ascii) + 1)
If ServerPtr
PokeS(ServerPtr, Server$, -1, #PB_Ascii)
EndIf
Again, ChatGPT objected with the same reason.
I thought strings were fixed memory and zero-byte delimited.
Is this correct or not?
For anyone curious, the entire test program's code, mostly generated by ChatGPT, is:
(The 64-bit version of yaz5.dll is needed from IndexData.)
Code: Select all
; Define constants and variables
;PWD$=#DQUOTE$+"set user 548880/bookmark"+#DQUOTE$+" "
;Connect$=#DQUOTE$+"connect z3950.loc.gov:7090/voyager"+#DQUOTE$+" "
;Format$=#DQUOTE$+"set preferredRecordSyntax USMARC"+#DQUOTE$+" "
;Search$=#DQUOTE$+"search "+#DQUOTE$+#DQUOTE$+"ringworld"+#DQUOTE$+#DQUOTE$+" "+#DQUOTE$+" "
;Show$=#DQUOTE$+"show 0 1"+#DQUOTE$+" "
;Close$=#DQUOTE$+"close"+#DQUOTE$+" "
;Quit$=#DQUOTE$+"quit"+#DQUOTE$
;P$="C:\BMV10\zoomsh.exe"
;AF$ = Connect$ + Format$ + Search$ + Show$ + Close$ + Quit$
;"connect z3950.loc.gov:7090/voyager" "set preferredRecordSyntax USMARC" "search ""the exploration of mars"" " "close" "quit"
; AF$=#DQUOTE$+"connect z3950.loc.gov:7090/voyager"+DQUOTE$
; AF$+" "
; AF$+DQUOTE$+"set preferredRecordSyntax USMARC"+DQUOTE$
; AF$+" "
; AF$+#DQUOTE$+"search "+#DQUOTE$+DQUOTE$+"ringworld"+#DQUOTE$+DQUOTE$
; AF$+" "
; AF$+#DQUOTE$+"close"+#DQUOTE$
; AF$+#DQUOTE$+"quit"+#DQUOTE$
; LOC$=GetCurrentDirectory()
; P$=LOC$+"zoomsh.exe"
; C=RunProgram(P$,AF$,LOC$,#PB_Program_Open | #PB_Program_Read|#PB_Program_Hide)
; Debug C
; If C
; While ProgramRunning(C)
; If AvailableProgramOutput(C)
; Debug ReadProgramString(C)
; EndIf
; Wend
; EndIf
; CloseProgram(C)
; End
; Define constants and variables
YAZ_DLL$ = "\BMV10\yaz5.dll"
Server$ = "z3950.loc.gov:7090/voyager"
Query$ = "ringworld"
Syntax$ = "USMARC"
preferredRecordSyntaxPtr$="preferredRecordSyntax"
loglevel$="log-level"
; Allocate memory for strings
;ServerPtr = AllocateMemory(StringByteLength(Server$) + SizeOf(Character))
;PokeS(ServerPtr, Server$)
;ServerPtr = Ascii(Server$)
; Convert the server string to ASCII and allocate memory
ServerPtr = AllocateMemory(Len(Server$) + 1)
If ServerPtr
PokeS(ServerPtr, Server$, -1, #PB_Ascii)
EndIf
; Convert the preferred record syntax to ASCII
;SyntaxPtr = AllocateMemory(StringByteLength(Syntax$) + SizeOf(Character))
;PokeS(SyntaxPtr, Syntax$)
SyntaxPtr = Ascii(Syntax$)
;SyntaxPtr = AllocateMemory(Len(Syntax$) + 1)
;If SyntaxPtr
; PokeS(SyntaxPtr, Syntax$, -1, #PB_Ascii)
;EndIf
; Convert the query string to ASCII
;QueryPtr = AllocateMemory(StringByteLength(Query$) + SizeOf(Character))
;PokeS(QueryPtr, Query$)
QueryPtr = Ascii(Query$)
;QueryPtr = AllocateMemory(Len(Query$) + 1)
;If QueryPtr
; PokeS(QueryPtr, Query$, -1, #PB_Ascii)
;EndIf
preferredRecordSyntaxPtr=Ascii("preferredRecordSyntax")
;preferredRecordSyntaxPtr=AllocateMemory(Len(preferredRecordSyntax$)+1)
;If preferredRecordSyntaxPtr
; PokeS(preferredRecordSyntaxPtr, preferredRecordSyntax$,-1,#PB_Ascii)
;EndIf
loglevelPtr=Ascii("log-level")
;loglevelPtr=AllocateMemory(Len(loglevel$)+1)
;If loglevelPtr
; PokeS(loglevelPtr, loglevel$,-1,#PB_Ascii)
;EndIf
; Open the YAZ DLL
YAZ = OpenLibrary(#PB_Any, YAZ_DLL$)
If YAZ
Debug "YAZ DLL loaded successfully."
; Create a connection to the Z39.50 server
Connection = CallFunction(YAZ, "ZOOM_connection_new", ServerPtr) ; Explicitly pass port
If Connection
Debug "Connected to server: " + Server$
; Set the preferred record syntax
Debug "Setting preferredRecordSyntax to: " + Syntax$
CallFunction(YAZ, "ZOOM_connection_option_set", Connection, preferredRecordSyntaxPtr, SyntaxPtr)
; Enable logging
LogLevelPtr = AllocateMemory(StringByteLength("debug",#PB_Ascii) + 1)
PokeS(LogLevelPtr, "debug", #PB_Ascii)
CallFunction(YAZ, "ZOOM_connection_option_set", Connection, loglevelPtr, LogLevelPtr)
; Create a query
Query = CallFunction(YAZ, "ZOOM_query_create")
If Query
Debug "Query created successfully."
; Set the query string
Debug "Query String: " + Query$
CallFunction(YAZ, "ZOOM_query_prefix", Query, QueryPtr)
; Execute the search
Debug "Executing search..."
ResultSet = CallFunction(YAZ, "ZOOM_connection_search", Connection, Query)
If ResultSet
Debug "Search executed successfully."
; Get the number of results
ResultCount = CallFunction(YAZ, "ZOOM_resultset_size", ResultSet)
Debug "Number of results: " + Str(ResultCount)
; Retrieve error message
ErrorPtr = CallFunction(YAZ, "ZOOM_connection_errmsg", Connection)
If ErrorPtr
ErrorMessage$ = PeekS(ErrorPtr, -1, #PB_Ascii)
Debug "Error Message: " + ErrorMessage$
Else
Debug "No error message reported."
EndIf
; Debug diagnostic code
Diag = CallFunction(YAZ, "ZOOM_connection_diag", Connection)
Debug "Diagnostic Code: " + Str(Diag)
; Destroy the result set
CallFunction(YAZ, "ZOOM_resultset_destroy", ResultSet)
Else
Debug "Search failed."
EndIf
; Destroy the query
CallFunction(YAZ, "ZOOM_query_destroy", Query)
Else
Debug "Failed to create query."
EndIf
; Destroy the connection
CallFunction(YAZ, "ZOOM_connection_destroy", Connection)
Else
Debug "Failed to connect to server."
EndIf
; Close the YAZ DLL
CloseLibrary(YAZ)
Else
Debug "Failed to load YAZ DLL."
EndIf
; Free allocated memory
FreeMemory(ServerPtr)
FreeMemory(SyntaxPtr)
FreeMemory(QueryPtr)
FreeMemory(preferredRecordSyntaxPtr)
FreeMemory(loglevelPtr)