Я работаю над расширением Thunderbird, которое будет вызывать существующий код C # через посредника C ++ / CLR. Я столкнулся с проблемой, которую можно воспроизвести, используя только 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, после чего строка пройдет. Если я использую проект DLL с прямым C, но если я пытаюсь сделать это с проектом C ++ / CLR DLL, мне нужно использовать, чтобы получить доступ к моему существующему C # -коду, тогда попытки записи в жестко закодированный буфер вызывают программу врезаться
Так что я вижу три пути продвижения вперед;
Кто-нибудь знает, как заставить одного из них работать?
Вы не можете вернуть указатель на переменную стека из функции в C — как только функция вернется, эта часть стека будет возвращена, и указатель больше не действителен.
Допустимые альтернативы включают в себя использование статического глобального (осторожно, это не поточно-ориентированного) или наличие функции, выделяющей новую память из кучи, возвращающей указатель на нее и предоставляющей клиентам соответствующую функцию для использования при освобождении памяти, когда они сделали с этим.
Если я верну p, я получу «Hello World» обратно. Если я вернусь д, я получаю мусор
или зависание Проверка p и q в отладчике показывает, что они оба содержат
одни и те же данные.
Причиной такого поведения является то, что p
указывает на строковую константу, которая хранится в фиксированном месте в сегменте данных DLL — этот адрес остается действительным, пока DLL загружена / сопоставлена.
Тем не мение, q
указывает на стек выделенных данных, которые будут исправлены / повторно использованы во время выполнения …