Correct idiom for passing CString via structure?

You won’t use a CString for a pointer, instead you use a Ptr and then convert to memoryblock.
Otherwise it won’t work, i my experience. We’ve used MANY structures, and what your saying there is not something known to me to be working.

You say that the CString ends where the NULL byte is, but Xojo doesn’t expect it that way if you don’t delcare the size in the structure. The null byte is only telling xojo to stop reading the string must have a length (* bytes) otherwise it will keep reading untill a null byte is found… so you’d NOT declare this a CString, instead use a ptr and convert from there.

v As CString is the same as a char* v, a pointer to an Null terminated array of Chars

v As CString * 20 is the same as char v[20], where you’re embedding a fixed length array of Chars in the structure

They are totally different and each is perfectly valid on their own, Xojo works fine with both, however, in Xojo, the first method is very buggy when in a structure, this is a known bug and is a compiler issue. When you’re using certain windows apis you have to use the 1st method in certain circumstances, there is no way around it or the structure you send across will be totally incomprehensible by the windows api.

I’d hazard a guess that Xojo doesn’t have the expertise to analyse and correct the problem as I’d have hoped that something so fundamentally wrong would have been fixed by now, but I guess if @Geoff_Perlman doesn’t encounter it on a daily basis then it not going to bug him enough to have it fixed no matter what their line on it “not having a big enough impact surface” is, when you can’t rely on something as fundamental as a CString or a Structure and you’d rather rename things, then something is seriously wrong with the ethos of the product and the company.

PS. On reflection, some of the stuff I’ve written in this thread is patently wrong, I was getting crossed wires due to the inconsistency with Xojo around this issue and after restarting my machine, I’m no longer able to work around this issue with Structures containing CStrings, it is random whether it works or not which was leading me to incorrect conclusions.

1 Like

Good discussion all. For what it’s worth, quite a few of the weird issues you are reporting (wrong project running, same project behaving differently etc.) are ones I’ve never seen running the IDE on macOS. I think the macOS IDE is the “best” version if you want stability and a (more) bug free experience. Not sure if this is Xojo’s fault or Microsoft or what…

1 Like

Hi @Stephen_Greenfield,

I wrote a fairly lengthy book on Windows API Declares (Books), and some of the general trends that I use for structures with API DLL’s are:

  1. Separate 64-bit from 32-bit DLL calls
  2. Separate Unicode from ANSI calls
  3. Typically use CStrings and WStrings in Structures
  4. Use strings as input in a method, and then separate CStrings and WStrings in the method
  5. When trying to figure out structures, I typically use a MemoryBlock to determine Xojo structure spacing, which is sometimes different than Windows Structure API Spacing

I am sure there are other generalities that I am missing, and this is a good start. @anon20074439 has been very helpful at tracking down bugs and providing good information to Xojo to reproduce the issues.

Most Declares seem to work fairly well with 32-bit programs, and there are errors when Xojo became 64-bit compatible, as Xojo offsets and spacer sizes are sometimes needed with no indication as to why.

To minimize Xojo Declare errors, I typically write a program in C/C++ and then convert it to Xojo, which has saved a few new grey hairs from being created :slight_smile:

I am sure that you will like the speed and options that Declares provide, and there is a fairly steep learning curve. All the best in your journey!

2 Likes

@Eugene_Dakin — great list! I will check out your book!

Presently, I am already doing every one of your suggestions. I can’t recall who made the excellent suggestion (a couple months back) to encase the actual declare call in a Xojo method, passing a String in, handling it within the call, and converting CString back to String for return values — but it has really helped to keep a nice bright line between my DLL and Xojo.

Note that any Xojo-wrapped function where I expect to pass a CString parameter to my C-style DLL will (and DOES) work if the Xojo wrapper method is declared with CString and I pass a String to that Xojo function’s parameter. Clearly, Xojo got that right: if Xojo is going to provide an automatic String-to-CString calling parameter conversion, it already knows to make a temporary allocation, copy the String’s contents, and hold that allocation for the scope of the call. That’s something that I (unrealistically) EXPECTED was also going to work for assigning a String into a CString structure field — but apparently doesn’t.

It’s important for people reading this discussion to keep in mind that I am going back-and-forth between my OWN C++ DLL. So I am in control of every aspect of the binary API once execution of the declared call leaves Xojo. It’s very easy at the DLL end to see what the structure is when it arrives from Xojo.

I can’t comment on the DLL calling process involving Windows API calls — it may be the exact same situation — but I’m not working with that at the moment.

I appreciate the extraordinary expertise of the Xojo community. This process would be more difficult and time consuming without the kind assistance of skilled Xojo users such as yourself and others.

1 Like

@anon20074439

Thanks — I think you’ve stated this exactly right and succinctly. I just wish there was some Xojo docs on CString that similarly explained this, so it wouldn’t be up to each user to figure this out.

Try this: assign the String to a Var CString and then use THAT Var yo assign into the structure’s CString field, and the problem WILL go away.

@DerkJ — I wonder if it’s possible that you’ve worked with Xojo so long that the behavior has evolved over time. Because the way @anon20074439 and I are describing the process is exactly correct for this release of Xojo on Windows.

What @DerkJ describes sounds like RECEIVING data back from a Declare, not SENDING data to it.

@DerkJ – As @Tim_Hare hinted at, most of what I’ve been discussing is about passing the Structure out of Xojo and into my C++ DLL.

However, it totally works correctly going the other way: my C++ DLL has a definition for a “return_value” structure:

C++ structure definition in DLL code:

struct return_value
{
	char* fReturnValueString;
	int64_t fReturnValueInt;
	int64_t fReturnValueBool;
};

Structure definition in Xojo IDE:

Structure return_value
  fReturnValueString As CString
  fReturnValueInt As Int64
  fReturnValueBool As Int64
End Structure

The return structure is defined and allocated in Xojo, then passed into the Xojo wrapper function as:

ByRef retVal as MyApp.return_value

The DLL receives the structure as:

return_value* retVal

And the return value is allocated and stored in the return structure like so:

std::string myCPPString = "some text to return";
retVal->fReturnValueString = (char*)malloc(myCPPString.size() + 1); // +1 to account for null byte
strcpy(retVal->fReturnValueString, myCPPString.c_str());

So the returned CString is ALLOCATED in the C++ code, the contents are copied into the allocated buffer, and then the allocated pointer is returned via the Structure. The Xojo wrapper function might return a Xojo String, but all that’s needed is simply to:

return retVal.fReturnValueString

…and Xojo will take the pointer to the DLL-allocated CString in the returned structure and convert it to a Xojo String automatically.

THIS ALL WORKS PERFECTLY.

1 Like

Ah that’s true. Must have misunderstood that. Could it be that you must retain (differently) the sturcture for it work? (I mean for the non working code you had)

Such a guess would be hazardous indeed. :slight_smile: I can’t think of a single thing we have ever not done because we felt we didn’t have the internal expertise. Just as one example, when Joe Ranieri left, there were those that thought work on the compiler would grind to a halt. History has shown otherwise. One thing our team all have in common from administration to marketing to engineering to customer service is a desire to not just get the job done but to learn whatever needs to be learned in order to do so. It’s also the reason that I think every one of them would say their team is the best one they’ve ever been a part of.

Contrary to what you may think, I don’t dictate what bugs get fixed. Oh I occasionally run across bugs that I bring to the attention of someone on the engineering team (usually Travis) but that’s the extent of it. Because I primarily use an M1 MacBook Pro, I’ve discovered a few M1-specific bugs when debugging code. But just like all of you, I create a bug report in Feedback and for the most part, allow the system to work as we have designed it to do so.

It’s a dangerous thing when leaders start circumventing the system for their own personal gain.

At Xojo, Inc., our corporate philosophy is to hire smart, motivated people who need little in the way of supervision so that we can trust them to do good work. I have no desire to micromanage people and wouldn’t tolerate anyone for whom I had to do so.

First rule of hiring: hire people that are smarter than you at the job for which you are hiring them.

4 Likes

It’s a dangerous thing when leaders start circumventing the system for their own personal gain.

I’m the co-owner of a software company (for exactly forty years as of yesterday!) and I’m sure many engineer / entrepreneurs here are, too. Most of us recognize there’s day-today process — and there’s leadership. We’ve all had times when we’ve had to grab the wheel to set the ship on a better, safer course. That intervention is for the gain of all those employed in the team we lead.

When a customer with the experience and expertise of @anon20074439 suggests that The Process has routinely ignored important issues for years, it’s usually a good investment to investigate that claim (if you haven’t already done so).

That said we all understand that small businesses have very limited resources. So some issues by necessity must be left to wither in the bit-rot hell of bug-collecting databases.

This forum gives voice to those unaddressed issues. It would be helpful to Xojo newbies like myself to know what are the top unaddressed issues, from the perspective of the Xojo faithful. I’m guessing there’s already a thread like that? (vs the Feedback database)

Almost. You’re leaking the DLL-allocated strings. You said this is a brief process that terminates quickly, so that’s not a real problem for you, but just be aware.

Typically, the WIN API declares will have you call it once with no input and it will respond with the number of bytes you need to allocate. Then you allocate a block of memory and call it again. The CString will be written into the end of that block, giving you full control over memory management.

Thanks — I would NEVER leave memory leaking with: 1) any one else’s API, and certainly not Windows’ win32 API; 2) any API that would be persistently operating over any significant number of allocations or over a long period of time.

Although it would be trivial to make a DLL method to call free on that pointer, there’s almost no reason to do that from a performance or security perspective.

And I can’t really use C++11 automatic memory management, because the struct passed in (that contains the char*) isn’t owned by the DLL, so it won’t go out of scope, and even if it did, it would be at the wrong time — possibly before that char* was copied to the Xojo String.

HOWEVER — now that I think about it, a DLL typically doesn’t have a deinitialization called, because it might not be unloaded. So I guess it WOULD make sense to release the allocations from within the Xojo DLL wrapper function.

Thanks for keeping me honest!