【问题标题】:char* gets lost on return from C DLL to js-ctypeschar* 在从 C DLL 返回到 js-ctypes 时丢失
【发布时间】:2013-12-26 21:00:36
【问题描述】:

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

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

【问题讨论】:

  • 在您首先编写有效的 C 代码之前,不要尝试与 C 代码互操作。返回指向局部变量的指针是未定义的行为。

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


【解决方案1】:

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

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

【讨论】:

  • Doh。我知道有一次,但我在 C# 中的时间太长了 :) 谢谢 - 分配新内存让它工作了。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2012-02-14
    相关资源
    最近更新 更多