2013-12-09 3 views
0

Я работаю над расширением Thunderbird, которое будет называть существующий код C# через посредника C++/CLR. Я попал в ловушку, которую можно воспроизвести, используя только 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; 
} 

Если я вернусь р, я получаю "Hello World" назад. Если я вернусь, я получаю мусор или зависание. Проверка 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, ул определяется как объект типа 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

Не пытайтесь Interop с кодом C до тех пор, пока вы написали правильный код C первого. Возвращаемые указатели на локальные переменные - это неопределенное поведение. –

ответ

3

Вы не можете вернуть указатель на переменную стека из функции в C - как только функция вернется, эта часть стека будет исправлена, а указатель больше недействителен.

Альтернативы, которые действительны, включают использование статического глобального (предостережение, это не поточно-безопасное) или функция, выделяющая новую память из кучи, возвращает указатель на это и предоставляет соответствующую функцию для клиентов, которые будут использоваться для освободите память, когда они будут сделаны с ней.

+0

Дох. Я знал это однажды, но я слишком долго был на C# :) Спасибо, что выделение новой памяти заработало. –

3

Если я вернусь, я получаю «Hello World» назад. Если я вернусь, я получаю мусор или повесить. Проверка p и q в отладчике показывает, что оба они содержат те же данные.

Причиной такого поведения является то, что p указывает на строку постоянной, которая хранится в определенном месте в сегменте данных библиотеки DLL - это адрес остается действительным до тех пор, пока загружается/очерчен DLL.

Однако q указывает на стек выделенные данные, которые будут утилизированных/повторно во время выполнения ...