2013-12-09 35 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點到堆棧中分配的數據,這將被回收/在運行時重用......