If have an issue with MemoryBlock.CString and I’m not sure what’s going on, or if I misunderstand CString variables.
Dim mb As MemoryBlock
// some process to fill the MemoryBlock
...
The content of mb in the debugger now shows 61 62 63 00, which is “abc\0” (terminated with a null byte). This is of course just a test value. On runtime the content could be a String of any length.
Querying the content by StringValue returns the correct value:
Dim s As String = mb.StringValue(0, 3) // s is "abc"
Querying the content by using CString and assigning it to a String variable works also:
Dim c As String = mb.CString(0) // c is "abc"
Querying the content by using CString and assigning it to a CString variable returns garbage:
Dim c As CString = mb.CString(0) // c contains things like "BREAK" or "_VariantStructure" or just plain garbage
I think the Cstring data type is just for declares and is more or less a Ptr internally.
In that case, the compiler would probably throw away the temp string from the function call and you have a pointer to nowhere.
After reading the docs again, I think that it should work. The docs state CString as “uncommon data type” and there is no “for declares only”. I’ll work with assigning the value to a temporary string variable first, this works reliably (since MemoryBlock.CString returns a string, not a CString).
There is a data type called CString for declares. And there is a CString function on memoryblock which don’t do the same.
The CString function in memoryblock reads bytes from memoryblock until first zero byte is found. This string is returned.
Now try this example code:
[code] dim s as string = “Hello”
s = s + “!” // this makes copy, so we can modify it
dim c as cstring = s
dim m as new MemoryBlock(4)
dim p as ptr = m
p.CString(0) = c
dim op as ptr = p.Ptr(0)
MsgBox str(op.Int8(0))
op.int8(0) = 65
MsgBox s[/code]
Now you see we use the CString in Ptr which allows us to put the pointer of the CString into the memoryblock, to read it as ptr. Once we have the ptr to the actual string, we can modify it. And if you show s or c in msgbox, you see they point to the same bytes in string s.
So you read garbage because the original string the CString points to is gone already.
So when the CString is coming from an external source and its memory is freed by this external library, I receive garbage. And when I test it with a Xojo CString it works, because the Xojo framework handles the memory allocation and freeing of CStrings created in Xojo code. Makes sense.
Christian, I admire your brain “twistability” - took me some time to understand the code (and a lot of debugger steps - over and over again).
Despite the fundamental simplicity of this thread, it was actually quite interesting.
BASIC has always been the language “without pointers” but, you know, when you get used to them, they really aren’t that complicated, and actually quite simple.
[quote=78759:@Garth Hjelte]Despite the fundamental simplicity of this thread, it was actually quite interesting.
BASIC has always been the language “without pointers” but, you know, when you get used to them, they really aren’t that complicated, and actually quite simple.[/quote]
There is never any reason to DIM a variable of type CString. Use normal String variables in your Xojo code. CString is for communication with, well, C type code external to your app.
I have issues with a delares and CStrings. I have the following function in a dll
int __stdcall FuncGetVersion( void * objptr, char *cVersion, int nMaxLen);
my delare
Soft Declare Function FuncGetVersion Lib libName (cam as ptr, version as CString, len as integer) as Boolean
Then I use the function as follows.
dim res as Boolean
dim version as CString = “0123456789012345678901234567890” // without this it doesent work
dim len as integer = 30
res = FuncGetVersion(WID110, version, len)
I need to fill the version CString otherwise the program crashes or am I doing something wrong?
CString goes into the Declare. Use String in your code.
dim version as String = "0123456789012345678901234567890"
Xojo automatically converts a String variable into CString format when it passes it to the declare. Note that this is one-way only. If you need to get a string back from a declare, you need to use a memoryblock and declare the parameter as Ptr in the declare.
I get the correct result back in version without using a memoryblock and changing dim version as String work the same as before. The only time it’s not working is if I don’t set version to somthing longer then the string I’m expecting.
dim version as String = “0123456789012345678901234567890”
dim len as integer = 30
res = FuncGetVersion(WID110,version,len)
lbResults.AddRow "FuncGetVersion returned: " + str(res) + " " + version