Работа с DLL в Visual Basic (статья)03.08.2013, 22:51. Показов 60464. Ответов 18
Метки нет (Все метки)
В данной статье описаны основные способы работы с DLL в языке программирования Visual Basic. Рассчитана прежде всего на начинающих программистов. Она поможет заинтересованному читателю ответить на ряд вопросов: что такое DLL, зачем его используют, как его правильно использовать и создавать.
Основы Итак, что же такое DLL? Этой английской аббревиатурой словосочетания Dynamic-Link Library, что переводится как "динамически подключая библиотека", называют в операционных системах семейства Microsoft Windows динамические библиотеки, содержащие процедуры и функции, которые могут многократно использоваться различными программными приложениями. Ранние версии Windows работали в условиях жёсткого ограничения памяти, а потому использование DLL должно было позволить более активно использовать её, ведь один экземпляр DLL, загруженный в память, может использоваться сразу несколькими программами. Однако существенных преимуществ полностью получить не удалось. Причиной является такое явление, как DLL Hell ("DLL ад") - несколько программ работают с одинаковой библиотекой, однако с разными не полностью совместимыми версиями. Это приводило к большому количеству ошибок. Сейчас в Windows используется технология SxS, разрешающая параллельное использование разные версий библиотеки, что иногда сводит на нет её главное преимущество. Тем не менее, DLL (к этому понятию также относят библиотеки ActiveX и драйверы) активно используются при разработке ПО. Но в каких же случаях лучше использовать модули, а в каких DLL? Во-первых, модули, подключаемые к проекту, должны быть написаны на том языке, с которым работает среда разработки. DLL могут быть написаны на другом языке, хранятся они в уже откомпилированном виде. Во-вторых, использование DLL позволяет экономить память в том случае, если ею пользуются две или более программ одновременно (точнее, при использовании одной и той же версии). В-третьих, если функции не будут использоваться другими программами, то нет смысла создавать DLL. Тоже самое можно сказать про те случаи, когда нужно просто разбить для удобства большой код по модулям - удобнее работать с ними в одном проекте. Соглашения вызова Говоря о DLL как о библиотеках подпрограмм, следует рассказать о соглашения вызова - это часть интерфейса приложения, которая регламентирует технические особенности вызова подпрограммы, передачи параметров, возврата из неё, передача результата в основную программу. Говоря простым языком - разные стандарты использования подпрограмм (функций и процедур). Например, это расположения параметров подпрограммы: они могут быть в стеке или в регистрах. Различие существенное, от того-то эти соглашения не совместимы и нужно знать, какие используются в той или иной библиотеке. Существует немало разных соглашений, но из них обратим внимание на stdcall и cdecl. Первый используют библиотеки WinAPI функций. Второй же пригодиться нам для использования функций, написанных на языке Си (cdecl - C Declaration). В обоих соглашениях аргументы передаются через стек, справа налево. Но в stdcall очистку стека производит вызываемая подпрограмма, а в cdecl - вызывающая программа. Если что-то не поняли - не спешите ломать голову этими соглашениями, ведь для полного понимания работы с ними вам нужно знание основ Ассемблера. Не знаете? Вернетесь ещё к ним потом. Внимание мы уделим stdcall и cdecl. Большинство библиотек у вас будут работать и с этим. Использование Каким же образом использовать DLL? Как воспользоваться функциями из них? Для этого их нужно подключить к программе. Различают два способа подключения: статический и динамический. Статический. При использовании DLL загружается в память сразу при запуске программы, а выгружаются лишь при завершении работы программы. Преимущества: возможность вызова любой функции из библиотеки в любое время. Недостатки: нерациональное использование памяти в том случае, если какие-либо функции и процедуры из неё используются лишь 1 раз за всё время работы. Ведь она будет всё время в памяти, хотя логичнее её от туда выгрузить за ненадобностью. Динамический. Загрузить и выгрузить DLL можно в любое время при работе программы. Преимущества: экономное использование памяти в тех случаях, когда функция используется один раз за всё время работы программы, после чего они уже не нужны. Недостатки: большее, по сравнению со статическим подключением, количество кода. Статическое подключение При данном способе подключения нужные функции объявляют в разделе деклараций:
Declare - ключевое слово, обозначающее, что дальше следует объявление функции из библиотеки название_функции - название функции из библиотеки, которое будет использоваться у вас в программе. Может отличаться от названия функции в самой библиотеке (см. Alias) Lib "имя_библиотеки" - название подключаемой библиотеки. Она должна находиться в папке System32, либо вместе с исполняемым файлом Alias "название_функции_в_библиотеке" - необязательный параметр. Используется в том случае, если имя объявляемой функции в программе отличается от имени функции в библиотеке. Пример подключения:
Используются подключенные таким образом функции точно так же, как и обычные. Например:
Ну, это всё описываются библиотеки с stdcall. А как же cdecl? Ну, в VB есть ключевое слово cDecl, причём использоваться оно должно так:
Мда, вот они какие - недокументированные возможности! Может есть шанс подключать cdecl библиотеки с динамическим подключением? Динамическое подключение Как уже было сказано выше, при данном способе подключения библиотек кода будет намного больше. Ну во-первых сразу скажу, что в Visual Basic нет возможности стандартными средствами подключать библиотеки динамическим способом. Для этого нам нужно 3 WinAPI функции: LoadLibrary, GetProcAddress, FreeLibrary. Объявим их в разделе деклараций, а также 3 переменные, куда будем сохранять результаты:
Разберем подробнее эти функции, новые для нас. Как они работают, что делают и для чего нужны? LoadLibrary Эта функция отображает заданный исполняемый модуль в адресное пространство вызывающего процесса, или, проще говоря, загружает библиотеку в память. Единственный её параметр lpLibFileName (строковой тип) содержит путь либо имя подключаемой библиотеки. Если функция завершается успешно, то она возвращает дескриптор модуля (библиотеки). Если происходит ошибка - 0. GetProcAddress Эта функция извлекает адрес нужной процедуры или функции из DLL. Имеет два параметра: hModule ("хэндл", обычно целочисленный тип) и lpProcName (строковой тип). Первый параметр - дескриптор модуля. Получить его нам позволяет вышеописанная функция LoadLibrary. Второй параметр - имя нужной функции. Если функция завершается успешно, то она возвращает адрес экспортируемой функции из модуля (библиотеки). Если происходит ошибка - 0. FreeLibrary Эта функция уменьшает итоговое число ссылок на DLL (если она используется одновременно несколькими приложениями), а если число ссылок становится равно 0, то выгружает библиотеку из памяти. Имеет один параметр: hModule, т.е. дескриптор библиотеки (который, напомню, возвращает функция LoadLibrary). Если функция завершается успешно, возвращаемой значение не равно нулю. Если происходит ошибка, то оно равно нулю. Но основе этих функций составим программу, которая будет подключать динамически DLL (stdcall):
А теперь рассмотрим возможность динамического (впрочем, как я писал выше, работать со статическим очень сложно) подключения cdecl. Для этого, кроме упомянутых выше, нам понадобятся ещё функции CallWindowProc и CopyMemory. Сразу замечу, что необходимо знание Ассемблера для полного понимания работы такой программы. GetProcWindow Эта функция передает информацию сообщения процедуре заданного окна. Имеет 5 параметров: lpFunc, который указывает на процедуру, и Param1-Param4, через которые передаются параметры функции. Все параметры имеют тип Long. Возвращаемое значение определяет результат обработки и зависит от параметров. RtlMoveMemory Эта функция копирует содержимое одного блока памяти в другой. Имеет 3 параметра: Dest - указатель в тот блок памяти, куда нужно произвести копирование, Src - указатель на тот блок памяти, который копируется, Length - количество байтов, которое должно передаваться. Возвращаемое значение отсутствует. В качестве примера использования мы будем вызывать функцию qsort из библиотеки ntdll.dll, написанной на Си (cdecl). Данная функция используется для быстрой сортировки массива.
Подробное описание работы - в комментариях к коду. Альтернативный код - с CallBack функцией. В отличие от предыдущего варианта, он гибче, т.к. позволяет менять критерий сравнения, а во-вторых здесь используется CopyMemory. Вместо функции RtlMoveMemory здесь используем API-функции GetMem4, PutMem4, GetMem2.
Создание По каким-то причинам в Microsoft решили, что возможность создавать обычные DLL в Visual Basic будет лишней, а потому создавать их так просто мы не сможем, во всяком случае, без бубна. Да, я говорю про обычные DLL, потому что можно создавать лишь ActiveX DLL. В чём же разница обычных DLL от ActiveX? ActiveX ActiveX была внедрена в Windows компанией Microsoft в 1996 году как продолжение развития её технологий OLE (Object Linking and Embedding) и COM (Component Object Model). OLE - технология связи и внедрения объектов в другие документы и объекты. Она позволяет передавать данные от одной программы для редактирования другой. Так, например, изображение или рисунок в программе Microsoft Word можно редактировать в Paint, и при сохранении он автоматически измениться и в документе Word. COM - технология создания программного обеспечения на основе взаимосвязанных компонентов. Воплощение идей объектно-ориентированного программирования (ООП): инкапсуляции и полиморфизма. И вот мы имеем фреймворк ActiveX, совмещающий эти две технологии. Он активно используется при разработке форм приложений. Все кнопки, списки, диалоговые окна, "этикетки" (Label), поля ввода (Textbox), их которых мы собираем форму - всё это ActiveX. Вообще многие продукты Microsoft используют управляющий элементы ActiveX, что позволяет использовать их функционал в других приложениях. Подробнее об этом смотрите в моей статье об использовании компонента Windows Media Player для создания музыкального проигрывателя. Итак, приступим к созданию ActiveX DLL! Запускаем Visual Basic, в окне New Project выбираем ActiveX DLL (либо в меню File-New Project). И вот уже перед нами и редактор кода! Процесс написания кода здесь ничем не отличается от написания обычной программы. Пишете код, сохраняете проект, компилируете библиотеку. Но не забывайте тот факт, что ActiveX DLL, в отличие от обычной DLL, не библиотека процедур и функций, а библиотека классов! Так что здесь забудьте про процедурное программирование - только ООП! Пишем классы: поля, свойства, методы, инкапсуляция, наследование (кстати, в Visual Basic нет обычного наследования, так что это делать нужно через наследование интерфейсов), полиморфизм. В принципе это и есть главное отличие. Хотя написать процедуру как метод не составит проблем. Коротко об использовании ActiveX DLL. Подключаются они точно так же, как и обычные, но с той разницей, что необходимо создать объект и вызывать его методы - это называют связыванием. Различают ранее и позднее связывание. Ранее связывание осуществляется командой
программе. При позднем связывании нужно сначала создать объект:
Если вас заинтересовала технология ActiveX и её возможности, рекомендую вам ознакомится со статьей Б.Л. Файфеля "COM в действии": "Создаем ActiveX DLL": и "Вопросы" (часто задаваемые вопросы про ActiveX). Обычные DLL Вообще-то создавать обычные DLL в Visual Basic, как уже было сказано выше, нельзя без "танцев с бубном". Но энтузиастами был создан Add-In для среды разработки Visual Basic, который позволяет создавать почти полноценные DLL на Visual Basic. Единственный, и самый существенный минус - невозможность использования созданных таким образом библиотек в других языках программирования. Загрузить Add-In можно по этой ссылке К архиву прилагается файл ReadMe с подробным описанием установки дополнения и его использования, а также пара примеров создания DLL. Каким же образом мы компилируем библиотеки, если такой возможности в VB нет? Весь секрет в недокументированных возможностях link.exe ("линкеры", как известно, выполняют компиляцию в всё с этим связанное). Если запустить его в DOS командой link.exe > c:/link.txt, то мы увидим множество различных ключиков. Их них наибольший интерес представляют /DLL и /DRIVER. Понятно, что компилятор Visual Basic 6 способен ещё и компилировать библиотеки с драйверами! Ну вот именно на первом ключе и основан принцип работы этой надстройки: перехватываем командную строку линкера, изменяем, вызываем настоящий линкер. Только одно но... это скорее не продуманная реализация линкера, а баг. Он нарушает компоновку библиотеки, из-за чего она будет работать не стабильно. А именно - лишь в Visual Basic! Если вас заинтересовало это, то подробнее ознакомиться с работой надстройки вы можете здесь. Автор: Павел Смирнов (Craw) Источник: basic.ucoz.net Отдельная благодарность за помощь в написании статьи: Catstail, SoftIce, locm, Pro_grammer, TheTrick
15
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 03.08.2013, 22:51 | |
|
Ответы с готовыми решениями:
18
Создание процедурных DLL в Visual Basic (статья) Способы передачи данных с Visual Basic в Excel (статья) Visual Basic + VC++ DLL = ошибка Bad DLL calling convertation |
|
Телекомпания ВИD
1364 / 115 / 19
Регистрация: 14.10.2012
Сообщений: 100
|
||||||||||||||||||||||||||||||||
| 19.08.2013, 17:10 | ||||||||||||||||||||||||||||||||
|
Комментарии к статье:
1. Даже в официальной MSDN-документации сказано, что в фортрановском соглашении стек очищает вызываемая (с помощью RET), а при сишном это должна делать вызывающая (ADD ESP). А теперь подумайте, с какого перепугу cdecl «сама» чистит стек? 2. Сам посредник для вызова можно сократить до 9 байт:
3. Колбёк лучше вынести в отдельную функцию, сделав число аргументов динамическим. Это и есть «гибкость». Да что обсуждать… сами смотрите аргументо-упрощенный пример: Пример 1. CallEx_ASM.rar 4. Примечание. При большом числе передаваемых аргументов асмовый код, естественно, «раздуется», как и время на его «формирование» в циклах. Поэтому можно еще немного улучшить, возложив вбшные действия на сам асмовый код, задействовав для этого регистры. В результате он будет всегда иметь фиксированный размер 24 байта при любом числе параметров (см. Пример 2). Пример 2. CallEx_ASM_v2.rar 5. Все это будет работать только на незащищенных машинах (имеется ввиду запуск байтового массива). В противном случае необходимо выделять кусок памяти для размещения посредника там.
New / CreateObject – это не типы связывания, а способы создания класса (причем самих способов создания больше, также как и подтипов связывания), различие между которыми незначительное, но в итоге они оба по CLSID-у и IID определяют лишь указатель на нужный интерфейс. Так, CreateObject, но с переменной-интерфейсом в библиотеке типов – означает раннее, а New, но с объектной переменной и использованием библиотеки типов – позднее связывание. Существуют различные технологии методов, но для COM характерна виртуализация, то есть получение указателей в специальной «виртуальной» таблице, выполняемое в момент обращения. Такой выбор метода в VB6 является ранним связыванием, поскольку *Ptr метода уже должен быть известен во время компиляции заранее полученного класса (и относится это исключительно к классам), но в других языках он будет являться поздним связыванием, т.к. они поддерживают более простое связывание методов с заранее предопределенными *Ptr-ами. Далее, для COM характерен IDispatch интерфейс для работы с заранее неизвестными объектами, связывание по которому при помощи disp-идентификатора является поздним. В ранних версиях VB мог использоваться лишь disp-интерфейс, а в 6 версии классы являются дуальными, поддерживая оба типа связывания. В случае отсутствия поддержки таблицы указателей методов, но хранения disp-идентификаторов для исключения необходимости их запроса во время выполнения такой подтип IDispatch-связывания будет ранним, однако при каких-либо изменениях требуется повторная компиляция. Наиболее простая, но медленная работа заключается в «позднем» связывании по имени с помощью каждый раз запрашивающегося идентификатора, а потом и обеспечения доступа к нужному методу. Следует заметить, что сами внутренние процедуры сопоставления по имени + доступ реализуются с помощью раннего связывания, но так как при обращении от объекта к методу это происходит 2 раза, связывание называется поздним. Частный случай: сопоставление «IDispatch – метод», также позднее. Другой, достаточно нетривиальный подвид позднего связывания – отличается однократным получением идентификатора имени, а при повторных обращениях используется его сохраненное значение. Еще один подвид – позднее связывание по виртуальным таблицам, в котором через IDispatch происходит однократное определение типа объекта для получения класса, но без непосредственного доступа к методу, после чего все вызовы происходят по виртуальной таблице. Раннее связывание по виртуальным таблицам использует исключительно виртуальные таблицы. В этом случае переменная может быть неизвестного типа, но не может быть объектной. Здесь нужные методы берутся из подключаемой библиотеки типов.
1. У проблемы «хочу DLL, не хочу регистрацию ActiveX и другие языки» существует множество обходных путей. 2. Работать из VB будут лишь простейшие функции а-ля «сумма-разность-инкремент-декремент» и им подобные, к тому же не имеющие практической ценности. Но тестировать следует и на другом. 3. Библиотеки, как правило, пишутся на других языках (PB, C/C++, Delphi и т.д.) и вызываются из VB, а не наоборот. Но обратный вариант «с автомобилем», если захотеть, реализовать на самом деле можно (см. Пример 3 – расчет хеша md5 и вызов формы из DLL на VB). После получения формы с помощью различных языков – функции можно вызывать прямо из нее. Пример можно найти на указанном выше сайте.
Проверено на XP/2003. Но экспериментировать все же лучше на VM (драйвер находится на том же сайте).
9
|
||||||||||||||||||||||||||||||||
|
|
||
| 19.08.2013, 17:39 | ||
|
Какой прием без "танцев с бубном" или с ними заставил VB работать без MSVBVM60.DLL - иначе загрузить в (ядерное) пространство драйвер невозможно!
1
|
||
|
|
|
| 19.08.2013, 22:18 | |
|
Хм, в "драйвере" (в кавычках, потому что это ИМХО не рабочий драйвер) должны быть вызовы функций ядра, а не MSVBVM60.DLL.
![]() На бейсике можно написать и скомпилировать рабочий драйвер без танцев с бубном, только речь идет не о VB.
0
|
|
|
|
||||||
| 20.08.2013, 00:52 | ||||||
|
Драйвер запускается, но это не драйвер, а хз что.
Его исполняемый код.
1
|
||||||
|
Модератор
|
||
| 20.08.2013, 14:05 | ||
|
0
|
||
| 22.08.2013, 21:26 [ТС] | ||
|
За критику спасибо!
Не по теме: На сайте: "Читать миллион раз 6 снизу строку комментариев! Примера больше не будет.", и что-то про то, что ваш IP в логах (хотя кому надо, будет прокси использовать). Не будет ещё одной ссылки, чтобы все это хорошо протестировать и проверить? Ведь в статье написано, что без бубна здесь не обойтись, а вы говорите, что ещё как можно и обойтись, так что нужно изучить и написать. По поводу драйвера - не уж то вы и в правду полноценный сделать смогли? И без "танцев", опять-таки?
2
|
||
|
Супер-модератор
|
||
| 22.08.2013, 21:43 | ||
|
Тем временем, я нашел хорошую статью на английском на тему "Как сделать полноценную процедурную DLL на VB". Эту статью я уже почти перевел и выполнил все, что описал автор. Процедурные DLL действительно получаются! Когда закончу перевод - выложу сюда (с примером и дополнением от себя). Постараюсь побыстрее.
1
|
||
|
|
||
| 22.08.2013, 21:58 | ||
|
Драйвер не полноценный и кроме того, содержит импорт WinAPI и VB-рантайма, что не допустимо в режиме ядра. Наверняка его еще допиливали после компиляции.
0
|
||
| 28.08.2013, 16:31 [ТС] | |
|
Не по теме: Да, осталось нам только драйвер нормальный сделать - докажем, что на VB можно делать всё что угодно.
0
|
|
| 28.08.2013, 16:47 | |
|
0
|
|
| 28.08.2013, 17:09 | |
|
0
|
|
| 28.08.2013, 17:15 | |
|
1
|
|
| 28.08.2013, 17:15 | |
|
Помогаю со студенческими работами здесь
19
Создание dll на основе Visual Basic
Можно ли в Visual Basic использовать стандартные Windows DLL? Visual Basic 6 DLL для работы с php файлами
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
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 .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|