0

我正在开发一个 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 可以填充的缓冲区。

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

4

2 回答 2

3

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

有效的替代方案包括使用静态全局(注意,这不是线程安全的)或让函数从堆中分配新内存,返回指向该内存的指针,并为客户端提供相应的函数以在以下情况下释放内存他们已经完成了。

于 2013-12-09T16:54:10.577 回答
3

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

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

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

于 2013-12-09T17:45:07.150 回答