Заметки по работе с 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;
}
Для изменения метаданных DLL в Qt с использованием qmake, вам нужно использовать макросы VERSION, VERSION_INFO и RC_FILE. В файле .pro вы можете установить версию DLL через макрос VERSION, например: VERSION = 1.2.3. Для добавления более детальной информации, такой как имя продукта, описание, и т.д., используйте макрос VERSION_INFO и создайте файл ресурсов .rc (для Windows). В файле .rc вы определяете необходимые ресурсы, включая информацию о версии, используя структуру VS_VERSION_INFO. Затем, в вашем файле .pro укажите этот файл через макрос RC_FILE.
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,3,4
PRODUCTVERSION 1,2,3,4
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "MyCompany"
VALUE "FileDescription", "My Awesome DLL"
VALUE "FileVersion", "1.2.3.4"
VALUE "InternalName", "my_awesome_dll"
VALUE "LegalCopyright", "Copyright (C) 2024 MyCompany"
VALUE "OriginalFilename", "my_awesome_dll.dll"
VALUE "ProductName", "MyAwesomeLibrary"
VALUE "ProductVersion", "1.2.3.4"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
* Добавьте в *.pro файл:
VERSION = 1.2.3.4 VERSION_INFO_RC = version.rc RC_FILE = $$VERSION_INFO_RC
Пояснения:
В файле version.rc: