Вопрос по windows, unix, dll – C Runtime объекты, границы DLL

6

Каков наилучший способ разработки C API для dll, который решает проблему передачи «объектов»? которые зависят от времени выполнения C (FILE *, указатель, возвращаемый malloc и т. д.). Например, если две библиотеки DLL связаны с другой версией среды выполнения, я понимаю, что вы не можете безопасно передать ФАЙЛ * из одной библиотеки DLL в другую.

Является ли единственным решением использовать Windows-зависимый API (который гарантированно работает через DLL)? C API уже существует и является зрелым, но в основном он был разработан на основе Unix POV (и, конечно, все еще должен работать на Unix).

Ваш Ответ

4   ответа
2

Обычные методы для таких вещей в C:

Design the modules API to simply not require CRT objects. Get stuff passed accross in raw C types - i.e. get the consumer to load the file and simply pass you the pointer. Or, get the consumer to pass a fully qualified file name, that is opened , read, and closed, internally.

An approach used by other c modules, the MS cabinet SD and parts of the OpenSSL library iirc come to mind, get the consuming application to pass in pointers to functions to the initialization function. So, any API you pass a FILE* to would at some point during initialization have taken a pointer to a struct with function pointers matching the signatures of fread, fopen etc. When dealing with the external FILE*s the dll always uses the passed in functions rather than the CRT functions.

С помощью некоторых простых приемов, подобных этому, вы можете сделать свой интерфейс DLL C полностью независимым от CRT хостов - или фактически потребовать, чтобы хост вообще был написан на C или C ++.

0

поскольку структура FILE * принадлежит до одной среды выполнения в системе Windows.

Но если вы напишете небольшую оболочку интерфейса, то все готово и это на самом деле не помешает.

stdcall IFile* IFileFactory(const char* filename, const char* mode);

class IFile {

  virtual fwrite(...) = 0;
  virtual fread(...) = 0;

  virtual delete() = 0; 
}

Это безопасно, чтобы быть переданным через границы dll всюду и не действительно причиняет боль.

П.С .: Будьте осторожны, если вы начинаете бросать исключения через границы dll. Это будет работать тихо, если вы выполните некоторые настройки в ОС Windows, но не получится в других.

1

Учитывая следующее в Windows: у вас есть две библиотеки DLL, каждая из которых статически связана с двумя различными версиями стандартных библиотек C / C ++.

В этом случае не следует передавать указатели на структуры, созданные стандартной библиотекой C / C ++ в одной DLL, в другую. Причина в том, что эти структурыmay различаться между двумя реализациями стандартной библиотеки C / C ++.

Другая вещь, которую вы не должны делать, это освободить указатель, выделенный new или malloc, из одной DLL, которая была выделена в другой. Менеджер кучи также может быть реализован по-разному.

Обратите внимание, что вы можете использовать указатели между библиотеками DLL - они просто указывают на память. Это проблема бесплатна.

Теперь вы можете обнаружить, что это работает, но если это так, то вам просто повезло. Это может вызвать проблемы в будущем.

Одним из возможных решений вашей проблемы является динамическая связь сЭЛТ, Например, вы можете динамически ссылаться на MSVCRT.DLL. Таким образом, ваши DLL всегда будут использовать один и тот же CRT.

Обратите внимание, я предполагаю, что не рекомендуется передавать структуры данных CRT между DLL. Возможно, вы захотите посмотреть, сможете ли вы учесть вещи лучше.

Обратите внимание, я не эксперт по Linux / Unix - но у вас будут такие же проблемы и в этих ОС.

Error: User Rate Limit Exceeded David Cournapeau
Error: User Rate Limit Exceeded David Cournapeau
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded David Cournapeau
0

обход CRT внутри с использованием чистого Win32 API поможет вам на полпути. Другая половина удостоверяется, что пользователь DLL использует соответствующие функции Win32 API. Это сделает ваш API менее переносимым как в использовании, так и в документации. Кроме того, даже если вы пойдете по этому пути с распределением памяти, когда функции CRT и функции Win32 имеют дело с void *, у вас все еще есть проблемы с файловыми ресурсами - Win32 API использует дескрипторы и ничего не знает о структуре FILE.

Я не совсем уверен, каковы ограничения FILE *, но я предполагаю, что проблема та же, что и при распределении CRT между модулями. MSVCRT использует Win32 для обработки файловых операций, и основной дескриптор файла можно использовать из каждого модуля в одном и том же процессе. Что может не сработать, так это закрытие файла, который был открыт другим модулем, что предполагает освобождение структуры FILE на возможно другой CRT.

Что бы я сделал, если изменение API все еще является опцией, это экспортные функции очистки для любого возможного "объекта" созданный в DLL. Эти функции очистки будут обрабатывать удаление данного объекта так, как оно было создано в этой DLL. Это также сделает DLL абсолютно переносимой с точки зрения использования. Единственное беспокойство, которое у вас возникнет, - это убедиться, что пользователь DLL действительно использует ваши функции очистки, а не обычные функции CRT. Это можно сделать, используя несколько приемов, которые заслуживают другого вопроса ...

Похожие вопросы