I’m using a Soft Declare to call a C-function on a Linux Box. In “C” terms I pass in a “string” and get back a “string” – let’s call it … key : value
I defined my function to have a single CString parameter and expect a CString result.
When I call that function I just pass in an ordinary Xojo “String” and the C-Function seems happy enough. It receives the value no issue. So far so good.
Second…when I receive the CString result… and put it in a message box… again…it seems just fine. (beginners luck?) My question is…what’s really going on here? I think my function returns a “pointer” to string. I’m amazed it works. Also…my CString is UNSIGNED character data and may contain unprintable characters. Is that going to cause a problem? I know I can’t put it in a MsgBox because… . I can COPY the CString into a memory block right? There’s no issue with sending/receiving unsigned character data is there?
One potential issue to be aware of is memory management. Somebody - your app or the library - has to be responsible for allocating and then freeing a chunk of memory. Typically, it falls to your app to do the memory management. You allocate a New MemoryBlock and pass a pointer to it. The library function uses that as a char * string variable and writes to it. A typical setup is
Declare Sub myfunction Lib "somelib" (inputstring as CString, outputstring as Ptr)
dim s as string = "Hello World"
dim mb as New MemoryBlock(512)
myfunction(s, mb)
msgbox mb.CString(0)
Yea, the piece of cloth would be a G-String. Very different. I like doing the memory block management in the Xojo app. I was using the C program to create the memory and wondered when and how I would free it so I dont create a memory leak. Im setting up the Xojo app as a web service which will parse the key value response and JSONize it and return it to the caller. Passing a pointer to memory effectively updating a parameter by reference sounds like a good plan. I expect msgbox will still be unhappy if if tell it to display the CString and there are undisplayable characters in there…but I can deal with that if I have the raw bytes in a memory block.
Just use a String There is no need for a MemoryBlock here as a String will act as a “bag of bytes” for this purpose and, I believe, Xojo will handle the trailing Null for your automatically.
Also, a MsgBox is going to try to display whatever is in a String, regardless if it’s readable or not, and will do so without issue. In other words, no “boom”.
To confirm, try this:
dim s as string
for i as integer = 0 to 255
s = s + ChrB( i )
next
MsgBox s
Finally, behind the scenes, a String variable is a pointer to chunk of memory anyway. When you assign one String variable to another, you are really just assigning the same pointer, not making a copy, so a String will hold the reference for you.
The MemoryBlock is needed for interfacing with a declare. You can’t get a String back directly.
If you retrieve arbitrary data that could contain a null byte, then you want the declare to return the data size as well. Then you can use mb.StringValue(0, datasize) to put the data into a string, which as Kem notes, is just a bag of bytes at that point.
Interestingly enough… the following code works on both Desktop and Web Message can be defined as either a Cstring or String…no difference. And yet when my C subroutine returned a Cstring with an embedded Hexfe that app gave me an “illegal character java exception” or some such thing.
dim message as Cstring
message = “hello” + chr(254) + “world”
msgbox(message)
I have experienced no issue thus far with Xojo both sending and receiving a Cstring - however, I need to do some significant manipulation on that value…so if a function “returns a string” I need to store it somewhere I can manipulate it. Looks like I have multiple choices. I do think I’ll change my code to pass a pointer parameter and have the function return value go back to integer and signal success/failure of fetching a value for the key provided. A special shout -out thank you to all the participants in this discussion. Your insight is truly appreciated.
I just whipped up a dll (ascii not unicode) and used it without issue. It was just a simple test to add every character from 0x01 to 0xFF to a string and return it with the allocation taking place in the dll.
Here is a view of the data in the IDE having put a breakpoint after the returned call to the dll.
This was all done using CString in the Xojo declare being placed into a String. The only character you cant send is 0 because it will terminate the string at that point. Use a memoryblock if you want to handle this.
Here’s the Xojo code:
Declare Function MyFunction Lib "StringTest.dll" () As CString
Dim tmp As String
tmp = MyFunction()
MsgBox(tmp)
Thanks…Your test is pretty much exactly what I was going to do. It’s strange. I’ll have to use the debugger to figure out why my program is unhappy – naturally I don’t “need” the data in a msgbox…but I was just testing to make sure I get the correct data back when I run with various keys. It can be tough to pin down because…I’m using Web Edition on a Linux host. It could be something unique to a 64-bit linux host build…or it could be something entirely different. I have so many options here now…and I don’t really “need” the result in a msgbox – I was just making sure I was getting back what I expected. The Linux builds use some shared libraries…so it could even be something unique to my version of linux and supporting libraries.
My problem center around how web edition sends data back to the browser. The strings must be UTF8 encoded somehow.
(even if the encoding property is Nil…as long as the string is UTF8 – no issue)
Dim s as string
s = “hello” + Chr(254) + “world”
MsgBox s
I might expect viewing this variable in the debugger I would see a Hex “fe” in between the bytes for “Hello” and “World”.
This is not true. The actual bytes for Chr(254) are “C3 BE”.
It doesn’t matter whether I declare “s” as String or CString. The MsgBox displays perfectly.
As I’d expect in a memory block the Hex value is indeed 41 FE 42
If I set s = mb.CString(0) the value of “s” is as directly above with the embedded Hex FE.
String or CString doesn’t matter. Encoding setting doesn’t matter. What does matter is that the binary contains the “FE”
It’s the memory block builders responsibility to make sure the bytes in the memory block are valid UTF-8.
This non UTF8 encoded character (Hex FE) cannot be delivered to the browser via the JSON model used by Xojo.
I haven’t yet lucked upon a built-in method to convert the string into UTF8 – though I’m not entirely certain I want to.
These characters are meaningful for parsing the “Value” I get back from the external sub. Being able to display them in a MsgBox isn’t really necessary for me. Thanks again to everyone who has taken their time to look at this issue and share their knowledge.
If you are trying to display it on the web, you could just put a &# before every byte >127
[code]Dim mb As New MemoryBlock(5)
mb.Byte(0) = 65
mb.Byte(1) = 254
mb.Byte(2) = 66
mb.Byte(3) = 0
Dim s As String
Dim b As Byte
For i As Integer = 0 To mb.Size - 1
b = mb.Byte(i)
If b > 127 Then
s = s + “&#” + str(b)
Else
s = s + chr(b)
End If
Next
system.DebugLog(s)[/code]
This displays
AþB
which renders fine in HTML.
Or this method:
[code]Dim mb As New MemoryBlock(5)
mb.Byte(0) = 65
mb.Byte(1) = 254
mb.Byte(2) = 66
mb.Byte(3) = 0
Dim s As String
Dim b As Byte
'you don’t need this next line as strings are UTF-8 out of the box
s = s.DefineEncoding(encodings.UTF8)
For i As Integer = 0 To mb.Size - 1
b = mb.Byte(i)
s = s + chr(b)
Next
system.DebugLog(s)[/code]
This displays:
AþB
which renders fine in a browser but it more useful if you want to play around with the values in code.
If you go the 2nd code route, you might be able to increase performance by building raw bytes rather than building a string if you were after extreme performance. I’ve never had the need to tweak raw UTF-8 before, I remember Kem posting something about it here, you might be able to adapt the part that does it into your code.