2013-12-09 36 views
0

我正在研究Thunderbird扩展,它将通过C++/CLR中介调用现有的C#代码。我碰到了一个可以使用C++/CLR DLL或直C DLL复制的障碍。char *在从C DLL返回时丢失到js-ctypes

我的功能是

__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将文本复制到缓冲区,并返回,则成为该字符串来通过。如果我正在使用一个DLL项目,它是直的C.但是如果我尝试使用C++/CLR DLL项目,我需要使用能够获取我现有的C#代码,然后尝试写入硬编码缓冲区导致程序坠毁。

因此,我有三种方法可以看到未来;

  • GET运行时创建的字符串坚持从C++/CLR到JS-ctypes的转回,
  • 获得C++/CLR,让我改变静态buffer-不具有多个实例是造成问题,
  • 获取JS以提供C++/CLR可以填充的缓冲区。

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

+2

不要试图用C代码互操作,直到你第一次写有效的C代码。返回指向局部变量的指针是未定义的行为。 –

回答

3

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

有效的替代方法包括使用静态全局(谨慎,这不是线程安全的)或让函数从堆中分配新内存,返回指向该内存的指针,并提供相应的函数供客户端使用当他们完成它时释放内存。

+0

Doh。我知道有一次,但我已经在C#中太久了:)谢谢 - 分配新内存使它工作。 –

3

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

这样做的原因行为是p指向一个串常数,它是存储在DLL的数据段内的一个固定的位置 - 作为DLL被加载/映射此地址仍然只要有效。

然而,q点到堆栈中分配的数据,这将被回收/在运行时重用......