Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.82/88: Рейтинг темы: голосов - 88, средняя оценка - 4.82
12 / 3 / 0
Регистрация: 12.07.2015
Сообщений: 69

Компиляция и использование DLL

12.08.2018, 18:28. Показов 16659. Ответов 23
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Простой, вроде-бы вопрос: как в с++ скомпилировать dll? Как его в последствии использовать? И я имею в виду компиляцию при помощи MinGW (g++.exe), а не при помощи всяких там сторонних редакторов с их непонятно как работающими компиляторами, где для компиляции dll достаточно в свойствах проекта указать, что ты компилируешь dll... Проблема как раз в том, что все гайды по dll, которые я находил, как раз и подразумевали компиляцию при помощи всяких там Visual Studio... А как это сделать из командной строки (или, в моём случае, из notepad++ и nppexec) при помощи g++.exe?

И вообще, что на самом деле представляет из себя dll? Если я буду представлять его как набор заранее скомпилированных функций, которые я смогу использовать в своей программе, если подключу dll, при этом с сохранёнными названиями функций, это будет правильно? Есть ли какой-нибудь способ узнать содержимое dll файла (какая-нибудь легковесная программа, разбирающая прямо каждый байт dll-файла? (вообще, мне бы и для exe подобная пригодилась бы, но пока и для dll хватит))
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
12.08.2018, 18:28
Ответы с готовыми решениями:

Компиляция dll библиотеки
Как правильно скомпилировать dll библиотеку, чтобы имена методов не изменялись? Например, у меня есть метод с именем Java_Test_test, а...

Компиляция функции в dll на С++
Всем привет. Есть функция для фильтрации сигнала. Пытаюсь разобраться как скомпилировать из неё dll. Просмотрел несколько видео на...

Компиляция dll на win8x64 и ошибка на winXP
Компилирую длл библиотеку на Windows 8 (x64), потом пытаюсь воспользоваться на windows xp и вылеатет Точка входа в процедуру...

23
 Аватар для Kuzia domovenok
4268 / 3327 / 926
Регистрация: 25.03.2012
Сообщений: 12,532
Записей в блоге: 1
12.08.2018, 20:33
Цитата Сообщение от Max_Cross Посмотреть сообщение
Есть ли какой-нибудь способ узнать содержимое dll файла
Dependency Walker
depends.exe
1
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
12.08.2018, 20:41
http://www.mingw.org/wiki/sampleDLL
1
12 / 3 / 0
Регистрация: 12.07.2015
Сообщений: 69
12.08.2018, 23:51  [ТС]
А сейчас, возможно, совсем тупой вопрос, но... В чём разница между типами int(*)(int, int) и int*(int, int) ?
Почему этот код:
C++
1
2
3
4
5
6
7
8
#include <windows.h>
#include <iostream>
int (*TestAddValFuncFromExtDLL)(int, int);
int main() {
    HINSTANCE hinstLib = LoadLibrary("TestDLL.dll");
    TestAddValFuncFromExtDLL = (int(*)(int, int)) GetProcAddress(hinstLib, "TestAddValFuncFromExtDLL");
    TestAddValFuncFromExtDLL(10, 15);
}
- работает, а этот:
C++
1
2
3
4
5
6
7
8
#include <windows.h>
#include <iostream>
int *TestAddValFuncFromExtDLL(int, int);
int main() {
    HINSTANCE hinstLib = LoadLibrary("TestDLL.dll");
    TestAddValFuncFromExtDLL = (int*(int, int)) GetProcAddress(hinstLib, "TestAddValFuncFromExtDLL");
    TestAddValFuncFromExtDLL(10, 15);
}
- нет? (error: invalid cast to function type 'int*(int, int) в 6-й строчке)
0
 Аватар для Kuzia domovenok
4268 / 3327 / 926
Регистрация: 25.03.2012
Сообщений: 12,532
Записей в блоге: 1
13.08.2018, 00:21
Max_Cross, первое это указатель на функцию, возвращающую int
второе это и есть объявление(declaration) функции, только не int возвращающей, а указатель на int

Добавлено через 5 минут
Цитата Сообщение от Max_Cross Посмотреть сообщение
- нет? (error: invalid cast to function type 'int*(int, int) в 6-й строчке)
потому что это вообще не указатель на функцию, это объявление функции. Чё ты к нему приравнивать собрался?
int main(){
main=(int ())GetProcAddress(hinstLib, "TestAddValFuncFromExtDLL");//ну бред же, согласись!
}
1
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
13.08.2018, 00:29
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <type_traits>
 
int funct1(int, int) {return 1;}
int *funct2(int, int) {return nullptr;}
 
int main()
{
    std::cout << std::boolalpha;      
    std::cout << "types_equal " << std::is_same< decltype(&funct1), int (*)(int, int) >::value << std::endl;    //указатель на функцию
    std::cout << "types_equal " << std::is_same< decltype(funct2), int *(int, int) >::value << std::endl;       //просто функция  
}
Добавлено через 4 минуты
Цитата Сообщение от Max_Cross Посмотреть сообщение
TestAddValFuncFromExtDLL(10, 15);
лучше так
C++
1
(*TestAddValFuncFromExtDLL)(10, 15);
0
Эксперт С++
 Аватар для _lunar_
3701 / 2836 / 451
Регистрация: 03.05.2011
Сообщений: 5,193
Записей в блоге: 21
13.08.2018, 09:12
Цитата Сообщение от Max_Cross Посмотреть сообщение
как раз и подразумевали компиляцию при помощи всяких там Visual Studio...

для справки: в Visual Studio, как и в вашем непонятном MinGW, достаточно просто указать в свойствах проекта, что ты компилируешь dll.

Цитата Сообщение от Max_Cross Посмотреть сообщение
Как его в последствии использовать?
одним из двух способов:
- статической либой (*.lib) (#pragma comment (lib, "*.lib"))
- динамической библиотекой (*.dll) (HMODULE hMod = LoadLibrary("*.dll") с последующим GetProcAddress(hMod, "name function")).
0
12 / 3 / 0
Регистрация: 12.07.2015
Сообщений: 69
13.08.2018, 09:22  [ТС]
Так я про это и писал... Мне этим и ненравятся большинство современных редакторов - используя их - один фиг ты поймёшь, как пользоваться компилятором... Делают кучу непонятных действий за тебя, а как не окажется у тебя под рукой Visual Studio, так фиг ты что сам сделаешь... Этот опыт с попыткой банально компилировать dll без сторонних редакторов это только доказал... Поэтому я сейчас ставлю себе VSCode, и надеюсь, что хоть он не будет считать себя умнее меня (даже если это так и есть)...

И неужели, если у меня есть ТОЛЬКО dll, мне обязательно её самому подключать, обязательно объявлять указатели для каждой функции, обязательно получать адрес каждой функции? Нет какого-нибудь волшебного способа это одной строчкой сделать, что-бы я в последствии смог использовать все функции dll, как если бы они были подключены статически (насколько я помню, в C# так можно... Правда там я как раз Visual Studio использовал...)
P.S Что значит "КАК и в вашем MinGW"? В MinGW я как раз таки использую компилятор g++.exe из командной строки, то есть, всё делаю сам, и, соответственно, знаю, что делаю...
0
 Аватар для COKPOWEHEU
4083 / 2681 / 432
Регистрация: 09.09.2017
Сообщений: 11,911
13.08.2018, 10:23
Цитата Сообщение от _lunar_ Посмотреть сообщение
в вашем непонятном MinGW, достаточно просто указать в свойствах проекта
В mingw нет "проектов". Это просто компилятор. Консольный.
Цитата Сообщение от Max_Cross Посмотреть сообщение
Нет какого-нибудь волшебного способа это одной строчкой сделать, что-бы я в последствии смог использовать все функции dll, как если бы они были подключены статически
Просто слинкуйте с ней:
Code
1
2
gcc main.o sylib.dll $(LDFLAGS) -o prog.exe
gcc main.o sylib.so $(LDFLAGS) -o prog
В Linux программа не умеет искать .so рядом с собой, надо явно ее туда пнуть:
Code
1
$ LD_LIBRARY_PATH=./ ./prog
2
13.08.2018, 10:43

Не по теме:

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
В Linux программа не умеет искать .so рядом с собой, надо явно ее туда пнуть:
Я, обычно, пишу еще скриптик для запуска. :)

0
 Аватар для COKPOWEHEU
4083 / 2681 / 432
Регистрация: 09.09.2017
Сообщений: 11,911
13.08.2018, 11:55
Croessmah, "обычно"? Мне казалось, такая линковка - исключительный случай. Либо библиотека стандартная, как libc или какой-нибудь SDL, и тогда она лежит в стандартном месте. Либо она нестандартная и может вовсе отсутствовать, как разнообразные плагины, и тогда линковка должна быть динамической.
А жестко линковать самописную библиотеку в нестандартном месте это какой-то средний вариант, широкой области применений которому я с ходу не вижу.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
13.08.2018, 12:08
COKPOWEHEU, и стандартные библиотеки могут быть разных версий, что в линуксах очень часто бывает. Да и свои библиотеки можно положить куда-то в свои директории. Тот же steam содержит steam.sh, который меняет LD_LIBRARY_PATH
0
12 / 3 / 0
Регистрация: 12.07.2015
Сообщений: 69
13.08.2018, 17:52  [ТС]
И ещё вопрос, что-за Multi-Byte char/Wide char и как это влияет на работу приложения?
А то тут мой VS Code начал ругаться на строку
C++
1
HINSTANCE hinstLib = LoadLibrary("TestDLL.dll");
(argument of type "const char *" is incompatible with parameter of type "LPCWSTR")
, притом, у компилятора к этой же самой строке претензий нет... Если же использовать L"TestDLL.dll" вместо "TestDLL.dll", то претензии появляются, наоборот, у компилятора...
Как я понимаю, Wide char - это wchar_t (занимающий, как я понял, 2 байта), Multi-Byte char - это просто char, LoadLibrary - это define, который, в зависимости от наличия define _UNICODE использует либо LoadLibraryW, которая использует wchar_t, либо LoadLibraryA, использующую обычный char... И я, конечно, понимаю, что я могу просто использовать LoadLibraryA вместо LoadLibrary, и тогда претензий не будет ни у VS Code, ни у компилятора, но раз уж возникла проблема, я бы хотел не просто её решить, а понять, почему она возникла...
И так, что это за типы? Чем они отличаются? В чём разница между функциями, использующими wchar_t, и аналогичными с обычным char? Почему VSCode вдруг решил, что у меня где-то стоит define _UNICODE? Как заставить g++.exe использовать именно Wide char, или наоборот, VS Code не использовать Wide char, и на что это всё в конце концов повлияет?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
13.08.2018, 19:37
Цитата Сообщение от Max_Cross Посмотреть сообщение
В чём разница между функциями, использующими wchar_t, и аналогичными с обычным char?
Ну а как по-твоему? В чём разница между словами, в одном из которых буква кодируется 1 байтом, а в другом - двумя? И в чём разница между их обработкой?

Цитата Сообщение от Max_Cross Посмотреть сообщение
Почему VSCode вдруг решил, что у меня где-то стоит define _UNICODE?
можешь перед #include <windows.h> поставить #undef _UNICODE
0
12 / 3 / 0
Регистрация: 12.07.2015
Сообщений: 69
13.08.2018, 22:05  [ТС]
Цитата Сообщение от TRam_ Посмотреть сообщение
По теме - в WinAPI нет функции LoadLibrary с LPCWSTR, есть только с LPCTSTR https://msdn.microsoft.com/en-... s.85).aspx
Откуда VS Code взял LPCWSTR - непонятно.
LoadLibrary - ПКМ - Перейти к определению. Кидает в winbase.h:
C++
1
2
3
#define LoadLibrary __AW_SUFFIXED__(LoadLibrary)
WINBASEAPI HINSTANCE WINAPI LoadLibraryA (LPCSTR);
WINBASEAPI HINSTANCE WINAPI LoadLibraryW (LPCWSTR);
__AW_SUFFIXED__ - ПКМ - Перейти к определению. Кидает в w32api.h:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Related to the UNICODE macro definition, there are many functions in
 * the Win32 API with a generic name, which is mapped to a variant with
 * wchar_t UTF-16LE encoding of string arguments, in cases when UNICODE
 * is defined, as facilitated by the following macro...
 */
#ifdef UNICODE
 /* ...by appending a "W" suffix to the generic function name...
  */
# define __AW_SUFFIXED__(__NAME__)  __NAME__##W
#else
 /* ...or by appending an "A" suffix, to select an ANSI variant with
  * char encoding of string arguments, when UNICODE is not defined.
  */
# define __AW_SUFFIXED__(__NAME__)  __NAME__##A
#endif
То есть, LoadLibrary меняется на __AW_SUFFIXED__(LoadLibrary), а он, в свою очередь, меняется на LoadLibraryW или LoadLibraryA, в зависимости от наличия define _UNICODE
Судя по всему, VSCode либо по каким-то причинам считает, что define _UNICODE имеется, либо тупо берёт самое первое определение __AW_SUFFIXED__, которое ему попадётся... Вот только как решить это, я так и не понял...

Добавлено через 32 секунды
Цитата Сообщение от TRam_ Посмотреть сообщение
можешь перед #include <windows.h> поставить #undef _UNICODE
Побовал

Добавлено через 2 часа 13 минут
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Просто слинкуйте с ней:
Код
gcc main.o sylib.dll $(LDFLAGS) -o prog.exe
gcc main.o sylib.so $(LDFLAGS) -o prog
Спасибо, способ сработал... Правда, мне всё равно пришлось определить функцию, причём ещё и с extern "C" (хотя, если не использовать его при создании dll, то и при подключении не нужно)... Но да ладно...
Но... Нет ли способа залинковать c dll прямо из кода... Я видел, как c .lib файлами линкуют при помощи #pragma comment(lib, "file.lib"), но, как ни странно, с dll способ у меня не прокатывает...
Не хочется просто каждый раз редактировать команду, из кода удобнее.
P.S Как-то странно линковать через командную строку... Просто я могу написать "TestDLL.dll" хоть сразу после "g++", перед именем файла, хоть после имени, перед "-o", хоть вообще в самом конце - работает во всех случаях...
P.P.S Мой предыдущий вопрос о wchar_t и примирении VSCode с g++ по прежнему в силе...
0
19497 / 10102 / 2461
Регистрация: 30.01.2014
Сообщений: 17,813
14.08.2018, 08:59
Цитата Сообщение от Max_Cross Посмотреть сообщение
В чём разница между функциями, использующими wchar_t, и аналогичными с обычным char?
Для windows wchar_t - 2 байта и используется для хранения UTF16 (кодировка юникода). UTF16 - это нативная кодировка windows, именно в ней все работает. Версии А оставлены для совместимости и используют локальную кодировку (ту, на которую настроена система, для русских версий - это CP1251). Используется локальная кодировка посредством перекодировки в юникод. Т.е. любая A - функция внутри прибегает к перекодировке в UTF16.

Цитата Сообщение от Max_Cross Посмотреть сообщение
Почему VSCode вдруг решил, что у меня где-то стоит define _UNICODE?
Значит он и правда там есть. Надо посмотреть какую командную строку формирует среда.

Цитата Сообщение от Max_Cross Посмотреть сообщение
Как заставить g++.exe использовать именно Wide char, или наоборот, VS Code не использовать Wide char, и на что это всё в конце концов повлияет?
Для g++ надо добавить к командной строке -D_UNICODE
Для VS Code - покопаться в настройках и найти переключатель, который за это отвечает.

Цитата Сообщение от Max_Cross Посмотреть сообщение
Не хочется просто каждый раз редактировать команду, из кода удобнее.
Можно просто написать makefile, или, что лучше, воспользоваться cmake.
1
 Аватар для COKPOWEHEU
4083 / 2681 / 432
Регистрация: 09.09.2017
Сообщений: 11,911
14.08.2018, 10:42
Цитата Сообщение от Max_Cross Посмотреть сообщение
Как я понимаю, Wide char - это wchar_t (занимающий, как я понял, 2 байта)
Нет. wchar_t это тип данных, позволяющих хранить любой символ Юникода. В настоящее время максимальная длина такого символа составляет 21 бит.
Ограничение 16 бит wchar_t в windows это попытка microsoft сэкономить на редкоиспользуемых символах. В других системах размер wchar_t может составлять 32 бита.
Цитата Сообщение от Max_Cross Посмотреть сообщение
Правда, мне всё равно пришлось определить функцию
Для этого используют заголовочные файлы (*.h), где прописаны имена экспортируемых функций.
Цитата Сообщение от Max_Cross Посмотреть сообщение
причём ещё и с extern "C"
С++ декорирует имена функций, приписывая к ним закодированные типы аргументов. Лучше все-таки в заголовочном файле привести все функции к стандарту Си:
C
1
2
3
4
5
6
7
8
9
#ifdef __cplusplus
extern "C" {
#endif
 
int func(int a, int b);
 
#ifdef __cplusplus
}
#endif
Цитата Сообщение от Max_Cross Посмотреть сообщение
Я видел, как c .lib файлами линкуют при помощи #pragma comment(lib, "file.lib")
Это работает только для msvs если не ошибаюсь. Другие компиляторы такую запись не поймут. Да и вообще, линковка - задача линковщика, а не компилятора.
Цитата Сообщение от Max_Cross Посмотреть сообщение
Не хочется просто каждый раз редактировать команду, из кода удобнее.
Так используйте make или хотя бы сборочный скрипт.
Цитата Сообщение от Max_Cross Посмотреть сообщение
я могу написать "TestDLL.dll" хоть сразу после "g++", перед именем файла, хоть после имени, перед "-o", хоть вообще в самом конце - работает во всех случаях...
Потому что gcc считает все, не предваренное минусом, исходными файлами, которые нужно собрать. В зависимости от расширения и флагов может быть компиляция или линковка.
2
19497 / 10102 / 2461
Регистрация: 30.01.2014
Сообщений: 17,813
14.08.2018, 11:18
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Ограничение 16 бит wchar_t в windows это попытка microsoft сэкономить на редкоиспользуемых символах.
Так было раньше, когда использовалась урезанная версия UTF16 - UCS-2. Сейчас же используется UTF16, который покрывает весь диапазон юникода засчет суррогатных пар. Т.е. если какой-то экзотический символ не лезет в 2 байта, то будет использоваться еще 2.
Данное поведение является поведением по умолчанию, начиная с Windows XP.
2
 Аватар для COKPOWEHEU
4083 / 2681 / 432
Регистрация: 09.09.2017
Сообщений: 11,911
14.08.2018, 22:26
DrOffset, то есть тот же multibyte char, только уже по 16 бит. Смысл wchar_t не в изобретении multibyte поверх utf-16, а в представлении любого символа текущей локали одной переменной (информация из стандарта). То что когда-то давно локалью по умолчанию считалось utf-16, а до того cp1251, а еще раньше 866 - не оправдание.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
14.08.2018, 22:34
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Смысл wchar_t не в изобретении multibyte поверх utf-16
Не нужно никаких "поверх". UTF-16 уже сам по себе мультибайтный (мультисловный? ). То бишь суррогатные пары - часть UTF-16, а не какая-то надстройка. Если убрать из UTF-16 суррогатные пары, то получим UCS-2.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.08.2018, 22:34
Помогаю со студенческими работами здесь

Компиляция консольного приложения. Ошибка msvcp120.dll
Добрый день. Cсоздаю проект консольного приложения фреймворк 2.0 ставлю(не знаю влияет ли это на проблему) Компилировал на релизе на двух...

Компиляция Sqlite3.dll в Visual C++ 6. Нужны умные головы профессионалов
Доброе время суток уважаемые программисты! В языке C++ я даже не новичок, а лузер (так пару dll делал). Я редко у кого прошу помощи,...

Дизассемблирование DLL, правка кода и компиляция его в DLL
ни разу не писал на c#, не пользовался monodeveloperом. сделано следующее: 1. дизассемблировал библиотеку name.dll, использовал...

Использование String Tables в .dll(.dll.mui) (Для VB .NET)
Здравствуйте. Нужно извлечь(а потом запоковать) таблицу строк(string tables ). Допустим есть файл explorerframe.dll.mui из...

Компиляция .cs в .dll
Добрый день. Уважаемые форумчане, помогите с компиляцией .cs кода в .dll По определённым причинам выложить код не могу, могу скинуть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru