Correct idiom for passing CString via structure?

Yes you get the pointer plus * bytes. Structure debugging is broken in xojo. This would make it hard. Try to wrap a class around the structure. And have computed properties with getters return your values. This way you can debug it

@DerkJ – not sure I need to debug it anymore. Xojo support wants me to submit a project to reproduce the issue, so I’ve created that, and it fails as I now expect it would.

I think the error is just that there IS NO ERROR when making this assignment. Making an assignment from a String to a structure member of CString DOES NOT create a scoped CString allocation, like if I would have made the assignment to a Var x as CString.

In C++, it would the equivalent of this:

std::string str1("some string");
char * foo = str1.c_str();

…which absolutely works – until str1 goes out of scope and is destructed. Then the char* foo is holding onto a pointer that is stale.

The problem with Xojo not launching my simple test app was that somehow, some data related to the Xojo IDE got corrupted. I needed to RESTART Windows, and then the test app launched again.

Long story short, did you get this working as I can’t find the feedback report with your project in and I just put a demo together that works with CString’s in a structure being directly assigned and passed to a DLL.

@JulianS – Xojo removed my feedback report because I didn’t submit the requested project within the required timeframe.

YES – it works if you already have an “allocated” CString (IE a Var), then assign that to a CString field.

NO – it DOESN’T work if you attempt to directly assign a String object to that CString field.

I’m not sure if that’s entirely wrong, but it seems that attempting to do so should at least generate a warning that it won’t work.

Hmm, that’s not what I see here, but my demo might be different to what you’re doing. Take a look if you want, tweak it, re-upload it, and I’ll take a look at what is happening. The output can be viewed easily using DebugView

https://blog.samphire.net/private/xojo/forum/VSDLLTestCString.zip

OK, you don’t even need to involve a DLL. As this project shows, you can’t even assign directly from a String object then retrieve the CString:

LINK TO DOWNLOAD Simple Project:

This is a 64-bit only project. All three structure members are CString.I also dump the strings to System.DebugLog. Note Str2:

Str1 = testing, one, two, three
Str2 =
Str3 = testing, one, two, three

The code is simply:

// string sources:
Var testString as String = "testing, one, two, three"
Var testCString as CString = testString

// Now we assign to the Structure's CString members, which are all the same definition
Var aStruct as MyApp.MyStructure

aStruct.Str1 = "testing, one, two, three" // string literal.  WORKS

aStruct.Str2 = testString  // allocated Var String.  FAILS: (will not have a ptr to anything).

aStruct.Str3 = testCString  // allocated Var CString.  WORKS

// read it back out -- no need to even involve a call to a DLL
System.DebugLog("Str1 = " + aStruct.Str1)
System.DebugLog("Str2 = " + aStruct.Str2)
System.DebugLog("Str3 = " + aStruct.Str3)

Quit(0)

No matter what you do, if any process or output converts that CString to a String, it wont show the Null (0) byte. Whenever you go from a CString to a String in Xojo, it will strip off the end Null (0) byte but as you can see in the following screenshot, the Null (0) is there if you look at the block of memory.

The reason Str2 doesn’t show is because the structure is invalid for 64bit, you need to pad things so they align correctly, this is a known bug <https://xojo.com/issue/51124>

If you correct the structure layout for 64bit, see below, then all DebugLog outputs will work.

image
(note the other bug in the above image, the project is 64bit but it’s showing the 32bit sizes of the structure, you have to check another box to see the “correct” sizes but it doesn’t show those when you actually do that because of <https://xojo.com/issue/65295>)

image

If this is what you’re doing here Correct idiom for passing CString via structure? - #6 by Stephen_Greenfield, then you will need padding.

You can use StructureAlignment 0 on the structure (see Structure — Xojo documentation), but I prefer to do it by hand as I wouldn’t trust that as far as I could throw it.

1 Like

Well, now I AM confused.

Are the structure’s STRx CString fields pointers, or not? Because if they are, on x64, shouldn’t they be 64-bit pointers (IE 8 bytes)? And if so, why would they need padding?

When I measured the SIZE of the structure in a 64-bit build, three CString fields equals a size of 24 bytes. That’s what I would expect for three 64-bit pointers.

That’s why I believe this Structure preference is broken:

image

Yes they are pointers and they change from 4 to 8 but see <https://xojo.com/issue/65295>, the IDE doesn’t show the correct sizes for WString or CString when they are in structures.

However, their offsets are wrong when used in 64bit. To see that, change it to a 32bit project and remove any padding you have manually put in, boom, working as expected.

I apologize if we’re talking about two different issues.

Forget for a moment about anything 32-bit. All my stuff is 64-bit.

And let’s assume for a moment that the display of offsets in the Xojo IDE is incorrect. But I assume the Structure.Size() function works correctly, right?

If Structure.Size() works correctly, then the size of three CString pointers is 24 bytes. Three 64-bit pointers. There is no need for padding, and the offsets in the actual program will be correct?

There is no logic to it, I can cause errors and/or different output by literally adding in one line of code that is unrelated.

<https://xojo.com/issue/52211>

This is why I said a looooooong time ago, do not trust xojo produced 64bit windows apps.

Most of these issues are 4-5 years old now, nothing is ever done about it, I’m sure @Joe_Ranieri would have sorted it by now if he were still there. Impact surface, that’s all Xojo seems to care about now.

Case in point:

Do some stuff, revert back to your code, run without issues:

Reload the IDE and load the exact same code in and run it:

Basically unusable, which is why I always default to 32bit when testing stuff.

Just talking about this is making me seriously wonder why I’m still even playing around with Xojo.

This is why I said a looooooong time ago, do not trust xojo produced 64bit windows apps.

Oh, this is quite worrisome. I’m about to embark on an app where I build massive UI and interface to a very large 64-bit C++ DLL. I can’t go back to 32-bit.

I recently saw an issue where somehow Xojo gets corrupted (or maybe its Xojo that corrupts the Windows 10 OS), such that debug builds won’t run and binary builds won’t have all the proper DLLs copied into the build folder – UNTIL I RESTART Windows 10!

Happens to me approximately twice a day. No idea what’s causing it. That’s very brittle behavior.

Yup, I have a video of two loaded projects in the IDE, debug on one causes the other to run, I’ve not even though about looking into reproducing that in a ticket yet.

Hand on heart, I’d look elsewhere, the fact that this stuff hasn’t been fixed in 4-5 years should be setting off alarm bells for you.

Sadly, outside of the various web app frameworks, there just isn’t any feature-rich cross-platform tools for developing native desktop apps. MAYBE ReactNative, or Flutter. Java is a big hunking mess.

My company has written two high-end cross-platform frameworks, but sooner or later, the amount of maintenance required to keep them up-to-date becomes excessive.

The best that one can do is to move virtually all model (“business logic”) operations into a separate, cross-platform library. Probably C++ with a C-API. Then use RAD tools to apply UI.

That was my hope for Xojo.

You may be better off abandoning Structures for this and just wrap a MemoryBlock in a class where the members of the “structure” are computed properties that know their own offsets and can get/set their values dependably.

@Tim_Hare – cool idea, but would work for a structure I’m trying to pass to a C++ DLL?

In any case, I’ve had absolutely no problem ever since I assigned the String to a Var CString as an intermediate step BEFORE I THEN assigned that CString to the CString structure field. I described doing that in my very first post.

I STILL suspect what I original ran into was a bug because I was assigning a String directly to a CString field in a structure, which probably created a temporary CString allocation that in no way was going to have any kind of lasting scope.

And that’s what I saw INSIDE my DLL when the structure/CString arrived: sometimes I got a pointer to a completely arbitrary string – from my Xojo program, but not a string close to the scope where the call was made.

The inconsistent behavior that @JulianS demonstrated would be consistent with this hypothesis: the pointer being accurate (when directly assigned from a String) would be highly dependent on the state of Xojo’s memory management at that moment.

As a side note, you can see I made all the fields in my structure 64-bit quantities, so there could be no issues with alignment or padding when going back-and-forth to the C/C++ DLL. Sure, it’s excessive to send 8 bytes for a Boolean that could easily take a single byte. But in my case this is ONE structure being passed back and forth, so who cares?

In fact, as a further don’t-try-this-at-home move, I allocate the strings I return from the DLL in the DLL – and I NEVER BOTHER TO RELEASE THEM. Why? Because the lifetime of my activation/registration tool is on the order of 5 minutes, max, and there’s maybe a dozen strings that are allocated – so who cares? The program terminates, and all memory is freed up.

Just don’t tell Bjarne Stroustrup… :wink:

Yes. MemoryBlock was the original mechanism for interacting with declares before Xojo implemented the concept of a Structure. If you ever hit a bug in Structure that you can’t work around, you can always fall back to a MemoryBlock and make your own convenience methods for working with it.

1 Like

You need a size for the string in the structures.
MyCstring As Cstring * 4 // 4 bytes size

I think we’re going in circles —

CStrings fields in a Structure are NOT like Strings.

CStrings in a structure are EITHER a bare pointer (4 bytes in 32-bit, or 8 bytes in 64-bit), OR, if declared with a size, they are an array of bytes of that size, with the last byte expected to be a null byte.

There isn’t any portion of a CString in a Structure that contains a place to store its allocated size, or the current length of the string. Otherwise, it wouldn’t be a CString.

It MUST be that way, otherwise you would not be able to pass CStrings to a DLL as a char* or as a char [ ] — which is what you MUST be able to do.

It’s easy to see this is the case by dumping the bytes of the structure.