There is a main program:

#define BUILD_DLL #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <windows.h> #include <ctype.h> #include <string.h> // Структура листа struct listlight { char MD5[33]; // MD5 struct listlight* right; // Правый ребенок }; // Структура листа struct list { struct listlight* first; }; // Глобальные переменные char tmp[33]; HINSTANCE dllp; //Генератор рандомных md5 сумм void RadndomMD5(){ unsigned char i, j; srand(time(NULL)); for (i = 0; i < 32; i++) { j = (rand()%(17)); if (j == 0) tmp[i] = '0'; else if (j == 1) tmp[i] = '1'; else if (j == 2) tmp[i] = '2'; else if (j == 3) tmp[i] = '3'; else if (j == 4) tmp[i] = '4'; else if (j == 5) tmp[i] = '5'; else if (j == 6) tmp[i] = '6'; else if (j == 7) tmp[i] = '7'; else if (j == 8) tmp[i] = '8'; else if (j == 9) tmp[i] = '9'; else if (j == 10) tmp[i] = 'A'; else if (j == 11) tmp[i] = 'B'; else if (j == 12) tmp[i] = 'C'; else if (j == 13) tmp[i] = 'D'; else if (j == 14) tmp[i] = 'E'; else if (j == 15) tmp[i] = 'F'; else i = 0; } } bool slm(const char *str1, const char *str2){ return (strcmp(str1, str2) == 0); } void PrintHelp(){ system("cls"); printf("Справка:\n\n"); printf("Строение: \n|основная комманда|дополнительный параметр|ключ|\n"); printf("\nОсновные комманды: \n"); printf("|ADD |First/End |MD5| - добавление элемента\n"); printf("|REMOVE|First/End/VAL|MD5|true/false| - удаление элемента (true - всех элементов)\n"); printf("|CHECK | | | | - проверка на пустоту\n"); printf("|FIND | |MD5| | - происк элемента\n"); printf("|PRINT | | | | - вывод листа\n"); printf("|CLEAN | | | | - очистка листа\n"); printf("|EXIT | | | | - выход из программы\n"); } void FindFind(struct list* List){ char tmpword[33]; unsigned char i; bool (__stdcall *List_FindMe)(char MD5[32], struct list* List); scanf("%s", tmpword); for (i = 0; i < 33; i++) tmpword[i] = toupper(tmpword[i]); if (dllp) { List_FindMe = (bool(__stdcall *) (char MD5[32], struct list* List)) GetProcAddress(dllp, "_List_FindMe"); } if (slm(tmpword, "RANDOM")){ RadndomMD5(); if (List_FindMe(tmp, List)) printf("true\n"); else printf("false\n"); } else { if (List_FindMe(tmpword, List)) printf("true\n"); else printf("false\n"); } } void AddAdd(struct list* List){ char tmpword[33]; char tmppos[33]; unsigned char i; void (__stdcall *List_Add_First)(char MD5[32], struct list* List); void (__stdcall *List_Add_End) (char MD5[32], struct list* List); if (dllp) { List_Add_First = (void(__stdcall *) (char MD5[32], struct list* List)) GetProcAddress(dllp, "_List_Add_First"); List_Add_End = (void(__stdcall *) (char MD5[32], struct list* List)) GetProcAddress(dllp, "_List_Add_End"); } scanf("%s%s", tmppos, tmpword); for (i = 0; i < 33; i++){ tmpword[i] = toupper(tmpword[i]); tmppos[i] = toupper(tmppos[i]); } if (slm(tmppos, "FIRST")) { if (slm(tmpword, "RANDOM")){ RadndomMD5(); List_Add_First(tmp, List); } else { List_Add_First(tmpword, List); } } else if (slm(tmppos, "END")) { if (slm(tmpword, "RANDOM")){ RadndomMD5(); List_Add_End(tmp, List); } else { List_Add_End(tmpword, List); } } } void RemoveRemove(struct list* List){ char tmpword[33]; char tmppos[33]; unsigned char i; void (__stdcall *List_RemoveFirst)(struct list* List); void (__stdcall *List_RemoveLast) (struct list* List); void (__stdcall *List_RemoveValue)(char MD5[32], struct list* List, bool All); if (dllp) { List_RemoveFirst = (void(__stdcall *) (struct list* List)) GetProcAddress (dllp, "_List_RemoveFirst"); List_RemoveLast = (void(__stdcall *) (struct list* List)) GetProcAddress (dllp, "_List_RemoveLast"); List_RemoveValue = (void(__stdcall *) (char MD5[32], struct list* List, bool All)) GetProcAddress(dllp, "_List_RemoveValue"); } scanf("%s", tmppos); for (i = 0; i < 33; i++) tmppos[i] = toupper(tmppos[i]); if (slm(tmppos, "FIRST")) List_RemoveFirst(List); else if (slm(tmppos, "END")) List_RemoveLast(List); else if (slm(tmppos, "VAL")){ scanf("%s%s", tmppos, tmpword); for (i = 0; i < 33; i++){ tmpword[i] = toupper(tmpword[i]); tmppos[i] = toupper(tmppos[i]); } if (slm(tmppos, "RANDOM")) { RadndomMD5(); for (i = 0; i < 33; i++) tmppos[i] = toupper(tmp[i]); } if (slm(tmpword, "TRUE" )) List_RemoveValue(tmppos, List, true); else List_RemoveValue(tmppos, List, false); } } void PrintPrint(struct list* List){ void (__stdcall *List_PrintMe)(struct list* List); if (dllp) { List_PrintMe = (void(__stdcall *) (struct list* List)) GetProcAddress(dllp, "_List_PrintMe"); } List_PrintMe(List); } void CheckCheck(struct list* List){ bool (__stdcall *List_IsEmpty)(struct list* List); if (dllp) { List_IsEmpty = (bool(__stdcall *) (struct list* List)) GetProcAddress(dllp, "_List_IsEmpty"); } if (List_IsEmpty(List)) printf("true\n"); else printf("false\n"); } void FreeFree(struct list* List){ void (__stdcall *List_FreeAndNil)(struct list* List); if (dllp) { List_FreeAndNil = (void(__stdcall *) (struct list* List)) GetProcAddress(dllp, "_List_FreeAndNil"); } List_FreeAndNil(List); } int main(){ // Переменные bool exitkey; char tmpword[257]; int i; struct list* MyList; dllp = LoadLibrary("DinLib.dll"); struct list* (__stdcall *List_Create)(); // Начальная инициализация листа dllp = LoadLibrary("DinLib.dll"); if (dllp) { List_Create = (struct list*(__stdcall *) ()) GetProcAddress(dllp, "_List_Create"); } MyList = List_Create(); RadndomMD5(); // Фикс кириллицы SetConsoleOutputCP(1251); SetConsoleCP(1251); // Вывод приветствия printf("Добро пожаловать!\nПрограмму выполнил: Буренков Игорь (М80-206Б-17)\n\nведите h или help для вывода справки\n"); // Панель ввода вывода while (exitkey != true){ // Печать t> перед командой printf("t>"); // Считываем первое слово scanf("%s", tmpword); // Перевод слова в верхний регистр for (i = 0; i < 257; i++) tmpword[i] = toupper(tmpword[i]); // Анализ первой комманды if (slm(tmpword, "H")||slm(tmpword, "HELP")) PrintHelp(); else //if (slm(tmpword, "PRINT")) PrintPrint(MyList); else //if (slm(tmpword, "FIND")) FindFind(MyList); else //if (slm(tmpword, "CHECK")) CheckCheck(MyList); else //if (slm(tmpword, "ADD")) AddAdd(MyList); else //if (slm(tmpword, "REMOVE")) RemoveRemove(MyList); else //if (slm(tmpword, "CLEAN")) FreeFree(MyList); else if (slm(tmpword, "EXIT")) exitkey= true; } FreeFree(MyList); free(MyList); FreeLibrary(dllp); system("pause"); return 0; } 

When a function is called, for example List_Add_First (tmp, List); the program crashes.

DLL is two files

mainlib.h:

 #if defined(BUILD_DLL) # define DLL_EXP __declspec(dllexport) #else # if defined(BUILD_APP) # define DLL_EXP __declspec(dllimport) # else # define DLL_EXP # endif #endif // Стандартные заголовки #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <windows.h> #include <ctype.h> #include <string.h> // Структура листа struct listlight; // Структура листа struct list; // Создание узла листа DLL_EXP struct list* List_Create(); // Уничтожение листа DLL_EXP void List_FreeAndNil(struct list* List); // Проверка на пустоту DLL_EXP bool List_IsEmpty(struct list* List); // Добавить элемент-лист в начало DLL_EXP void List_Add_First(char MD5[32], struct list* List); // Добавить элемент-лист в конец DLL_EXP void List_Add_End(char MD5[32], struct list* List); // Удаление первого листа DLL_EXP void List_RemoveFirst(struct list* List); // Удаление последнего листо DLL_EXP void List_RemoveLast(struct list* List); // Удаление листа по значениею DLL_EXP void List_RemoveValue(char MD5[32], struct list* List, bool All); // Поиск значения DLL_EXP bool List_FindMe(char MD5[32], struct list* List); // Печать элементы DLL_EXP void List_PrintMe(struct list* List); 

mainlib.c:

 #define BUILD_DLL #include "mainlib.h" // Структура листа struct listlight { char MD5[33]; // MD5 struct listlight* right; // Правый ребенок }; // Структура листа struct list { struct listlight* first; }; // Создание листа DLL_EXP struct list* List_Create(){ struct list* List = malloc(sizeof(struct list)); List->first = NULL; return List; } // Уничтожение листа DLL_EXP void List_FreeAndNil(struct list* List) { // Запускаем балалайку ^_^ //while (List_IsEmpty(List) == false) { // List_RemoveLast(List); //} return; } // Проверка на пустоту DLL_EXP bool List_IsEmpty(struct list* List){ return (List->first == NULL); } // Инициализация элемента списка DLL_EXP struct listlight* Leaf_inside_Create(char MD5[32]){ // Переменные struct listlight* tmp; unsigned char i; // Начальная инициализация tmp = malloc(sizeof(struct listlight)); tmp->right = NULL; for (i = 0; i < 33; i++) tmp->MD5[i] = MD5[i]; // Возращаем указатель return tmp; } // Добавление листа в конец DLL_EXP void List_Add_End(char MD5[33], struct list* List){ // Указатель на новый элемент struct listlight* tmp = Leaf_inside_Create(MD5); struct listlight* current; // Вставляем указатель if (List_IsEmpty(List)) { List->first = tmp; } else { current = List->first; while (current->right != NULL) current = current->right; current->right = tmp; } } // Добавление листа в начало DLL_EXP void List_Add_First(char MD5[33], struct list* List){ // Указатель на новый элемент struct listlight* tmp = Leaf_inside_Create(MD5); // Временный контейнер struct listlight* current; // Вставляем указатель if (List_IsEmpty(List)) { List->first = tmp; } else { tmp->right = List->first; List->first = tmp; } } // Удаление первого элемента DLL_EXP void List_RemoveFirst(struct list* List){ // Временный контейнер struct listlight* tmp; // Если лист не пустой if (List_IsEmpty(List) == false) { // Запоминаем 2ю позицию tmp = List->first->right; // Освобождение памяти free(List->first); // Делаем 2ю позицию первой List->first = tmp; } } // Удаление последнего элемента DLL_EXP void List_RemoveLast(struct list* List){ // Временный контейнер struct listlight* tmp = List->first; if (tmp == NULL) return; if (tmp->right == NULL) { List_RemoveFirst(List); return; } while (tmp->right->right != NULL) tmp = tmp->right; free(tmp->right); tmp->right = NULL; } //Сравнить две MD5 суммы DLL_EXP bool EquivalentMD5(char MD5left[33], char MD5right[33]){ unsigned char i; for (i = 0; i < 33; i++) if (MD5left[i] != MD5right[i]) return false; return true; } // Удалить по значению DLL_EXP void List_RemoveValue(char MD5[33], struct list* List, bool All){ // Переменные unsigned char i; struct listlight* tmp = List->first; struct listlight* tmp2; if (tmp == NULL) return; if (EquivalentMD5(tmp->MD5, MD5)) { List_RemoveFirst(List); if (All == false) return; } while (tmp->right != NULL){ if (EquivalentMD5(tmp->right->MD5, MD5)) { if (tmp->right->right == NULL) List_RemoveLast(List); else{ tmp2 = tmp->right->right; free(tmp->right); tmp->right = tmp2; } if (All == false) return; } } } // Поиск значения DLL_EXP bool List_FindMe(char MD5[33], struct list* List){ struct listlight* tmp = List->first; while (tmp != NULL){ if (EquivalentMD5(tmp->MD5, MD5)) return true; tmp = tmp->right; } return false; } // Печать элементы DLL_EXP void List_PrintMe(struct list* List){ struct listlight* tmp = List->first; unsigned char i; while (tmp != NULL){ printf("%c", '|'); for (i = 0; i < 33; i++) { printf("%c", tmp->MD5[i]); } tmp = tmp->right; } printf("%c%c", '|', '\n'); } 

If you connect this library as .lib (static) - everything works, but as a dll, for some reason it does not.

Link to the project: https://yadi.sk/d/390OeXKfXdiBcg (Static - .lib, Unstatic - .dll)

I sincerely hope for your help, because I'm just learning how to work with such libraries and maybe I don't understand something.

  • I did a tutorial from Kaspersky and from here: codenet.ru/progr/bcb/dll.php - Alrott SlimRG
  • So what is your BUILD_APP symbol BUILD_APP ? Where is it used? And why do you have #define BUILD_DLL at the beginning of the main program ??? - AnT
  • The problem is in the transfer of pointers to dynamic memory across the DLL boundaries: docs.microsoft.com/en-us/cpp/c-runtime-library/ ... This is not recommended because it will only work correctly when EXE and DLL use the same same standard C library (by version and debug / release version) - MSDN.WhiteKnight
  • @ MSDN.WhiteKnight and how then to be, because I need to work with pointers! - Alrott SlimRG 2:58 pm
  • It is possible and necessary to work with pointers. It is impossible to do free in EXE on the pointer returned from DLL, and vice versa. But you seem to have a more serious problem. In the DLL struct list* List_Create(); , and in the EXE struct list* (__stdcall *List_Create)(); . Where did __stdcall come from? - MSDN.WhiteKnight

1 answer 1

I suspect that your DLL is linked to the MSVC runtime library statically . Then your DLL has its own internal dynamic memory manager, i.e. its heap. Every time you execute LoadLibrary , you create this heap from scratch, and every time you execute FreeLibrary , you destroy this heap with all the data stored in it.

Therefore, every time you do FreeLibrary , you destroy everything you just created on the heap of this DLL. Any attempts to work with your list after FreeLibrary will cause the program to crash.

Stop making these permanent LoadLibrary / FreeLibrary . Since you want to load DLLs manually (why, by the way?), LoadLibrary should be done only once at the very beginning of working with lists, and FreeLibrary should be done when you no longer need lists. Usually LoadLibrary is done once at the beginning of the program, and FreeLibrary is FreeLibrary once at the very end.


A side note:

You are lucky that the function declaration is the first in mainlib.h

 DLL_EXP struct list* List_Create(); 

which mentions the type of struct list within its return type (and not in the parameter list). This automatically creates a global declaration of type struct list , to which all subsequent declarations refer.

However, it would be more reasonable practice to provide an independent declaration of type struct list somewhere at the very beginning of mainlib.h

 struct list; 

so that the "declaration" of this type does not depend on which function will be declared first.

Also, it is recommended to declare functions without parameters in the C language with an explicit (void) . Ads with () are deprecated.

  • Thank. 2nd part corrected - Alrott SlimRG
  • But with the first one, not everything is so rosy: on the List_Add_First function, as it crashed, it crashes. Only before the error was Write Access Error, and now System Exeption 0x00 ... 01 - Alrott SlimRG
  • I think the thing about the availability of pointers - Alrott SlimRG
  • one
    @Alrott SlimRG: I don’t know what accessibility of pointers you're talking about. It is also not clear to me where you have __declspec(dllexport) , why the names in GetProcAddress begin with _ and what is #define BUILD_DLL . I corrected these oddities - everything works for me. - AnT 10:27 pm
  • It is also not clear what kind of constant bounce between 32 and 33 in the size of the arrays is. - AnT pm