Требования к dll / Какие правила соблюдать при проектировании API?
В первом приближении
|
- Функции должны экспортироваться по ординалам.
- К dll должен прилагаться .h-файл с описанием функций
- Если интерфейс опубликован, то менять его нельзя.
Если нужны новые функции, исправленные, то добавляй их как новые.
|
Не возвращать указатели |
Функции, сообщения, методы и прочие структуры API не должны возвращать
указатели. Предпочитаемый вариант - использование хэндлов. Функции
(и пр.) не должны выделять внутри себя память и отдавать ее
клиентскому приложению. Память имеет право выделять только
клиентское приложение, оно же и ответственно за ее освобождение.
Пример такого подхода см. в OS/2 Toolkit. Исключением являются
функции класса malloc, DosAllocMem и пр.
|
Возможность расширять структуры в будущем
|
Структуры данных должны позволять в дальнейшем вводить новые поля.
Т.е. каждый составной тип первым полем должен иметь переменную с
информацией о размере структуры. Примеры см. в OS/2 Toolkit. При
передаче клиентом в функцию структуры (буфера) меньшей длины,
структура должна заполняться частично. Т.е. если API использовал
ранее структуру типа:
struct DemoType1 {
USHORT size;
LONG item1;
};
А потом стал использовать
struct DemoType2 {
USHORT size;
LONG item1;
PSZ item2;
};
То при передаче клиентом буфера размером sizeof(DemoType1)
должны быть заполнены поля по Item1 (включительно), несмотря
на то, что функция API может заполнить и более полную структуру.
|
Зафиксируйте выравнивание |
Если в аргументах функции передаются структуры,
то обязательно зафиксируйте выравнивание, .h файл должен содержать:
#pragma pack(4)
pack(1) может использоваться:
- только тогда когда речь идет к примеру, о структуре базы данных или сетевого пакета
- при работе с "железом" (оборудованием)
- при обмене данными с многоплатформенными "черными ящиками"
(т.е. с кодом, который также работает в Windows/Linux)
ВНИМАНИЕ: Если меняете значение pragma pack в начале .h файла,
то не забывайте вернуть дефолтное значение в конце .h файла:
#pragma pack()
|
Export by ordinals, not names |
Экспортировать надо всегда по ординалам
(чтобы старые программы работали с новыми версиями .dll).
Импортировать надо всегда по имени, а не по ординалам.
OpenWatcom, wlink.exe
Добавьте в .def на линковку dll:
EXPORTS
RegisterPluginProc @501 NONAME
если в makefile, то
export VfmParserVersion.1
Visual Age for C, v.4
option link(export, "PLINIT",,1,NONAME)
|
Простой Си |
Не используйте C++ внутри dll
|
Неожиданность |
Вызовы функций abort, exit в модулях недопустимы.
|
Параметры: char * или const char*
|
Если аргумент функции объявлен как char*, а не const char*, то этот аргумент
может быть изменен этой функцией. Ну и, собственно, в самой
функции случайно можно ошибиться и угробить строку. Для этого
const и придуман.
|
| |