Заметки по работе с DLL. Links:
В VS есть утилита dumpbin.exe, а в Delphi утилита TDump.exe.
> TDump.exe SM_Dll.dll > dump.txt
В заголовочном файле лежат объявления функций.
#if defined(SM_DLL_LIBRARY) #define DLL_EXP __declspec(dllexport) #define ADDCALL __stdcall #else # if defined(BUILD_APP) #define DLL_EXP __declspec(dllimport) #define ADDCALL __stdcall # else #define DLL_EXP #define ADDCALL # endif #endif DLL_EXP ret_status_t ADDCALL init(const char * fileCfg, const char * fileValues, const char * fileAppCfg, EventCallBack notifyFunc, LogCallBack logFunc, uint8_t logEna); DLL_EXP ret_status_t ADDCALL initGetCompleted(uint8_t *completed); DLL_EXP ret_status_t ADDCALL setLogEnable(uint8_t logEna); DLL_EXP ret_status_t ADDCALL deinit();
Если DLL собирается в QtCreator, то define можно объявить в *.pro файле:
DEFINES += SM_DLL_LIBRARY
В компилируемом файле *.с могут быть функции с одинаковым именем, но с разным набором входных параметров. Линкеру, собирающему несколько объектных файлов (*.о) необходимо понимать, какому вызову следует подставить ту или иную реализацию функции. Поэтому компилятор, формируя объектные файлы, "шифрует" в названии функции параметры ее вызова. Это называется - манглирование.
DLL файл, это тоже своего рода объектный файл. Поэтому внутри DLL названия функций представлены в манглированном виде.
При этом манглирование у разных компиляторов может быть различным. Если использующее DLL приложение собирается компилятором, манглирование которого отличается от манглирования компилятора, которым собиралась DLL, то импорт функции по имени не получится. Деманглирование даст не то исходное имя, которое ожидает импортировать из библиотеки программист. Но можно с помощью утилит dumpbin.exe / TDump.exe узнать как в DLL называется функция и загрузить ее по прямо по манглированному имени. Пример для Delphi:
Содержимое dll, полученное TDump.exe:
... Exports from libNT_Spectrm.dll 5 exported name(s), 5 export addresse(s). Ordinal base is 1. Sorted by Name: RVA Ord. Hint Name -------- ---- ---- ---- 0001683B 1 0000 _ZN9NT_SM_DLL10boardCountEPh ... прочие функции ...
Загрузка манглированной функции _ZN9NT_SM_DLL10boardCountEPh:
var SMDLL_GetBoardCount : function(var brdCount: Byte) : Integer; stdcall; function SMDLL_LoadDll(dllFileName: string): THandle; var lFuncNotFoundMsg : string; begin result := 0; if (dllFileName = '') or (not FileExists(dllFileName)) then begin OutputDebugString(PChar('SMDLL: Dll File not found: ' + dllFileName)); exit; end; result := LoadLibrary(PChar(dllFileName)); if result < HINSTANCE_ERROR then begin OutputDebugString(PChar('SMDLL: Can"t load Library: ' + dllFileName)); exit; end; lFuncNotFoundMsg := ''; @SMDLL_GetBoardCount := LoadDllFunc(result, '_ZN9NT_SM_DLL10boardCountEPh', lFuncNotFoundMsg); ... end
Подробнее "Using Existing DLLs"
Посмотреть название функции в неманглированном виде можно командой:
$> c++filt -n _ZN9NT_SM_DLL23appSingleLaserGetStatusEPj NT_SM_DLL::appSingleLaserGetStatus(unsigned int*)
NOTE: При использовании stdcall в манглировании используются символы @:
// 1. Вызов функции i = Func(x, y, z); // 2. Исполнение функции int Func(int a, int b, int c) { return a + b + c; }