Здравствуйте, A.Lokotkov, Вы писали:
AL>Здравствуйте, anton20vlad, Вы писали:
A>>Проблема решилась VirtualAlloc, VirtualFree. Всё красиво и тихо отрабатывает. Только вот не уверен что это правильное решение )
AL>Как именно оно решилось?
Здравствуйте, A.Lokotkov, Вы писали:
AL>Здравствуйте, anton20vlad, Вы писали:
A>>Никаких ошибок с памятью, отрабатывает как надо.
AL>Вы можете рассказать, почему Вы сделали именно так и почему оно перестало падать?
Перебирал варианты ) и сделал так. А вот насчёт почему перестало падать...думаю что решился вопрос с тем где именно и кем выделяется и высвобождается память. Вы видите какую-то ошибку в коде?
Здравствуйте, anton20vlad, Вы писали:
A>Перебирал варианты ) и сделал так. А вот насчёт почему перестало падать...думаю что решился вопрос с тем где именно и кем выделяется и высвобождается память. Вы видите какую-то ошибку в коде?
Конструктор и деструктор интерфейсного объекта на клиентской стороне теперь не вызываются. Поскольку не вызывается конструктор, для каждой stl-строки внутри интерфейсного объекта DIVA_REQUEST_INFO не создается небольшой умолчательный буфер, -- там будет NULL. Когда несконструированный интерфейсный объект с несконструированными строками внутри передается в их dll, stl почему-то не падает. Может быть, потому что, увидев NULL, аллокирует буфера в строках на стороне dll. Если это так, то после того, как Вы делаете VirtualFree на своей стороне, память, выделенная под буфера строк, никогда не будет освобождена (по-крайней мере, до выгрузки выделившей ее dll). Для такого решения необязательно делать именно VirualAlloc/VirualFree, я думаю, с тем же успехом можно было бы написать как-нибудь так:
Здравствуйте, MasterZiv, Вы писали:
>> Динамический рантайм мог бы спасти отца русской демократии MZ>у него он и так динамический. Другого не бывает в .dll.
Здравствуйте, MasterZiv, Вы писали:
MZ>g_i пишет:
>> Динамический рантайм мог бы спасти отца русской демократии
MZ>у него он и так динамический. Другого не бывает в .dll.
Да, действительно так тоже работает без ошибок. Мне всё-таки важно, чтобы память занятая строками высвобождалась. Признаюсь, что настолько глубоко я темой не владею, поэтому хочу спросить Вашего совета. Мне предложили ещё несколько способов(цитирую):
1. Отказываешься от размещения класса в стеке, вместо этого, пусть её для тебя создаёт и уничтожает библиотека(в стиле С):
Foo* foo = AllocFoo();
DoSmth(foo);
FreeFoo(foo);
2. Класс ты ж сам придумал?(Тут не совсем так...его буржуи придумали). Тогда задай для его небезопасных членов собственный алокатор. Тогда вместо wstring придётся взять basic_string<>. Словом, намаешься, но такой класс можно будет размещать даже в стеке. Это больше по С++.
3. Ещё есть одно простое решение. По идее, тебе достаточно написать (пусть и пустой) деструктор(Как я понял для класса DIVA_REQUEST_INFO). Таким образом его код будет находится в библиотеке, следовательно, и освобождаться память будет кодом библиотеки. Это только отсрочка. Так как нужно будет проследить, чтобы никто другой не работал с твоим wstring непосредственно. Правда для этого тоже можно подмутить методы-аксесоры.
Мне кажется самое простое это 3й вариант. Правда как я понимаю, память всё-равно не высвободится, так как деструктор пустой? И ещё один вопрос: для чего нужно "подмутить методы-аксесоры"? Это я недопонял.
Здравствуйте, Odi$$ey, Вы писали:
OE>Здравствуйте, MasterZiv, Вы писали:
>>> Динамический рантайм мог бы спасти отца русской демократии MZ>>у него он и так динамический. Другого не бывает в .dll.
OE>/MT для при сборке .dll уже отменили?
В продолжение темы с пустым деструктором и про "подмутить методы аксесоры". Судя по всему, их таки надо подмутить так как ошибка никуда не делась...Правда я не понимаю что имеется в виду.
Здравствуйте, Аноним, Вы писали:
А>[/list]
А>Мне кажется самое простое это 3й вариант. Правда как я понимаю, память всё-равно не высвободится, так как деструктор пустой? И ещё один вопрос: для чего нужно "подмутить методы-аксесоры"? Это я недопонял.
Я не понял, что коллеги имели в виду. Для того, чтобы все работало правильно, у авторов из DLL должны были быть экспортированы конструктор и деструктор интерфейсного объекта DIVA_REQUEST_INFO. Тогда проблем бы не было вообще (ну, вернее, были бы, но они решались бы путем добровольного запрета на доступ к строковым членам из клиента по записи), поскольку при любом способе создания объекта DIVA_REQUEST_INFO на клиентской стороне (по new, на стеке или статически) буферы stl-строк и прочая создавались бы и освобождались в их DLL.
Авторы DLL этого не сделали, поэтому конструктор и деструктор DIVA_REQUEST_INFO, сгенерированные компилятором, всегда вызываются на клиентской стороне и, конструктор, как минимум, создает в каждой stl-строке маленький исходный буфер. А это значит, что у проблемы нет корректного решения, есть только костыли разной степени кривизны типа такого (эскиз, предполагающий, что обертка для delphi также расположена в dll):
// Используется для всех запросов к той DLL
// При необходимости использования из разных потоков
// дооснастить крит.секцией.static DIVA_REQUEST_INFO* globalRequestor = NULL;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
globalRequestor = (DIVA_REQUEST_INFO*) new [sizeof(DIVA_REQUEST_INFO) + sizeof(__int64) - 1];
// В этом случае все аллокации stl-строк будут всегда выполняться на стороне их DLL,
// и память не потечет.if(globalRequestor != NULL)
memset(globalRequestor, 0, (sizeof(DIVA_REQUEST_INFO) + sizeof(__int64) - 1));
}
break;
case DLL_PROCESS_DETACH:
{
// в принципе, не очень-то и нужноif(globalRequestor != NULL)
delete [] globalRequestor;
}
break;
}
return TRUE;
}
DIVA_STATUS DLL_SPEC WDIVA_getRequestInfo(RequestInfo *reqInf, int reqNum)
{
// передаем глобальный интерфейсный объект
DIVA_STATUS cr = DIVA_getRequestInfo (reqNum, globalRequestor);
//...return cr;
}
Здравствуйте, MasterZiv, Вы писали:
MZ>g_i пишет:
>> MZ>у него он и так динамический. Другого не бывает в .dll. >> >> Судя по описанию проблемы, это не так.
MZ>Тем хуже для него. Так может только в этом и проблема ? MZ>А вообще, какой рантайм "Дельфа" использует ?
Тут до Delphi еще далеко, он CPP не может заставить работать.
Здравствуйте, anton20vlad, Вы писали:
A>Здравствуйте, Odi$$ey, Вы писали:
OE>>Здравствуйте, MasterZiv, Вы писали:
>>>> Динамический рантайм мог бы спасти отца русской демократии MZ>>>у него он и так динамический. Другого не бывает в .dll.
OE>>/MT для при сборке .dll уже отменили?
A>/MT при сборке имеется.
У вас имеется dll. С каким рантаймом собрана эта dll? Со статическим? Заказать пересборку с динамическим можно?
Важно чтобы оба модуля (клиент и длл) использовали один тип рантайма. Затем важно чтобы они могли работать с одной и той-же версией рантайм dll.
Сам себя запутал.
DLL собираешь ты. Используй динамический рантайм если клиент сможет использовать динамический рантайм.
Если нет — не используй string. Вообще, откуда проблема с деструктором std::string если ты утверждаешь, что допустимы только сишные экспорты?
Здравствуйте, anton20vlad, Вы писали:
A>Спасибо, за ответ. У меня нет вариантов — так сваяли библиотеку апишную буржуи. Я честно говоря уже все мозги сломал как решить эту проблему? Да я понимаю что оно в разных местах выделяется и высвобождается, но в этом конкретном случае что нужно сделать чтобы избавится от ошибки?
Я правильно понимаю, что, проблема состоит только в том, что приложение валится, когда дело доходит до разрушения локальной DIVA_REQUEST_INFO requestInfo; внутри WDIVA_getRequestInfo()?
Ваша обертка и буржуйский код используют совместимые версии STL, т.е. строки в структуре requestInfo инициализирются корректно?
Если все так, то можно так попробовать проблему решить:
Похожее решение тут уже предлагали, только там буфер был локальный, а тут статический. Смысл в статическом буфере в том, что память под строки не будет утекать.
Если у вас приложение многопоточное, то вместо простого глобального статического буфера можно использовать буфер из TLS.
g_i пишет:
> У вас имеется dll. С каким рантаймом собрана эта dll? Со статическим? > Заказать пересборку с динамическим можно?
Если какая-то DLL собрана со статическим рантаймом, то её, за исключением очень
редких случаев очень грамотного проектирования интерфейсов этой .DLL,
которые в жизни почти не встречаются, и к числу которых данная .DLL явно НЕ
относится, МОЖНО СРАЗУ ЖЕ ВЫКИНУТЬ НА ПОМОЙКУ, как непригодную к использованию.
Danchik пишет:
> Тут до Delphi еще далеко, он CPP не может заставить работать.
Да я вообще не очень понимаю, что он там делать собирается,
как он это дело в дельфу вставит ? Легче наверное новый язык
программирования изучить, чем это вот сделать.
Здравствуйте, MasterZiv, Вы писали:
MZ>Если какая-то DLL собрана со статическим рантаймом, то её, за исключением очень MZ>редких случаев очень грамотного проектирования интерфейсов этой .DLL, MZ>которые в жизни почти не встречаются, и к числу которых данная .DLL явно НЕ MZ>относится, МОЖНО СРАЗУ ЖЕ ВЫКИНУТЬ НА ПОМОЙКУ, как непригодную к использованию.