Есть C# dll, предназначенная для вызовов из неуправляемого кода через COM (интерфейс и класс):
interface IFoo
{
string GetResult(string str);
}
public class Foo : IFoo
{
public string GetResult(string str)
{
string result = .... // создаем объект типа string и возвращаем его как результатreturn result;
}
}
Вопрос в том, что происходит с памятью, выделяемой внутри C#-метода. Объект string создается и возвращается в С++, где "превращается" в BSTR. Происходит глубокое копирование, или этот BSTR есть тот же адрес, что и оригинальный string? Но ведь за очистку с одной стороны отвечает GC, с другой — на стороне С++ нужно явно вызвать какую-то очистку..
В общем вопрос, как правильно вернуть строку из C# в С++, чтобы не было никаких ликов и прочих граблей...
Блок памяти, переданный по ссылке клиенту, переходит под ответственность клиента, и им должен быть освобождён. Это общее правило COM, так как сервер не может знать, когда эту память можно будет освободить. Ну а память из управляемой кучи тем более не может быть отдана в распоряжение нативного кода.
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, TopSpace, Вы писали:
JR>Блок памяти, переданный по ссылке клиенту, переходит под ответственность клиента, и им должен быть освобождён. Это общее правило COM, так как сервер не может знать, когда эту память можно будет освободить. Ну а память из управляемой кучи тем более не может быть отдана в распоряжение нативного кода.
Спасибо за ответ,
но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи.. Как все-таки правильно вернуть string из C# в C++? Получив через BSTR как-то его удалить?
Здравствуйте, TopSpace, Вы писали:
TS>Спасибо за ответ, TS>но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи..
Указатели на управляемые объекты могут уходить в неуправляемый код только когда вызывающая сторона — управляемый код. В остальных случаях память копируется рантаймом.
Здравствуйте, TopSpace, Вы писали:
TS>Спасибо за ответ, TS>но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи.. Как все-таки правильно вернуть string из C# в C++? Получив через BSTR как-то его удалить?
Да всё просто, по-моему. Вы получили копию строки в блоке неуправляемой памяти, выделенном через CoTaskMemAlloc, и должны её освободить с помощью CoTaskMemFree
Если конечно NET придерживается правил COM, но это наверняка так.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, TopSpace, Вы писали:
TS>>Спасибо за ответ, TS>>но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи..
H>Указатели на управляемые объекты могут уходить в неуправляемый код только когда вызывающая сторона — управляемый код. В остальных случаях память копируется рантаймом.
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, TopSpace, Вы писали:
TS>>Спасибо за ответ, TS>>но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи.. Как все-таки правильно вернуть string из C# в C++? Получив через BSTR как-то его удалить?
JR>Да всё просто, по-моему. Вы получили копию строки в блоке неуправляемой памяти, выделенном через CoTaskMemAlloc, и должны её освободить с помощью CoTaskMemFree
JR>Если конечно NET придерживается правил COM, но это наверняка так.
Добавил:
if (hRes == S_OK)
{
CComBSTR val = ....;
BSTR strResult = NULL;
pFoo->GetResult(val, &strResult);
CString result = strResult;
CoTaskMemFree(strResult);
...
}
Исключение Microsoft C++: ibpp_internals::ExceptionImpl по адресу 0x0012d404..
Поток 'Поток Win32' (0x170c) завершился с кодом 0 (0x0).
Draw counter ticks: 968190
HEAP[foo.exe]: Invalid Address specified to RtlFreeHeap( 00150000, 24560024 )
Здравствуйте, TopSpace, Вы писали:
TS>Здравствуйте, Jolly Roger, Вы писали:
JR>>Здравствуйте, TopSpace, Вы писали:
TS>>>Спасибо за ответ, TS>>>но что-то не улавливаю решение) Получается какое-то противоречие: должен освободить клиент (С++), но при этом в его распоряжение не отдается память из управляемой кучи.. Как все-таки правильно вернуть string из C# в C++? Получив через BSTR как-то его удалить?
JR>>Да всё просто, по-моему. Вы получили копию строки в блоке неуправляемой памяти, выделенном через CoTaskMemAlloc, и должны её освободить с помощью CoTaskMemFree
JR>>Если конечно NET придерживается правил COM, но это наверняка так.
Строки нужно освобождать через SysFreeString, а не CoTaskMemFree.