> The problem is that I want it to be usable by C programs as well, and I don't know how C handles things like this.
It doesn't. In C there is no such thing as a "string". Only buffers of characters.
So you cannot return a string in C, only the pointer to one. Where and how that
is stored is up to you.
There is no language independant standard of how to return a string from a function,
thats the reason for this whole mess. (otherwise PB could simply comply to this standard)
Basically what you need is to clearly define who allocates the string buffer and how,
and who has to free it.
There are 3 options: (well, 3 that make sense anyway)
1) The caller of the function creates the buffer and passes a pointer to it.
The good thing is it does not matter if a function is in a dll or anthing as the caller both allocates
and frees the buffer.
This is a very common way to do it in C.
The bad thing here is that the buffer size is limited (and the caller most does not know
the needed size in advance.)
For this, you would need to pass a length parameter and have a special return value
that tells that a bigger buffer is needed... all in all, more work.
2) The function allocates the string buffer, returns the pointer and forgets about it.
The caller has to free the string after using it to avoid memory leaks.
Good thing: the length problem is gone, and it is much less work.
Problem: The string must be freed the same way it was allocated. This is a bit of
a problem with PB, as PB uses HeapAlloc_() for AllocateMemory() with a private heap.
So the Dll and main program have different heaps. I know the windows memory functions are
quite forgiving about that one, so this may even work with different heaps, but it cannot be guaranteed.
Note that this is the advised way to handle it on windows (so PB does not go a weird way here),
it just is not so practical in the Dll problem.
Two solutions to that one: You can either use HeapAlloc_() yourself with a heap
like the process heap (GetProcessHeap_()), which the caller can also access to
call HeapFree(), or you can simply import the "malloc() and free()" from the C library
into PB and use these to allocate the memory. This is probably the best when
you want the Dll to be used from C as well.
Code: Select all
ImportC "msvcrt.lib"
malloc(size)
free(*memory)
EndImport
Now the Dll uses malloc() to get a buffer, put the string in and returns the pointer.
The caller simply calls free() and the memory is freed.
3) Use another String system such as the BSTR one.
This is not much different from solution 2, except that the BSTR system has its own functions to alloc/free a string.
Other than that, it is the same. The function allocates the string and the caller frees it. (SysAllocString_() / SysFreeString_())
The good point here is that some languages have native support for BSTR strings. (VB i think, and maybe also Delphi iirc)
The bad point is that it is unicode based, and if your Program/dll is ascii only,
you need to convert your strings always.
The way with the global variable in PB works, because then the string does not need to be freed.
It simply stays there until the next function uses the global variable to return a string. (returning the pointer to the global variable)
It is obviously not threadsave though.
These are the most practical solutions to this problem imho.
As you see, there is no common way of doing it, thats where all the trouble comes from.
I would go for solution 2 with the malloc() and free(). It is not so hard to do,
and especially C programmers will be quite comfortable with it
