Что происходит, в основном это. Каждый фрагмент кода, скомпилированный отдельно (DLL или EXE), содержит свой собственный код, который выделяет память из системы и управляет ею, называется менеджером памяти. Проще говоря, когда этот фрагмент кода инициализируется, он выделяет большой блок памяти из системы. Позже, когда он делает GetMem или выделяет строки, массивы и так далее, менеджер памяти отмечает части этого большого блока, как он используется. Когда вы FreeMem/deallocate их, они помечены как неиспользуемые.
Теперь представьте, что у вас есть EXE и DLL, как со своими менеджерами памяти. EXE вызывает DLL-процедуру, DLL выделяет строку (PChar), тем самым выделяя часть своего большого блока памяти в качестве используемого. Затем он возвращает указатель на EXE, который использует его, а затем решает освободить. EXE дает указатель на свой собственный менеджер памяти и просит освободить его, но его даже не от огромного блока памяти EXE!Менеджер памяти EXE не знает, как «освободить» чужую память.
Вот почему вам нужно вызвать DllReleaseString(), возвращая при этом заимствованный указатель памяти на DLL и позволяя его встроенному диспетчеру внутренней памяти.
Теперь, что делают Менеджеры Памяти памяти, они соединяются друг с другом. Менеджер памяти в вашем DLL и диспетчере памяти в вашем EXE умеет разговаривать друг с другом, а когда вы указываете память DLL на менеджер памяти EXE, он понимает, что это из DLL и позволяет диспетчеру памяти DLL освободить его. Конечно, это возможно только тогда, когда BOTH DLL и EXE-серверы памяти построены из одного и того же кода менеджера памяти (иначе они не узнают друг друга!). Если ваш менеджер памяти DLL является общим, а ваш менеджер памяти EXE - это что-то еще, менеджер памяти DLL не сможет «спросить» EXE о выпуске памяти, и диспетчер памяти EXE даже не попытается (он не используется).
Поэтому, если вы хотите, чтобы ваша библиотека была универсальной, вы не можете полагаться на менеджеров памяти, разговаривающих друг с другом. Ваша DLL может использоваться с EXE или DLL, которые полагаются на другой менеджер памяти, возможно, написанный на другом языке. Совместное использование диспетчеров памяти возможно только тогда, когда вы контролируете все части своего проекта и можете явно настроить один и тот же менеджер во всем мире.
+1. Я действительно надеялся, что смогу вернуть PChar, но ваш аргумент кажется твердым. – Ampere
Вы можете применять такие же действия, как и COM. Если вы не используете COM-функции для освобождения памяти, выделенной COM, вы получаете ошибки. Вот как это «принуждает» вещи. Вы также можете использовать свой собственный код управления памятью DLL таким же образом. Нет никакой опасности в распределении и возврате указателей из вашей DLL. Существует риск того, что EXE будет неправильно использовать память, но всегда есть риск, что в другом коде будут ошибки. Это не твоя проблема. –
Проблема в том, что те языки, которые не знают о указателях, могут передавать буферы, и эти буферы автоматически управляются. IMHO намного лучше разрешить вызывающей программе управлять своей памятью и просто манипулировать уже выделенным буфером, а не выделять ее и просить звонящего освободить ее, особенно если вы не можете принудительно использовать свои типы данных onw, такие как COM. У кода могут быть ошибки, но некоторые методы более склонны вводить ошибки, чем другие. – 2010-08-12 07:19:53