I'm working on a Thunderbird extension that will call existing C# code via a C++/CLR intermediary. I've hit a snag that can be reproduced using just the C++/CLR DLL, or a straight C DLL.
My function is
__declspec(dllexport)char* strTest2()
{
char *p = "Hello World";
char buffer[200];
char *q = buffer;
strcpy_s(q,200,p);
return p;
}
If I return p, I get "Hello World" back. If I return q, I get garbage or a hang. Inspecting p and q in the debugger shows they both contain the same data.
I'm calling the function using this js;
Components.utils.import("resource://gre/modules/ctypes.jsm");
var lib = ctypes.open("<path to DLL>");
var getStr = lib.declare("strTest2",
ctypes.default_abi,
ctypes.char.ptr);
var str = getStr();
alert(str.readStringReplaceMalformed());
lib.close();
In the Mozilla debugger, str is identified as an object of type CData, and digging down far enough shows it's containing a string in each case, though I'm unable to see what that string is.
The docs for js-ctype say if something's referenced directly by a CData then it'll be kept alive. But it looks to me like this isn't correctly happening.
If I specify a large 'static' buffer such as
char *r = "\0....\0";
then use strcpy_s to copy the text into that buffer and return r then the string comes through. If I'm using a DLL project where it's straight C. But if I try that with the C++/CLR DLL project I need to use to be able to get at my existing C# code then attempts to write to the hardcoded buffer cause the program to crash.
So there's three ways I see of going forward;
- get runtime-created strings to persist on switching back from C++/CLR to js-ctypes,
- get C++/CLR to allow me to alter a static buffer- without that causing problems with multiple instances,
- get the JS to provide a buffer that C++/CLR can populate.
Does anyone know how to get one of those to work?
You can't return a pointer to a stack variable from a function in C - once the function returns, that part of the stack gets reclaimed and the pointer is no longer valid.
Alternatives that are valid include using a static global (caution, this is not thread-safe) or having the function allocate new memory from the heap, return a pointer to that, and provide a corresponding function for clients to use to free the memory when they are done with it.