Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.79/723: Рейтинг темы: голосов - 723, средняя оценка - 4.79
Эксперт С++
 Аватар для MikeSoft
3956 / 1811 / 184
Регистрация: 21.11.2009
Сообщений: 2,540

Dynamic-Link Library: Теория + Практика

20.07.2010, 23:49. Показов 152481. Ответов 7

Студворк — интернет-сервис помощи студентам
1. Теоретическая часть. Знакомство с Dynamic-Link Library.
  • 1.1. Что такое DLL.
  • 1.2. Использование DLL.
  • 1.3. Необходимость внедрения DLL. Нужно ли это?


2. Практическая часть. Создание Dynamic-Link Library в RAD Studio.
  • 2.1. Создаём первую DLL своими руками.
  • 2.2. Неявная загрузка.
  • 2.3. Явная загрузка.
  • 2.4. Отложенная загрузка.


3. Заключение.


________________________________________ _________



1. Теоретическая часть. Знакомство с Dynamic-Link Library.
  • 1.1. Что такое DLL.


Для начала нужно разобраться, что же такое DLL.
DLL — это сокращение фразы Dynamic-Link Library — динамически подключаемая библиотека.
Первоначальная идея введения библиотек заключалась в более рациональном использовании ресурсов ПК, таких как ОЗУ и НЖМД. Предполагалось, что различные приложения будут использовать одну библиотеку, тем самым ликвидируя проблему сохранения одинаковых участков кода в различных местах и многократную загрузку одинаковых участков в ОЗУ.

В дальнейшем, было решено увеличить эффективность разработки приложений за счёт модульности. Обновление самих DLL должно было позволить расширять и усовершенствовать систему, не затрагивая при этом всех приложений. Однако, данная идея столкнулась с проблемой одновременного требования приложениями разных, не полностью совместимых версий библиотек, что приводило к сбоям. Данная проблема была названа "DLL Hell".

По сути, DLL - это относительно независимый участок кода, имеющий свою оболочку.
Оболочка DLL имеет секции импорта/экспорта.

Секция экспорта перечисляет те идентификаторы объектов (классы, функции, переменные), доступ к которым предоставляет данная DLL. В большинстве случаев именно эта секция вызывает особый интерес у разработчиков. Тем не менее, DLL может вовсе не содержать секцию экспорта. Кроме функций, к которым можно получить доступ извне (exported), существуют также внутренние функции (internal), которые спрятаны от "посторонних глаз" и могут использоваться лишь кодом самой DLL.

Секция импорта предназначена для связи данной DLL с другими.
Большинство библиотек импортируют функции из системных DLL (kernel32.dll, user32.dll и др.). Иногда в стандартный список нужно добавить другие библиотеки, например ws2_32.dll для работы с Socket'ами.



  • 1.2. Использование DLL.


DLL не может выполняться сама по себе, поэтому требует хост-процесс (главный процесс, в котором предполагается использование DLL).
Перед тем, как библиотеку можно будет использовать, её необходимо загрузить в область памяти хост-процесса. В exe-файле компилятором будет сгенерирована инструкция вызова заданной функции (call).
Т.к. DLL расположена в адресном пространстве процесса, то вызов функции из библиотеки будет иметь вид:
Code
1
call адрес_вызываемой_процедуры
Например:
Assembler
1
2
3
4
5
6
7
;Произвольный код
call 010199  ; Вызов процедуры
; Произвольный код
; Код с адреса 010199:
add eax, 500
mul eax, edx
ret
При выполнении команды call, процессор передает управление на код с адреса 010199, и выполняет его до команды ret, а затем возвращает управление команде следующей за call. Код который вызывается командой call называется процедурой.

Файл, являющийся динамически загружаемой библиотекой не всегда носит расширение *.dll.
Есть также: *.cpl (библиотеки, используемые апплетом панели управления) и *.ocx.

Библиотеки удобно использовать для разделения приложения на части, выполняющие разные роли.
Например, приложение, обеспечивающее работу с базами данных может быть разделено на часть, отвечающую за выборку данных из базы, находящейся на сервере, и, часть, которая отвечает за визуальное управление приложением. Это явный пример той модульности, о которой я упоминал выше. Вы в праве изменять принципы обмена данными с сервером БД, не затрагивая при этом работу с визуальной частью.

DLL может являться также обычным хранилищем ресурсов, о создании которого я рассказывал в теме https://www.cyberforum.ru/cpp-... 27736.html.



  • 1.3. Необходимость внедрения DLL. Нужно ли это?


Настало время ответить на вопрос: Когда же нужно использовать DLL?
Если вы разрабатываете небольшой проект или тестовое приложение, то внедрение DLL будет для вас пустой тратой времени и сил. Тратой времени: не только времени на создание библиотеки, но ещё и времени, необходимого для загрузки DLL в память хост-процесса. До того, как вы будете использовать объекты из DLL, вам рано или поздно прийдётся выгрузить содержимое в память. А это требует некоторого времени.
Однако, если вашу DLL будет использовать более, чем одна копия приложения (или несколько различных приложений) - наступит явный выигрыш.

Для эксперимента запустите Microsoft Office. Первый запуск долгий. Это обусловлено тем, что все необходимые модули загрузаются в оперативную память. Теперь полностью закройте Office и снова откройте его! Окно появится почти мгновенно. Это обусловлено тем, что модули хранились в ОЗУ (система не тронет их, пока ей не понадобится память для других целей).

При создании больших проектов лучше сразу пытаться представить себе части, которые могут быть уникальными и требующими частого усовершенствования.

Но не старайтесь придать вашему проекту чрезвычайной "уникальности" за счёт помещения каждой функции в отдельную библиотеку! Это можно делать, только зачем тратить время для загрузки каждого модуля?



2. Практическая часть. Создание Dynamic-Link Library в RAD Studio.
  • 2.1. Создаём первую DLL своими руками.


Пришло время постепенно перейти от теории к практике.
Открываем IDE (для написании данной статьи я использовал RAD Studio 2010).
Переходим к File -> New -> Other -> Dynamic-Link Library.
Перед нами возникает диалог:

Source Type - язык, на котором ведётся разработка.
Use VCL - использование библиотеки визуальных компонентов.
Multi Threaded - опция, указывающая на то, будет ли использоваться многопоточность в данной DLL (VCL уже подразумевает в себе многопоточность).
VC++ Style DLL - опция, указывающая на то, будет ли DLL совместима с компиляторами Microsoft.

Если в совместимости нет нужды и опция не выбрана, то DLL будет иметь точку входу с таким прототипом:
C++
1
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved);
Для обеспечения совместимости точка входа изменяется на:
C++
1
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved);
Оставим диалог без изменений и нажмём "ОК".
Перед нами появится шаблон минимальной DLL. Сохраним его.
Как вы помните, сама по себе DLL работать не может, ей нужен клиент. Поэтому, для удобства сразу создадим новый проект VCL Forms Application.
Для этого переходим в Project Manager, вызываем контекстное меню у нашей Project Group и переходим к Add New Project -> VCL Forms Application.
Для удобста я назвал проекты TestDLL и TestVCL соответственно (и сохранил их в одном каталоге - это избавит меня от копирования DLL или указания абсолютного пути):
Название: 2.png
Просмотров: 13363

Размер: 12.3 Кб
Без изменений запускаем TestVCL, сохраняем и переключаемся к проекту TestDLL (дабл-клик на проекте в Project Manager).

Переходим к Run -> Parameters и в поле Host Application указываем путь к нашему проекту TestVCL.

К шаблону DLL добавляем функцию, которая будет вычислять сумму и выводить результат на экран:
C++
1
2
3
4
5
6
7
#include "TestDLL.h" // создание этого заголовочного файла будет описано ниже
//---------------------------------------------------------------------------
void ShowSum(const int A, const int B)
{
  ShowMessage(IntToStr(A) + " + " + IntToStr(B) + " = " + IntToStr(A + B));
}
//---------------------------------------------------------------------------
В проекте TestDLL добавим также заголовочный файл (TestDLL.h) с таким содержанием:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef __TESTDLL_H
#define __TESTDLL_H
 
/*
символ TESTDLL_EXPORTS по умолчанию определен в Вашем проекте (см. Project Options -> С/С++ -> General->Preprocessor Definitions).
При этом все экспортируемые идентификаторы предваряются символом DLL_SPEC.
В случае определения TESTDLL_EXPORTS в проекте DLL_SPEC определяется как экспортируемый объект; в случае же отсутствия такого определения мы получим импортируемый объект.
Таким образом, один и тот же заголовочный файл может быть использован и в DLL-проекте, и в проекте, который будет использовать данную DLL! Без каких-либо изменений.
*/
 
#ifdef TESTDLL_EXPORTS
#define DLL_SPEC extern "C" __declspec(dllexport)
 
#else
#define DLL_SPEC extern "C" __declspec(dllimport)
#endif // TESTDLL_EXPORTS
 
/*
Каждый экспортируемый идентификатор предваряем __declspec(dllexport).
Эта директива позволяет линкеру определить, что данный идентификатор следует экспортировать из DLL. При этом создается специальный lib-файл, который содержит все экспортируемые идентификаторы из модуля. Также экспортируемые объекты заносятся в раздел экспорта DLL.
*/
 
DLL_SPEC void ShowSum(const int A, const int B);
 
#endif // __TESTDLL_H
Сохраняем. Запускаем. DLL мы подготовили. Теперь необходимо узнать, как же подключить DLL к проекту. Сделать это можно тремя способами. Рассмотрим их подробнее.



  • 2.2. Неявная загрузка.


При неявной загрузке DLL загружается (проецируется на адресное пространство вызывающего процесса) при его создании. Если при загрузке возникает ошибка - процесс останавливается и разрушается.

Для выполнения неявной загрузки приложению требуются:
- Заголовочный файл (*.h) с прототипами функций, описаниями классов и типов, которые используются в приложении.
- Библиотечный файл (*.lib), в котором описывается список экспортируемых из DLL функций (переменных), и их смещения, необходимые для правильной настройки вызовов функций.

В проекте TestVCL подключим наш заголовочный файл:
C++
1
#include "TestDLL.h"
Также, не забываем сделать Project -> Add To Project и добавить в проект TestDLL.lib
Далее, объявим прототип:
C++
1
void DLL_SPEC ShowSum(const int A, const int B);
Теперь осталось только вызвать функцию там, где это необходимо.
Чтобы убедится в том, что всё работает, прописываем в конструкторе формы:
C++
1
ShowSum(3,2);
Запускаем и смотрим на результат. Думаю, "3 + 2 = 5" всех устраивает.



  • 2.3. Явная загрузка.


Для того, чтобы выполнить явную загрузку программист должен попыхтеть, управляя DLL через функции WinAPI.
Наиболее часто рассматриваемые WinAPI функции:
DisableThreadLibraryCalls, FreeLibrary, FreeLibraryAndExitThread, GetModuleFileName, GetModuleHandle, GetProcAddress, LoadLibrary ...

При этом, основными функциями являются:
LoadLibrary[Ex] - позволяют загрузить DLL в адресное пространство хост-процесса.
FreeLibrary - функция, используемая для явной выгрузки DLL.
GetProcAddress - функция, позволяющая получить виртуальный адрес экспортируемой из DLL функции(или переменной) для ее последующего вызова.

Общая методика выглядит так:
1. Загрузить DLL с помощью LoadLibrary.
2. Получить указатели на необходимые объекты с помощью GetProcAddress.
3. Выгрузить DLL после завершения всех действий.

Теперь возникает вопрос, как же проверить теорию на практике?
Всё, что нужно, это добавить TestDLL.lib к проекту (также, как и при неявной загрузке).
А дальше, для проверки снова пишем в конструкторе формы:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// определяем тип "указатель на функцию"
typedef void __cdecl (*dll_func)(const int A, const int B);
 
dll_func pShowSum = NULL;
 
HMODULE hDLL = LoadLibrary("TestDLL.dll");
if (!hDLL) {
  ShowMessage("Невозможно загрузить TestDLL.dll");
  return;
}
 
// пытаемся найти в таблице экспорта необходимую нам функцию
pShowSum = (dll_func)GetProcAddress(hDLL, "_ShowSum"); // обратите внимание на название функции (объяснение будет ниже)
 
if (!pShowSum) {
  ShowMessage("Невозможно найти функцию ShowSum");
  return;
}
 
pShowSum(3,2);
 
FreeLibrary(hDLL);
И на экране снова красуется победная надпись "3 + 2 = 5"

Остался один неосвещенный вопрос. Почему же название функции "ShowSum" мы ищем в библиотеке с нижним подчёркиванием?

Виновато во всём декорирование имён.
Декорирование (или искажение, mangling) имен - это специфическое явление, присущее компиляторам языка C++, которое необходимо учитывать при разработке DLL на этом языке. Оно заключается в том, что компилятор С++ к имени функции всегда добавляет сокращенный список формальных параметров и тип возвращаемого значения.
Прототип функции Test(int); мог быть преобразован компилятором, например в ?Test@@YAKH@Z.
Естественно, такое декорирование нам вообще не по душе. Избавиться от него можно объявляя все экспортируемые функции с модификатором extern "C" - тогда компилятор не будет искажать имя функции.

Однако, как мы видим, нижние подчёркивание всё же добавилось.
Это один из нюансов среды C++ Builder. Однако, можно отучить его добавлять нижнее подчёркивание таким образом:
Project -> Options -> C++ Compiler -> Output -> Generate underscores on symbol names - перевести в состояние false.



  • 2.4. Отложенная загрузка.


Для чего же нужна отложенная загрузка?
Представьте себе ситуацию: вы написали приложение, использующее стандартные системные библиотеки вашей новой операционной системы, скажем, для проверки орфографии.
Даёте это приложение пользователю, который использует ОС более старой версии, чем у вас и в этой ОС нет функций для проверки орфографии. А пользователю это не сильно и надо. Приложение будет работать, пока не обратится к необходимой функции. То есть, фактически, DLL не нужна до обращения к определённой функции. Исключение отсутствия можно обработать и выдать пользователю предупреждение с просьбой обновить библиотеки своей ОС (и т.п.).

Использование отложенной загрузки DLL в C++ Builder мало отличается от неявной загрузки.
В проект добавляется заголовочный (*.h) файл с описаниями и библиотечный файл (*.lib).
Далее, переходим в Project -> Options -> C++ Linker -> Advanced -> Delay Load DLLs и вписываем название нашей библиотеки (TestDLL.dll).

Когда библиотека теряет свою необходимость её нужно явно выгрузить с помощью __FUnloadDelayLoadedDLL. В качестве параметра передаём имя DLL (с расширением + параметр регистрозависим).
Если вы используете многопоточные приложения - убедитесь, что все потоки завершили работу с DLL.

Примечание: Нельзя использовать отложенную загрузку для библиотек, имеющих секцию импорта (т.е. использующих другие библиотеки), а также Kernel32.dll и RTLDLL.dll (т.к. функции поддержки отложенной загрузки как раз и находятся в последней).



3. Заключение.

Данная статья даёт вам представление о возможных вариантах использования DLL в ваших проектах.
При внимательном ознакомлении с методами загрузки можно выбрать наиболее оптимальный вариант.

Подведя итоги можно выявить плюсы и минусы описанных методов:

Явная загрузка:
+ контроль и управление процессом жизни DLL.
- управлением DLL занимается программист посредством WinAPI.

Неявная загрузка:
+ все заботы берет на себя компилятор и сборщик.
- ресурсы заняты всё время жизни приложения.

Отложенная загрузка:
+ все заботы берет на себя компилятор и сборщик.
+ возможность использования приложения с не полностью совместимыми DLL.
- необходимость усиленного контроля за многопоточными приложениями.


________________________________________ _________
С уважением, Михаил (a.k.a MikeSoft)
58
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
20.07.2010, 23:49
Ответы с готовыми решениями:

Вопрос по теме Dynamic-Link Library: Теория + Практика
Здорова всем! Посмотрел тему Dynamic-Link Library: Теория + Практика и решил попробовать сделать длл. До этого ни разу не пробовал....

Г.Шилдт. Теория и практика С++
Кто-нибудь дайте бесплатную ссылку на книгу: Г.Шилдт. Теория и практика С++. BHV-Санкт-Петербург. 416 стр Please, очень...

Dynamic Link Library (.dll)
Необходимо создать программу с использованием динамической библиотеки. А именно: создать подпрограммы обработки множеств: объединение,...

7
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
25.12.2012, 22:38
Хочу сделать поправку по тому как в проекте самой DLL по умолчанию макрос TESTDLL_EXPORTS не определен, и
ф-ция будет "импортироваться" а не идти на экспорт, т.е будет не доступна.

Если заглянуть в Архангельского ( 7 издание ) то там используется для этих целей макрос __DLL__

А значит следовало бы в место
C++
1
2
3
4
5
6
#ifdef TESTDLL_EXPORTS
#define DLL_SPEC extern "C" __declspec(dllexport)
 
#else
#define DLL_SPEC extern "C" __declspec(dllimport)
#endif // TESTDLL_EXPORTS
использовать :
C++
1
2
3
4
5
6
#ifdef __DLL__
#define DLL_SPEC extern "C" __declspec(dllexport)
 
#else
#define DLL_SPEC extern "C" __declspec(dllimport)
#endif // __DLL__
Макрос __DLL__ определяет среда если проект представляет собой dll и не определяет если это обычный проект

Да и непонятно зачем в самом проекте еще раз объявлять ф-цию еще раз если она уже включена в хедер подключаемой бибиотеки ?
Цитата Сообщение от MikeSoft Посмотреть сообщение
Далее, объявим прототип:
C++
1
void DLL_SPEC ShowSum(const int A, const int B);
Добавлено через 8 минут
https://www.cyberforum.ru/post3890200.html
8
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
29.04.2014, 11:37
Явную загрузку можно ещё и так сделать (без использования typedef):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        // îáúÿâëÿåì "óêàçàòåëü íà ôóíêöèþ"
        void __cdecl (*pShowSum)(const int A, const int B); pShowSum = NULL;
 
        HMODULE hDLL = LoadLibrary("TestDLL.dll");
        if (!hDLL) {
          ShowMessage("Íåâîçìîæíî çàãðóçèòü TestDLL.dll");
          return;
        }
 
        // ïûòàåìñÿ íàéòè â òàáëèöå ýêñïîðòà íåîáõîäèìóþ íàì ôóíêöèþ
        (FARPROC)pShowSum = GetProcAddress(hDLL, "_ShowSum");
 
        if (!pShowSum) {
          ShowMessage("Íåâîçìîæíî íàéòè ôóíêöèþ ShowSum");
          return;
        }
 
        pShowSum(3,2);
 
        FreeLibrary(hDLL);
P.S. Этот кусок кода был взят из шапки и затем переправлен.
1
 Аватар для Tlya
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
17.12.2015, 04:29
"ShowSum(3,2);" - нельзя ли конкретне... куда именно это записывать?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33187 / 21484 / 8232
Регистрация: 22.10.2011
Сообщений: 36,862
Записей в блоге: 12
17.12.2015, 09:48
Чтобы убедится в том, что всё работает, прописываем в конструкторе формы
C++
1
ShowSum(3,2);
Какое из выделенных слов непонятно?
0
 Аватар для Tlya
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
19.12.2015, 01:41
в какое из мест? (вопрос наверно не из умных, просто я новичок)
Миниатюры
Dynamic-Link Library: Теория + Практика  
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
22.12.2015, 11:02
Tlya, по правилам языка C++ конструктор класса носит имя этого класса. Форма это класс. Из всего этого следует, что конструктор формы будет иметь название формы - TForm1, номер два в вашем списке.

На всякий случай:
1) Глобальная область видимости (вне функций).
2) Конструктор формы.
3) Метод формы, вызывающийся сразу после завершения работы конструктора.
0
 Аватар для Tlya
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
22.12.2015, 15:40
Большущее спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.12.2015, 15:40
Помогаю со студенческими работами здесь

The ordinal 459 could not be located in the dynamic link library urlmon.dll
В общем,я не знал куда засунуть эту тему и написал сюда... Проблема такая... the ordinal 459 could not be located in the dynamic link...

Makefile dynamic library creation error
Добрый день. Создал makefile со следующим содержанием: # Project PROJECT_NAME=StarXml EXECUTABLE=StarXml # Dirs TARGET_DIR=bin...

Unable to load dynamic library '/usr/lib/php/20151012/php_intl.dll __at Linux
Возникает ошибка --Unable to load dynamic library '/usr/lib/php/20151012/php_intl.dll Хотя расширение php_intl.dll установлено так...

Проблемы с подключением библиотек: Unknown(): Unable to load dynamic library 'C:PHPextensionsphp_exif.dll' - Не найдена указанная процедура.
Операционная система: Windows XP Pro Web-сервер: IIS Хочу подключить библиотеку php_exif.dll Она лежит в каталоге C:PHPextensions ...

Теория и практика вероятностей
Где-то увидел задачку:В чём некорректность данной задачи? Дополните условие, чтобы убрать некорректность и приведите все решения...


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

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru