Приручаем Borland C++ к crtdll.dll

Eugene Kotlyarov [ek@oris.ru]ek@oris.ru

Чтобы скомпилировать программу под Borland C/C++, которая будет использовать crtdll.dll нужно:

  1. создать библиотеку импорта crtdll.dll
    implib crtdll.lib crtdll.dll
  2. скомпилировать основную программу, причем нужно указать опции:
  3. слинковать dll, чтобы она использовала crtdll
    tlink32 -Tpd -x xxx.obj, xxx.dll,, import32.lib crtdll.lib

Проблемы могут возникнуть, если программа написана на C++, а не на C. В таком случае некоторые функции (например, strchr) объявляются как extern c++, соответственно их имена в obj-файле получаются mangled (типа strchr$qpci) и не могут линковаться. Решается это путем написания своего .h файла и объявления этих функций в нем, как extern "C".

Поскольку даже при #include <windows.h> в BC подключаются все rtl-ные .h-файлы, нужно добавить соответствующий #define, чтобы не подключились стандартные хедеры. Например для string.h - #define __STRING_H. Этот .h-файл нужно подключать перед всеми остальными. Подобный заголовочный файл может выглядеть следующим образом:

// crtdll.h
#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned size_t;

/* stdio.h */
int sprintf(char *buffer, const char *format, ...);

/* stdlib.h (alloc.h) */
void *malloc(size_t size);
void *realloc(void *block, size_t size);
void free(void *block);

/* mem.h */
void *memcpy(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);

/* string.h */
int strncmp(const char *s1, const char *s2, size_t maxlen);
char *strchr(char *s, int c);
char *strrchr(char *s, int c);

/* not include standard string.h */
#define __STRING_H

#ifdef __cplusplus
};
#endif

Еще одна проблема в том, что такая функция, как wsprintf в import32.lib объявлена с подчеркиванием и соответственно при компиляции с опцией /u- линковаться не будет. Решение - либо использовать sprintf из crtdll.dll, либо линковать напрямую к user32.lib. Для этого нужно создать аналогично user32.lib -

implib user32.lib user32.dll
и добавить user32.lib в строку запуска tlink32

Более удобный, правильный и совместимый вариант - объявить прототипы нужных RTL функций внутри своего пространства имен, например:

#ifdef __cplusplus
namespace crt {
extern "C" {
#endif

typedef unsigned size_t;
int strncmp(const char *s1, const char *s2, size_t  maxlen);
char *strchr(char *s, int c);
char *strrchr(char *s, int c);

#ifdef __cplusplus
}
}
#endif

В результате исчезают проблемы с совпадением имен, однако для использования функций объявленных extern "C++" нужно непосредственно указывать namespace, т.е. вместо strchr нужно писать crt::strchr.

Если этой информации Вам не хватает, то "типичный" пример использования crtdll.dll можно посмотреть в исходниках плагина QuakePAK.


 
04.04.2000
Rev. 24.06.2000
наверх