char *从C DLL返回到js-ctypes时丢失

时间:2013-12-09 16:46:25

标签: c++ dll thunderbird thunderbird-addon jsctypes

我正在开发一个Thunderbird扩展,它将通过C ++ / CLR中介调用现有的C#代码。我遇到了一个只能使用C ++ / CLR DLL或直接C DLL重现的障碍。

我的功能是

 __declspec(dllexport)char* strTest2()
 {
    char *p = "Hello World";
    char buffer[200];
    char *q = buffer;

    strcpy_s(q,200,p);

    return p;
 }

如果我返回p,我会回到“Hello World”。如果我返回q,我会得到垃圾或挂起。检查调试器中的p和q表明它们都包含相同的数据。

我正在使用这个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();   

在Mozilla调试器中,str被识别为CData类型的对象,并且挖掘得足够远,表明它在每种情况下都包含一个字符串,尽管我无法看到该字符串是什么。

js-ctype的文档说如果某个东西被CData直接引用,那么它将保持活着状态。但在我看来,这并没有正确发生。

如果我指定一个大的“静态”缓冲区,例如

 char *r = "\0....\0";

然后使用strcpy_s将文本复制到该缓冲区并返回r然后字符串通过。如果我正在使用一个直接C的DLL项目。但是如果我尝试使用C ++ / CLR DLL项目,我需要使用它来获取我现有的C#代码然后尝试写入硬编码缓冲区导致程序崩溃。

所以我看到了前进的三种方式;

  • 让运行时创建的字符串在从C ++ / CLR切换回js-ctypes时保持不变,
  • 获取C ++ / CLR以允许我更改静态缓冲区 - 而不会导致多个实例出现问题,
  • 让JS提供C ++ / CLR可以填充的缓冲区。

有谁知道如何让其中一个工作?

2 个答案:

答案 0 :(得分:3)

你不能从C中的函数返回指向堆栈变量的指针 - 一旦函数返回,堆栈的那部分就会被回收并且指针不再有效。

有效的替代方法包括使用静态全局(注意,这不是线程安全的)或让函数从堆中分配新内存,返回指向它的指针,并为客户端提供相应的函数来释放完成它后的记忆。

答案 1 :(得分:3)

  

如果我返回p,我会回到“Hello World”。如果我回q,我会得到垃圾   或挂起。检查调试器中的p和q显示它们都包含   相同的数据。

此行为的原因是p指向一个字符串常量,该常量存储在DLL数据段中的固定位置 - 只要DLL被加载/映射,该地址就会保持有效。

但是,q指向堆栈分配的数据,这些数据将在运行时回收/重用...