Пример создания vxd драйвера на delphi


Содержание

DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники

Программирование USB-устройств в Delphi

Что такое HID-устройство

Свойства HID-устройства

Организация обмена данными между HID-устройством и компьютером

Чтобы описать взаимодействие HID-устройства с компьютером, употребим термин «хост». В данном случае под ним понимается управляющее устройство в общей физической архитектуре взаимодействия по USB-протоколу. Так, все порты в компьютере — хосты. К ним можно подключать различные USB-устройства (флэшки, мыши, веб-камеры, фотоаппараты и проч.), которые хоста не имеют. Хост обеспечивает обнаружение, подключение, отключение, конфигурирование устройств, а также сбор статистики и управление энергопотреблением.

HID-устройство может само установить частоту опроса, во время которого выясняется наличие в нем каких-либо новых данных. Значит, даже на таком низком уровне программист может довериться системе, поскольку частота опроса и другие параметры обмена данными должны быть заранее заданы в программе контроллера HID-устройства. Этим протокол HID отличается от общего описания USB 1.1 или USB 2.0, в котором нет жестких требований к организации протокола. Однако при специфических задачах, требующих повышенного уровня безопасности, может оказаться довольно сложно избавиться от циклических опросов, когда постоянно передаются почти одни и те же блоки данных.

Особенности программирования HID-устройств

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

В Windows за доступ к HID-устройствам отвечает системная служба HidServ. Подробнее о функциях запросов к HID-устройствам и других особенностях работы с HID-драйвером рассказывается в работе П.?В. Агурова «Интерфейс USB. Практика использования и программирования» (СПб.: БХВ-Петербург, 2005).

Программирование HID-устройств на «верхнем уровне»

Нелегкую жизнь «прикладных» программистов, работающих на Паскале, облегчает проверенный модуль HID. PAS, программная оболочка для hid. dll (Hid User Library — как указано в свойствах файла). В комментариях к файлу сообщается, что в основе его лежат модули hidsdi.h и hidpi.h корпорации Microsoft. А сам файл HID. PAS — часть пакета JEDI (http://jvcl.sourceforge.net ).

Для работы с HID-устройством в среде Delphi for win32 применяется компонент TJvHidDeviceController, представляющий собой удобный глобальный менеджер для доступа к HID-устройствам. А уже на его базе можно получить объектный экземпляр для работы с конкретным устройством.

Основные свойства и события компонента TJvHidDeviceController

Рассмотрим компонент TJvHidDeviceController более подробно. Событие OnArrival срабатывает на поступление (подключение) в систему HID-устройства, доступ к устройству предоставляется в обработчике этого события через экземпляр класса TJvHidDevice. Простое событие OnDeviceChange реагирует на изменение состояния устройства, оно только сигнализирует об изменениях в системе. Событие OnDeviceData срабатывает при поступлении данных от одного из HID-устройств и передает обработчику следующее: HidDev: TJvHidDevice; — устрой-ство, от которого были получены данные;

Событие OnDeviceDataError уведомляет об ошибке передачи данных, передавая в процедуру обработки параметры H >

Для последовательного перечисления имеющихся в системе HID-устройств по вызову метода Enumerate предназначено событие OnEnumerate, т. е. в обработчике события найденные устройства последовательно передаются в виде объектов. Это событие принудительно инициируется методом Enumerate, использующимся для «проведения» имеющихся HID-устройств через обработчик, например при ревизии состояния HID-устройств по инициативе хоста (компьютера).

Событие OnRemoval срабатывает на физическое извлечение устройства из системы и имеет тот же тип обработчика TJvHidUnplugEvent, что и для OnDeviceUnplug. Функция CountByProductName выдает количество устройств, удовлетворяющих указанному в аргументе имени продукта, а CountByVendorName — указанному в аргументе имени производителя.

Основные свойства и события класса TJvHidDevice

Класс TJvHidDevice — виртуальное представление отдельно взятого HID-устройства. Новый объект этого класса можно получить, как было уже сказано, из события OnArrival или OnEnumerate. Функционал классов TJvHidDeviceController и TJvHidDevice частично дублируется, поскольку в первом из них интегрированы общий инструментарий для работы с набором имеющихся в системе HID-устройств и механизм доступа к одному из них.

Устройство можно однозначно идентифицировать по свойствам SerialNumber, ProductName и VendorName. Чтобы получить сведения о поступлении данных с применением такого объекта, можно воспользоваться событием OnData. Отсылка данных ведется через метод WriteFile (в строгом смысле — через функцию). WriteFile — это оболочка системной функции WriteFile (kernel32).

Чтобы проконтролировать факт извлечения устройства, следует присвоить свой обработчик событию OnUnplug. Перед началом обмена данными с HID-устройством нужно удостовериться в самой возможности такого обмена с помощью HasReadWriteAccess. В этом классе на возникновение ошибки обмена данными даже есть отдельное событие OnDataError.

А теперь рассмотрим фрагменты кода из «живого» проекта, реализующего тестовое клиентское приложение для организации обмена данными с нестандартным устройством — пластиковыми чип-картами на базе HID. В борьбе за реализм автор взял на себя смелость не выкидывать из листингов «лишние» технологические обвязки кода.

Метод ScanDevices (листинг 1) предназначен для инициирования процесса поиска в системе необходимого HID-устройства. Большая часть кода, за исключением вызова метода Enumerate, необязательна и обеспечивает гибкость приложения, например, для того, чтобы в эту же тестовую программу можно было добавить возможность работы по интерфейсу, отличному от HID. Метод AddError выводит в окно отладочную информацию в процессе работы программы.

Листинг 1. Инициирование диска поиска устройства

В листинге 2 приведен обработчик события OnEnumerate для поиска необходимого внешнего устройства. Для простоты будем считать, что программа может работать только с одним устройством нужного ей типа.

Листинг 2. Обработчик поиска

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

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

Ибо лучшее решение — то, которое будет реализовано в сжатые сроки с минимальной привязкой к программной среде и с большими возможностями дальнейшего развития. На основе этих принципов был создан протокол обмена верхнего уровня, где главное понятие — «команда». Из листинга 3 видно, насколько автор любит строковые данные, не раз спасавшие его при отладке программных модулей. Как же замечательно, что у нас вообще есть тип String! Все команды протокола делятся на категории (классы), внутри которых существует код команды, однозначно характеризующий ее назначение. Параметр edParam служит для отсылки данных в устройство, а параметр edAnswerData содержит в себе полученные от устройства данные.

Строковый тип описанных членов записи позволяет свободно и наглядно манипулировать данными в формате HEX-строки. И что самое приятное, формат описанной записи идеологически стоит где-то посередине между ее непосредственным назначением и различными формами ее представления (INI, HEX, XML и т. д.)

Листинг 3. Пример структуры отсылки данных для описания алгортимов обмена данными с внешним устройством.

// структура соответствует протоколу

// верхнего уровня,
// оговоренному для специфического устройства.
TedCommand = RECORD Caption: String; // метка команды
INDEX:Integer;
// индекс команды Enabled:Boolean; // флаг пригодности команды
WT:Cardinal; // время обработки
edClass: String [2] ;// HBX-строка класса команды
edCode:String[2];// HEX-строка кода команды
edLength:String[2]; // длина
edParam: String; // HEX-CTpoкa (параметр отсылки)
edAnswerdta:String;// HEX-CTpoкa
// полученных данных
IsAnswerdta:Boolean;
// флаг новых полученных данных ERROR:String; // поле для последней ошибки
WORKED:Boolean; //флаг обработки команды
end;

Выполнение команды, т. е. отсылка данных в устройство, реализовано с применением отсылки пакетов данных длиной 8 байт (листинг 4). Эта длина — не единственное решение, такой выбор продиктован требованиями протокола верхнего уровня и в каждом конкретном случае может быть другим. Это, что называется, дело вкуса. Странный флаг IsUSBMode в методе ExecuteCommand (листинг 5 на «Мир ПК-диске») оставлен как напоминание о том, что вместо работы с USB нам может потребоваться использовать COM-порт или какой-то другой интерфейс. В начале отсылаемой группы данных в устройство передается синхросерия произвольно выбранного формата (например, 3E3E3E2B), сообщающая устройству, что у него на входе вполне легальные данные. Напомню, что в данном случае речь идет не столько о HID, сколько о специфическом протоколе верхнего уровня, идеологически оторванном от «железа» и предназначенном для решения особых прикладных задач.

Листинг 4. Отсылка данных

В обработчике GetDataExecutor полученных от устройства данных (пакет по 8 байт) использовано специально созданное событие OnNewInputData для передачи первично обработанных данных на дальнейшую обработку, причем с указанием их старого и нового значений (листинг 6 на «Мир ПК-диске»). Таким образом, события поступления необработанных данных и указание на дальнейшую обработку развязываются, позволяя добавлять какой-то специфический алгоритм предупреждения на раннем этапе ошибочной, повторной или ненужной входной информации.

Представленные здесь примеры работы с HID-устройством иллюстрируют общую идею статьи — относительную простоту программирования нестандартных HID-устройств средствами Delphi.

Научитесь программировать микроконтроллеры прямо сейчас — получить видеокурс по микроконтроллерам!

Keeper’s blog

== I’m starting with the man in the mirror ==

Social Icons

Pages

пятница, 18 сентября 2009 г.

Delphi всемогущий

Статья эта очень старая и датируется аж 2007 годом. Интересно и познавательно.

Ты пишешь на дельфях и чувствуешь себя аутсайдером? Тебе нечем ответить в бесконечных hollywar’ах? Теперь ты точно будешь знать: дельфи стоит того, чтобы его любить. И не только из-за простоты этого языка. Очень маленькие и очень быстрые программы на дельфи — это возможно! Ты расскажешь об этом всем сомневающимся. И с мнением, что дельфи — язык для ламеров, будет покончено!

Многие системные программисты привыкли считать Delphi полным отстоем. Свое мнение они аргументируют тем, что компилятор генерирует слишком медленный и большой код, а средний размер пустой формы с кнопкой — 400 килобайт. Впрочем, иногда никаких аргументов и вовсе не приводится. Когда на форумах сталкиваются поклонники С++ и Delphi, первые обычно кричат о супернавороченном синтаксисе и потрясающих возможностях ООП, при этом утверждая, что в системном программировании все это необходимо, а вторые — о возможностях того же ООП на дельфи, которых нет в С++, и о том, что на этом языке писать проще. Из слов и тех, и других можно заключить, что обе стороны ни про Delphi, ни про C++ ничего толком не знают, и все это — пустая ламерская болтовня.

Эта статья посвящена приемам системного программирования на Delphi. Она написана для тех, кто любит этот язык, хочет добиться максимальной эффективности кода и не боится вложить в свое дело определенный труд. Я покажу, как делать на дельфи то, что многие считают невозможным. Тем, кто занимается кодингом на С++, не составит труда найти целую кучу статей по оптимизации. Если же ты пишешь на Delphi, ты не найдешь на эту тему ничего хорошего. Видимо, все считают, что никакой оптимизации здесь не нужно. Может быть, тебя устраивает 400-килобайтная пустая форма с кнопкой? А, ты думаешь, что это неизбежное зло, и уже давно с ним смирился? Что ж, придется немного расстроить твои нервы и развеять священные заблуждения.

Немного о генерируемом компилятором коде

Для начала проверим утверждение, что компилятор Delphi генерирует много лишнего и неэффективного кода. Для этого напишем функцию, скачивающую и запускающую файл из интернета (такие вещи обычно используют в троянах). Писать будем, естественно, с применением API. Вот что у меня получилось:
Этот сорец я вставил в программу, скомпилировал и дизассемблировал в ida. Вот его откомментированный листинг:
Ну и где же куча лишнего кода, о котором некоторые так любят говорить? Все просто и красиво, почти то же самое можно написать вручную на ассемблере. Тем более, что на нем некоторые умники иногда такое выдают — любые ошибки компилятора покажутся мелочью :).
Почему же программы, написанные на дельфи, такие большие? Откуда берется лишний код, если компилятор его не генерирует? Сейчас мы разберем этот вопрос подробнее.

ООП — двигатель прогресса

ООП — весьма модное в настоящее время направление программирования. Его цель — упростить написание программ и сократить сроки их разработки, и с нею ООП прекрасно справляется. Большинство прикладных программистов, пишущих на С++ или Delphi, уже не мыслят своей деятельности без ООП. Их главный принцип — быстрее сдал программу, быстрее получил деньги. В таких условиях о какой бы то ни было оптимизации просто забывают.


А ведь если взглянуть на дело глазами системного программиста, то сразу станет очевиден главный недостаток: ООП — качество генерируемого кода. Допустим, у нас есть класс, наследуемый от другого класса. При создании объекта этого класса компилятор будет вынужден полностью включить в его состав также код родительского класса, поскольку нет возможности определить, какие методы классов использоваться не будут. Если у нас целое дерево наследования классов, как обычно и бывает в реальных программах, то весь его код войдет в программу, и от этого никуда не денешься. Вызов методов класса производится через таблицу, что увеличивает время вызова. А когда метод наследуется от родителя в десятом поколении, то и вызов проходит через десять таблиц, прежде чем достигает обрабатывающего его кода. Получается, что вместе с кучей мертвого кода мы получаем еще низкую эффективность рабочего. Все это хорошо видно на примере библиотеки VCL в дельфи.

А вот программа, написанная на VB или на VC с применением MFC, отчего-то занимает гораздо меньше места. Все потому, что великая и ужасная компания Microsoft приложила к этому свою лапу. MFC и runtime-библиотеки в VB весят ничуть не меньше, просто они скомпилены в DLL и входят в поставку Windows, а значит, их код не приходится таскать с собой в программах. В защиту Borland можно сказать, что такая возможность присутствует и в Delphi. Нужно просто в настройках проекта поставить галочку build with runtime packages, тогда программа значительно уменьшится, но потребует наличия соответствующих runtime-библиотек. Естественно, эти библиотеки в поставку винды не входят, но в этом надо винить не Борланд, а монопольную политику мелкософта.

Любители ООП, желающие разрабатывать программы в визуальном режиме, могут использовать kol. Это попытка сделать что-то типа VCL, но с учетом ее недостатков. Средний размер пустой формы с кнопкой — 35 Кб, что уже лучше, но для серьезных приложений эта библиотека не подходит, так как часто глючит. Да и решение это половинчатое.

Те, кто хочет добиться действительно высокой эффективности кода, должны идти по принципиально другому пути: забыть про ООП и все, что с ним связано, раз и навсегда. Писать программы придется только на чистом API.

Виновник номер два

Создадим в Delphi пустой проект, заведомо не содержащий никакого полезного кода:
После компиляции в Delphi 7 мы получаем экзешник размером в 13,5 Кб. Откуда?! Ведь в программе ничего нет! Ответ на этот вопрос опять поможет дать ida. Дизассемблируем экзешник и посмотрим, что он содержит. Точка входа в программу будет выглядеть так:
Весь лишний код находится в функциях _initexe и _handlefinally. Дело в том, что к каждой Delphi программе неявно подключается код, входящий в состав RTL (run time library). Эта либа нужна для поддержки таких возможностей языка, как ООП, работа со строками (string) и специфичные для паскаля функции (assignfile, readln, writeln, etc.). initexe выполняет инициализацию всего этого добра, а handlefinally обеспечивает корректное освобождение ресурсов.
Сделано это, опять же, для упрощения жизни программистам, и применение RTL иногда оправданно, так как может не понизить, а повысить эффективность кода. Например, в состав RTL входит менеджер кучи, который позволяет быстро выделять и освобождать маленькие блоки памяти. По своей эффективности он в три раза превосходит системный. В плане производительности генерируемого кода работа со строками реализована в RTL тоже довольно неплохо, правда все равно, в увеличении размера файла, RTL — виновник номер два после ООП.

Уменьшаем размер

Если минимальный размер в 13,5 Кб тебя не устраивает, то будем убирать Delphi RTL. Весь код либы находится в двух файлах: system.pas и sysinit.pas. К сожалению, компилятор подключает их к программе в любом случае, поэтому единственное, что можно сделать, — удалить из этих модулей весь код, без которого программа может работать, и перекомпилить модули, а полученные dcu-файлы положить в папку с программой.

Файл system.pas содержит основной код RTL и поддержки классов, но все это мы выбросим. Минимальное содержимое этого файла должно быть таким:
Описания структуры tguid компилятор требует в любом случае и без нее компилировать модуль отказывается. tinitcontext понадобится линкеру, если мы будем собирать dll. handlefinally — процедура освобождения ресурсов RTL, компилятору она тоже необходима, хотя может быть пустой.

Теперь урежем файл sysinit.pas, который содержит код инициализации и завершения работы RTL и управляет поддержкой пакетов. Нам хватит следующего:

initexe — процедура инициализации RTL для exe-файлов, initlib — для dll, halt0 — завершение работы программы. Все остальные лишние структуры и переменные, которые пришлось оставить, необходимы компилятору. Они не будут включаться в выходной файл и никак не повлияют на его размер.

Теперь положим эти два файла в папку с проектом и скомпилируем их из командной строки:
Избавившись от RTL, мы получили экзешник размером в 3,5 Кб. Борландовский линкер создает в исполняемом файле шесть секций, они выравниваются по 512 байт, к ним плюсуется PE-заголовок, что и дает эти 3,5 Кб.

Но вдобавок к малому размеру мы получаем и определенные затруднения, так как теперь не сможем использовать заголовочные файлы на WinAPI, идущие с Delphi. Вместо них придется писать свои. Это нетрудно, поскольку описания используемых API можно брать из борландовских хедеров и переносить в свои по мере необходимости.

Илон Маск рекомендует:  Что такое код ncurses_scr_init

Если в составе проекта есть несколько pas-файлов, линкер для выравнивания кода вставит в него пустые участки, и размеры опять увеличатся. Чтобы этого избежать, нужно всю программу, включая определения API, помещать в один файл. Это весьма неудобно, поэтому лучше воспользоваться директивой препроцессора $include и разнести код на несколько inc-файлов. Тут может встретиться еще одна проблема — повторяющийся код (когда несколько inc-файлов подключают один и тот же inc) компилятор в таких случаях компилировать откажется. Выйти из положения можно, воспользовавшись директивами условной компиляции, после чего любой inc-файл будет иметь вид:
Таким образом, можно писать без RTL достаточно сложные программы и забыть о неудобствах.

Можно еще меньше!

Наверняка минимальный размер экзешника в 3,5 Кб удовлетворит не всех. Что ж, если постараться, можно ужать его еще в несколько раз. Для этого нужно отказаться от удобств работы с борландовским линкером и собирать исполнимые файлы линкером от Microsoft. К сожалению, здесь нас ждет одна загвоздка. Мелкософтовский линкер использует в качестве основного рабочего формата coff, но может понимать и интеловский omf. Однако программисты Борланда (видать, нарочно) в версиях Delphi выше третьей изменили генерируемый формат obj-файлов так, что теперь он несовместим с intel omf. То есть теперь существуют два вида omf: intel omf и borland omf. Программы, способной конвертировать объектные файлы из формата borland omf в coff или intel omf, я не нашел. Поэтому придется использовать компилятор от Delphi 3, который генерирует стандартный объектный файл intel omf. Импорт используемых API нам тоже придется описывать вручную, причем достаточно необычным способом. Для начала возьмем библиотеку импорта user32.lib из состава Visual C++ и откроем ее в hex-редакторе. Имена функций в ней имеют вид «_messageboxa@16», где после @ идет размер передаваемых параметров. Следовательно, объявлять функции мы будем таким образом:

Попробуем теперь написать helloworld как можно меньшего размера. Для этого создаем проект такого типа:
Тип модуля unit нужен для того, чтобы компилятор генерировал в объектном файле символьные имена объявленных процедур. В нашем случае это будет процедура start — точка входа в программу. Теперь компилируем проект следующей строкой:
Новый файл helloworld.obj открываем в hex-редакторе и смотрим, во что превратилась наша точка входа. У меня получилось start$qqrv. Это имя нужно указать как точку входа при сборке исполнимого файла. И наконец, выполним сборку:
В результате мы получаем работающий helloworld размером в 832 байта! Я думаю, что этот размер удовлетворит любого. Попробуем теперь дизассемблировать этот файл в ida и поискать лишний код:
Ни байта лишнего кода! Покажи этот пример всем, кто любит говорить о большом размере программ, написанных на дельфи, и понаблюдай за их выражением лица — это прикольно :). Самые упорные промычат: [А. Э. Все равно дерьмо!], но уже никто ничего не скажет по существу. А самые продвинутые спорщики приведут последний аргумент — на Delphi нельзя написать драйвер режима ядра для windows nt. Ничего. сейчас и они присоединятся к проигравшим :).

Пишем драйвер на Delphi

О том, как по нашей методике сделать невозможное — написать на Delphi драйвер режима ядра, даже есть статья на RSDN, и всем интересующимся я рекомендую ее прочитать. Здесь же я приведу пример простейшего драйвера и содержимое make.bat для его сборки.
Файл make.bat:
Для компиляции нам понадобится файл ntoskrnl.lib из ddk. Мы получим драйвер размером в килобайт, который выводит сообщение [hello world] в отладочную консоль и возвращает ошибку, а потому не остается в памяти и не требует определения функции driverunload. Для запуска драйвера используй kmdmanager от four-f. Увидеть результаты его работы можно в софтайсе или dbgview.

Главная проблема, из-за которой на Delphi нельзя писать полноценные драйвера, — отсутствие ddk. Для написания драйверов нужны заголовочные файлы на API-ядра и описания большого количества системных структур. Все это богатство есть только для С (от Microsoft) и для masm32 (от four-f). Есть слух, что ddk для паскаля уже существует, но автор продает его за деньги и сильно этот факт не афиширует. Думаю, когда-нибудь все-таки найдутся энтузиасты, которые перепишут ddk на паскаль и выложат для всеобщего использования. Другой проблемой является то, что большинство примеров, связанных с системным программированием, написаны на си, поэтому на каком бы языке ты ни писал свои программы, си знать придется. Это, конечно, не означает, что придется изучать С++ в полном его объеме. Для понимания системных программ хватит базовых знаний синтаксиса, все остальное же используется только в прикладных программах, которые нас совершенно не интересуют.

Переносимость кода

При программировании на стандартных Delphi компонентах, кроме кучи недостатков, мы получаем одно достоинство — некоторую переносимость кода. Если программа использует только возможности языка, но не возможности системы, то она будет легко компилироваться в Kilix и работать в Linux. Вся проблема в том, что без использования возможностей системы мы получим настоящее глюкалово, тяжелую и неэффективную программу. Тем не менее, при написании серьезных программ по вышеописанным методикам, все-таки хочется иметь некоторую независимость от системы. Получить ее очень просто — достаточно писать код, не использующий ни API-функций, ни возможностей языка вообще. В некоторых случаях это совершенно невозможно (например, в играх), но иногда функции системы абсолютно не нужны (например, в математических алгоритмах). В любом случае, следует четко разделять машинно-зависимую и машинно-независимую (если такая есть) части кода. При соблюдении вышеописанных правил машинно-независимая часть будет совместима на уровне исходных текстов с любой системой, для которой есть компилятор паскаля (а он есть даже для pic-контроллеров). Независимый от API код можно смело компилировать в dll и использовать, например, в драйвере режима ядра. Также такую dll не составит труда использовать и в других ОС. Для этого нужно просто посекционно отмапить dll в адресное пространство процесса, настроить релоки и смело пользоваться ее функциями. Осуществляющий это код на паскале занимает около 80 строк. Если же dll все-таки использует некоторые API-функции, то их наличие можно проэмулировать, заполнив таблицу импорта dll адресами заменяющих их функций в своей программе.

Общие приемы оптимизации

1) Старайся везде, где можно, использовать указатели. Никогда не передавай данные в функцию таким образом:
Всегда передавай указатели на структуры:
Такой вызов происходит быстрее и экономит немалое количество кода.

2) Старайся не пользоваться типом данных string, вместо него всегда можно использовать pchar и обрабатывать строки вручную. Если нужен временный буфер для хранения строки, то его следует объявить в локальных переменных как array of char.

3) Старайся передавать в функцию не больше трех параметров: первые три параметра согласно методу вызова fastcall (который по умолчанию применяется в Delphi) передаются в регистрах, а все последующие через стек, что замедляет доступ к ним и увеличивает размер кода.

4) Экономь память: если, например, у тебя есть массив чисел, диапазон которых укладывается в байт, то не нужно объявлять его как dword. Никогда не стоит писать повторяющийся код. Если какие-либо действия должны повторяться, то их нужно вынести в функцию. Тем не менее, не стоит делать функцию, содержащую две строчки кода, — ее вызов может занимать куда больше места, чем она сама.

И помни главное: эффективность кода в первую очередь определяется не компилятором, а примененным алгоритмом, что эффективнее!

З.Ы. Статья была частично мной подкорректирована, если вы заметили ошибки, черкните их в комментариях.

Пример создания Vxd-драйвера на Delphi

Компиляция данного примера возможна только с Delphi 3. Delphi 2 не был опробован в связи с его отсутствием, объектные фалы созданные Delphi 4 отвергаются Microsoft ® Linker 5.12.8181 как файлы неизвестного формата.
При написании данного материала были использованы Microsoft ® Macro Assembler ver. 6.11d и Microsoft ® Incremental Linker ver. 5.12.8181 из поставки Windows 98DDK

VxD драйвера делятся два типа:

Статические Загружаются в память при загрузке операционной системы и присутствуют в памяти постоянно
Динамические Загружаются в память при первом обращении к драйверу и могут быть выгружены при закрытии последнего дескриптора VxD.
Практически возможно создание драйвера поддерживающего оба типа загрузки.

Нам необходим динамически загружаемый VxD драйвер (далее «VxD») т.к. такой драйвер можно будет без перезагрузки Windows загружать из Win32® приложений используя процедуру CreateFile().

Когда Win32 приложение открывает дескриптор для VxD, виртуальное устройство VWIN32 используя сервис LoadDevice загружает VxD-драйвер в память и посылает информационное сообщение W32_DEVICEIOCONTROL загруженному VxD.

Таким образом для построения VxD необходимо обрабатывать как минимум три системных сообщения:

SYS_DYNAMIC_DEVICE_INIT
SYS_DYNAMIC_DEVICE_EXIT
W32_DEVICEIOCONTROL.
Собщение SYS_DYNAMIC_DEVICE_INIT посылается при попытке динамической загрузки VxD, SYS_DYNAMIC_DEVICE_EXIT посылается при попытке динамической выгрузке. Из обработчиков сообщений для подтверждения успеха необходимо вернуть VXD_SUCCESS в регистре AX
Сообщение W32_DEVICEIOCONTROL имеет следующие значения для параметра dwService

DIOC_OPEN — посылается посылается при открытии дескриптора VxD функцией CreateFile() только после SYS_DYNAMIC_DEVICE_INIT. В случае успеха необходимо вернуть NO_ERROR (0);
DIOC_CLOSEHANDLE — посылается при закрытии дескриптора VxD функцией API CloseHandle() и только перед SYS_DYNAMIC_DEVICE_EXIT
(Значение > 0) — Номер функции, заданный в параметре dwIoControlCode при обращении к VxD функцией API DeviceIoControl
Загрузочный модуль (vxdmain.asm)

При обращении к процедурам находящимся в модулях Delphi надо учесть для fastcall-процедур к имени добавляется в начале символ «@»

.
extrn SysDynamicDeviceInit :PROC
extrn SysDynamicDeviceExit :PROC
extrn W32DeviceIoControl :PROC
.
Control_0 proc
cmp eax, SYS_DYNAMIC_DEVICE_INIT
jnz short chkSysDynExit
call SysDynamicDeviceInit
cmp eax, 1
retn
;————-

chkSysDynExit:
cmp eax, SYS_DYNAMIC_DEVICE_EXIT
jnz short chkDevIOCtl
call SysDynamicDeviceExit
cmp eax, 1
retn
;————-
chkDevIOCtl:
cmp eax, W32_DEVICEIOCONTROL
jnz short loc_ret
push esi
push edx
push ebx
push ecx
call W32DeviceIoControl
cmp eax, 1
retn
;————-
loc_ret:
clc
retn

Delphi создает код для инициализации/деинициализации модулей, обращаясь к внешним процедурам HandleFinaly и initialization даже если блоки initilization и finalization в модуле отсутствуют. Создадим пустую «заглушку» для этих процедур и объявим их доступными для внешних модулей.

.
Public @@HandleFinally
Public @initialization
.
@@HandleFinally:
@initialization:
ret
.
end.

Процедурный модуль (vxdProcs.pas)

procedure ShellMessage(Handle, Flags : integer;
const Message, Caption : PChar;
Callback, ReferenceData : pointer); stdcall; assembler;
asm
mov ebx, Handle // virtual machine handle
mov eax, Flags // message box flags
mov ecx, Message // address of message text
mov edi, Caption // address of caption text
mov esi, Callback // address of callback
mov edx, ReferenceData // reference data for callback

int 20H // VxDCall
dd 170004h // Shell_Message
end;

const
Copyright : PChar = ‘© 1999 Emil Biserov, ‘+
‘fatty@mail.primorye.ru, http://dinfo.da.ru’;

function SysDynamicDeviceInit : INTEGER;
begin
ShellMessage(0, $10, Copyright,
‘SysDynInit: Hello from Delphi VxD . ‘, nil, nil);
Result := VXD_SUCCESS;
end;

function SysDynamicDeviceExit : INTEGER;
begin
ShellMessage(0, $10, Copyright,
‘SysDynDevExit: Bye from Delphi VxD . ‘, nil, nil);
Result := VXD_SUCCESS;
end;

var
Str : array [0..16] of char;

function W32DeviceIoControl(dwService : INTEGER;
dwDDB : INTEGER;
hDevice : INTEGER;
lpDIOCParms : pointer) : INTEGER;
begin
ShellMessage(0, $10, Copyright, ‘W32DevIOCtl’, nil, nil);

if (dwService = DIOC_OPEN) then
begin
Result := NO_ERROR;
end
//
//
else if (dwService = DIOC_CLOSEHANDLE) then
begin
Result := VXD_SUCCESS;
end
else if (dwService > MAX_PASVXD_W32_API) then
begin
Result := ERROR_NOT_SUPPORTED;
end
else
begin
Result := VXD_SUCCESS;
end;
end;


Инструмент для загрузки/выгрузки VxD

Представляет из себя простую форму с двумя кнопками. Приведу лишь методы для открытия и закрытия VxD драйвера.

const
VxDName = ‘\\.\DELPHIIO.VXD’;

function TVxDTestForm.OpenVxDDriver: boolean;
begin
HVxDHandle := CreateFile(VxDName,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
Result := HVxDHandle <> INVALID_HANDLE_VALUE;
end;

procedure TVxDTestForm.CloseVxDDriver;
begin
if HVxDHandle <> INVALID_HANDLE_VALUE then begin
CloseHandle(HVxDHandle);
HVxDHandle := INVALID_HANDLE_VALUE;
end;
end;

Выгрузку неиспользуемого модуля можно производить автоматически, указав в параметрах CreateFile(. FILE_FLAG_DELETE_ON_CLOSE,). В данном случае система при каждом открытии дескриптора к VxD будет увеличивать внутренний счетчик использования на 1 и вычитать 1 при закрытии дескриптора. При значении счетчика равном нулю VxD будет автоматически выгружен.

Драйвера на Delphi писать можно. Но вот только стоит ли?
Использование VxD имеет смысл только для использования Windows 3.1 и Windows 95. Да и доступ к аппаратным ресурсам в них гораздо прозрачнее чем Windows NT/2000. Windows 98, Windows NT и Windows2000 поддерживают новую модель драйверов WDM 1.0/2.0, использующую формат PE (Portable Executable) и (предположительно) проблем будет меньше, чем с VxD и его LE (Linear Executable) форматом драйверов.

Supporting Input-Output Control in VxDs
Loading and Opening the VxD
Opening the VxD
Calling DeviceIoControl on Windows 95/98

Developing.ru

VxD драйвера

Модератор: Andy

Aleksandr, можно долго и упорно это дело расписывать, но нет времени и необходимости.

В разделе полезные ссылки есть линк на великолепный сайт Iczelion’а — http://win32asm.cjb.net/. Там смотрите раздел Туториалы. Сайт на фреймах — так что точную ссылку дать не могу. Так вот в этом разделе есть все что нужно про VxD. Лучше и подробнее нигде не найдете, честное благородное слово.

ЗЫ. Лично если мне что-то надо сделать — я первым делом частенько туду заглядываю, и Вам рекомендую %)

Драйвер — это просто

Многие считают что самому создать драйвер для Windows это что-то на грани фантастики. Но на самом деле это не так. Конечно, разработка драйвера для какого-то навороченного девайса бывает не простой задачей. Но ведь тоже самое можно сказать про создание сложных программ или игр. В разработке простого драйвера нет ничего сложного и я попытаюсь на примерах это показать.

Сперва нам нужно определится в чем мы же будем создавать наш первый драйвер. Поскольку материал ориентирован на новичков, то язык программирования был выбран один из простых, и это не Си или ассемблер, а бейсик. Будем использовать один из диалектов бейсика — PureBasic. Из коробки он не обучен создавать драйверы, но у него удачный набор файлов, используемых для компиляции и небольшое шаманство позволяет добавить эту возможность. Процесс компиляции состоит из нескольких этапов. Если кратко, то он происходит следующим образом: Сначала транслятор «перегоняет» basic-код в ассемблер, который отдается FASM’у (компилятор ассемблера), который создает объектный файл. Далее в дело вступает линкер polink, создающий исполняемый файл. Как компилятор ассемблера, так и линкер могут создавать драйверы и если немного изменить опции компиляции, то получим не исполняемый файл, типа EXE или DLL, а драйвер режима ядра (SYS).

Скачать немного модифицированную бесплатную демо версию PureBasic 4.61 x86 можно на файлопомойке, зеркало.
Если нужно создать драйвер для x64 системы, качайте эту версию, зеркало.

Дистрибутивы имеют небольшие размеры, около 3 МБ каждый. С помощью этой версии можно создавать только драйвера.
Скачиваем, распаковываем и запускаем, кликнув по файлу «PureBasic Portable». При этом запустится IDE и вылезет окошко с сообщением что это демо-версия и списком ограничений. Из него наиболее существенным является ограничение числа строк кода, равное 800, а для создания простых драйверов этого может хватить. Остальные ограничения в нашем случае, не существенны.

Окно IDE с загруженным кодом драйвера показано на скрине.

Компиляция драйвера выполняется через меню «Компилятор» (это если кто не понял).

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

Может показаться что это куча бессмысленного кода, но это не так.

У каждого драйвера должна быть точка входа, обычно у нее имя DriverEntry() и выполнена она в виде процедуры или функции. Как видите, в этом драйвере есть такая процедура. Если посмотрите на начало кода, то в первых строках увидите как ей передается управление. В этой процедуре происходит инициализация драйвера. Там же назначается процедура завершения работы драйвера, которая в нашем случае имеет имя UnloadDriver(). Процедуры CreateDispatch() и CloseDispatch() назначаются обработчиками соединения и отсоединения проги из юзермода.
Процедура DeviceIoControl() будет обрабатывать запросы WinAPI функции DeviceIoControl(), являющейся в данном драйвере связью с юзермодом. В конце кода расположена так называемая ДатаСекция (DataSection), в которой находятся имена драйвера, сохраненные в формате юникода (для этого использована одна из фишек ассемблера FASM).

Теперь рассмотрим как драйвер будет взаимодействовать с внешним миром. Это происходит в процедуре DeviceIoControl(). В ней отслеживается одно сообщение, а именно — #IOCTL_MyPlus, которое отправляет юзермодная прога, когда ей нужно сложить два числа в режиме ядра (круто звучит, правда?). Когда такое сообщение получено, то считываем из системного буфера, адрес указателя на структуру со слагаемыми, производим сложение и результат помещаем в системный буфер. Собственно это основная задача нашего первого драйвера.

Видите сколько понадобилось кода для выполнения простейшей математической операции — сложения двух чисел?

А теперь рассмотрим программу, работающую с этим драйвером. Она написана на том же PureBasic.

При старте программы вызывается функция OpenDriver(), которая загружает драйвер. Для упрощения, имя драйвера, имя службы и описание службы заданы одинаковыми — «pbDrPlus». Если загрузка неудачная, то выводится соответствующее сообщение и программа завершает свою работу.

Процедура Plus() осуществляет связь с драйвером. Ей передаются хэндл, доступа к драйверу и слагаемые числа, которые помещаются в структуру и указатель на указатель которой, передается драйверу. Результат сложения чисел будет в переменной «Result».

Далее следует код простейшего GUI калькулятора, скопированного из википедии.

Когда закроют окно, то перед завершением работы программы, закрывается связь с драйвером и производится его деинсталляция из системы.

Результат сложения чисел 8 и 2 на скриншоте.

Исходные коды драйвера и программы, можно найти в папке «Examples», PureBasic на файлопомойке, ссылку на который давал в начале статьи. Там так же найдете примеры драйвера прямого доступа к порам компа и пример работы с памятью ядра.

PS.
Помните, работа в ядре чревата мелкими неожиданностями аля, BSOD (синий экран смерти), поэтому экспериментируйте осторожно и обязательно всё сохраняйте перед запуском драйвера.

За возможную потерю данных, я ответственности не несу!

Пример создания Vxd-драйвера на Delphi

Компиляция данного примера возможна только с Delphi 3. Delphi 2 не был опробован в связи с его отсутствием, объектные фалы созданные Delphi 4 отвергаются Microsoft ® Linker 5.12.8181 как файлы неизвестного формата.
При написании данного материала были использованы Microsoft ® Macro Assembler ver. 6.11d и Microsoft ® Incremental Linker ver. 5.12.8181 из поставки Windows 98DDK

VxD драйвера делятся два типа:

Статические Загружаются в память при загрузке операционной системы и присутствуют в памяти постоянно
Динамические Загружаются в память при первом обращении к драйверу и могут быть выгружены при закрытии последнего дескриптора VxD.
Практически возможно создание драйвера поддерживающего оба типа загрузки.

Илон Маск рекомендует:  Захват видео с камеры с помощью JavaScript и HTML5

Нам необходим динамически загружаемый VxD драйвер (далее «VxD») т.к. такой драйвер можно будет без перезагрузки Windows загружать из Win32® приложений используя процедуру CreateFile().

Когда Win32 приложение открывает дескриптор для VxD, виртуальное устройство VWIN32 используя сервис LoadDevice загружает VxD-драйвер в память и посылает информационное сообщение W32_DEVICEIOCONTROL загруженному VxD.

Таким образом для построения VxD необходимо обрабатывать как минимум три системных сообщения:

SYS_DYNAMIC_DEVICE_INIT
SYS_DYNAMIC_DEVICE_EXIT
W32_DEVICEIOCONTROL.
Собщение SYS_DYNAMIC_DEVICE_INIT посылается при попытке динамической загрузки VxD, SYS_DYNAMIC_DEVICE_EXIT посылается при попытке динамической выгрузке. Из обработчиков сообщений для подтверждения успеха необходимо вернуть VXD_SUCCESS в регистре AX
Сообщение W32_DEVICEIOCONTROL имеет следующие значения для параметра dwService

DIOC_OPEN — посылается посылается при открытии дескриптора VxD функцией CreateFile() только после SYS_DYNAMIC_DEVICE_INIT. В случае успеха необходимо вернуть NO_ERROR (0);
DIOC_CLOSEHANDLE — посылается при закрытии дескриптора VxD функцией API CloseHandle() и только перед SYS_DYNAMIC_DEVICE_EXIT
(Значение > 0) — Номер функции, заданный в параметре dwIoControlCode при обращении к VxD функцией API DeviceIoControl
Загрузочный модуль (vxdmain.asm)

При обращении к процедурам находящимся в модулях Delphi надо учесть для fastcall-процедур к имени добавляется в начале символ «@»

.
extrn SysDynamicDeviceInit :PROC
extrn SysDynamicDeviceExit :PROC
extrn W32DeviceIoControl :PROC
.
Control_0 proc
cmp eax, SYS_DYNAMIC_DEVICE_INIT
jnz short chkSysDynExit
call SysDynamicDeviceInit
cmp eax, 1
retn
;————-

chkSysDynExit:
cmp eax, SYS_DYNAMIC_DEVICE_EXIT
jnz short chkDevIOCtl
call SysDynamicDeviceExit
cmp eax, 1
retn
;————-
chkDevIOCtl:
cmp eax, W32_DEVICEIOCONTROL
jnz short loc_ret
push esi
push edx
push ebx
push ecx
call W32DeviceIoControl
cmp eax, 1
retn
;————-
loc_ret:
clc
retn

Delphi создает код для инициализации/деинициализации модулей, обращаясь к внешним процедурам HandleFinaly и initialization даже если блоки initilization и finalization в модуле отсутствуют. Создадим пустую «заглушку» для этих процедур и объявим их доступными для внешних модулей.

.
Public @@HandleFinally
Public @initialization
.
@@HandleFinally:
@initialization:
ret
.
end.

Процедурный модуль (vxdProcs.pas)

procedure ShellMessage(Handle, Flags : integer;
const Message, Caption : PChar;
Callback, ReferenceData : pointer); stdcall; assembler;
asm
mov ebx, Handle // virtual machine handle
mov eax, Flags // message box flags
mov ecx, Message // address of message text
mov edi, Caption // address of caption text
mov esi, Callback // address of callback
mov edx, ReferenceData // reference data for callback

int 20H // VxDCall
dd 170004h // Shell_Message
end;

const
Copyright : PChar = ‘© 1999 Emil Biserov, ‘+
‘fatty@mail.primorye.ru, http://dinfo.da.ru’;


function SysDynamicDeviceInit : INTEGER;
begin
ShellMessage(0, $10, Copyright,
‘SysDynInit: Hello from Delphi VxD . ‘, nil, nil);
Result := VXD_SUCCESS;
end;

function SysDynamicDeviceExit : INTEGER;
begin
ShellMessage(0, $10, Copyright,
‘SysDynDevExit: Bye from Delphi VxD . ‘, nil, nil);
Result := VXD_SUCCESS;
end;

var
Str : array [0..16] of char;

function W32DeviceIoControl(dwService : INTEGER;
dwDDB : INTEGER;
hDevice : INTEGER;
lpDIOCParms : pointer) : INTEGER;
begin
ShellMessage(0, $10, Copyright, ‘W32DevIOCtl’, nil, nil);

if (dwService = DIOC_OPEN) then
begin
Result := NO_ERROR;
end
//
//
else if (dwService = DIOC_CLOSEHANDLE) then
begin
Result := VXD_SUCCESS;
end
else if (dwService > MAX_PASVXD_W32_API) then
begin
Result := ERROR_NOT_SUPPORTED;
end
else
begin
Result := VXD_SUCCESS;
end;
end;

Инструмент для загрузки/выгрузки VxD

Представляет из себя простую форму с двумя кнопками. Приведу лишь методы для открытия и закрытия VxD драйвера.

const
VxDName = ‘\\.\DELPHIIO.VXD’;

function TVxDTestForm.OpenVxDDriver: boolean;
begin
HVxDHandle := CreateFile(VxDName,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
Result := HVxDHandle <> INVALID_HANDLE_VALUE;
end;

procedure TVxDTestForm.CloseVxDDriver;
begin
if HVxDHandle <> INVALID_HANDLE_VALUE then begin
CloseHandle(HVxDHandle);
HVxDHandle := INVALID_HANDLE_VALUE;
end;
end;

Выгрузку неиспользуемого модуля можно производить автоматически, указав в параметрах CreateFile(. FILE_FLAG_DELETE_ON_CLOSE,). В данном случае система при каждом открытии дескриптора к VxD будет увеличивать внутренний счетчик использования на 1 и вычитать 1 при закрытии дескриптора. При значении счетчика равном нулю VxD будет автоматически выгружен.

Драйвера на Delphi писать можно. Но вот только стоит ли?
Использование VxD имеет смысл только для использования Windows 3.1 и Windows 95. Да и доступ к аппаратным ресурсам в них гораздо прозрачнее чем Windows NT/2000. Windows 98, Windows NT и Windows2000 поддерживают новую модель драйверов WDM 1.0/2.0, использующую формат PE (Portable Executable) и (предположительно) проблем будет меньше, чем с VxD и его LE (Linear Executable) форматом драйверов.

Supporting Input-Output Control in VxDs
Loading and Opening the VxD
Opening the VxD
Calling DeviceIoControl on Windows 95/98

Подключение из Delphi через драйвер к MySQL

Хочу подключиться из Delphi к MySQL
скачал mysql-connector-odbc-5.2.7-winx64.msi
Установил. Завёл Delphi XE, но в списке «Создание нового источника данных» данный драйвер в списке не присутствует.
Как его ещё устанавливать? Или где-то прописывать ручками, что-то надо?

2 ответа 2

Дело в том, что Вы используете 64-разрядный драйвер. А, Delphi как была, так и сейчас осталась 32-разрядной. Поэтому Delphi его и не «видит».

Проблема обычно решается установкой 32-разрядного драйвера.

P.S. Для версии XE2 и выше это замечание также актуально. 64-разрядный там, по сути, только компилятор под Win64. Сама IDE по прежнему 32-разрядная и «видит» только 32-разрядные драйвера.

Все зависит от целевой платформы 32 ли 64 бит и типа подключения. Если используется dbGo (TADOConnection) тогда для каждой (32/64) нужно устанавливать свой ODBC Connector. И вручную создавать пользовательские, файловые или системные DSN выбрав соответсвенно драйвер MySQL. Но поставщиком данных нужно все равно выбирать Microsoft OLE DB Provider for ODBC!

А вот с использованием DbExpress или FireDAC все не так однозначно. IDE может сильно ругаться приблизительно такими словами:

DBX error: Driver could not be properly initialized Client library May be missing, of the wrong version, May be missing from the driver or the system path.

Delphi. FireDac. Работа с драйверами БД

Известно, что большинство производителей баз данных выпускают к ним драйвера, которые и помогают нашим приложениям работать быстро и правильно. Я, например, работаю с базой MySQL, и для 32 разрядных приложений существует драйвер libmysql.dll О том как его подключить, используя компоненты доступа к БД FireDAC мы и поговорим в данное статье.

За основу статьи, я взял официальную документацию

Старая версия мне нравится больше тем, что там удобное, раскрывающееся дерево с левой стороны, а новая версия хороша тем, что там практически весь код корректен. В старой версии использованы аббревиатуры AD, что означает AnyDAC, а в новой версии использованы аббревиатуры FD, что означает FireDAC.

Как подключить драйвер к нашему приложению?

Существует 2 способа

– через файл FDDrivers.ini

– через компонент TFDPhysXxxDriverLink

В данной статье мы рассмотрим оба способа.

Как подключить драйвер через FDDrivers.ini ?

Для начала посмотрим, где находится этот самый файл. По умолчанию, при установке Delphi он находится в директории

C:\Users\Public\Documents\Embarcadero\Studio\FireDAC\FDDrivers.ini

Когда я его открыл, он был у меня практически пустым и состоял всего из 2 строк

[FDDrivers.ini]
Encoding=UTF8

Теперь узнаем что позволяет сделать FDDrivers.ini?

-настроить параметры базового драйвера (для всех описаний драйверов обязательна секция BaseDriver >

-настроить так называемые виртуальные драйвера для того, чтобы, например, в одном и том же приложении использовать возможность подключаться к разным версиям сервера БД, для того, чтобы дать понять FireDAC, что у нас виртуальный драйвер, нам надо саму секцию назвать с какой-нибудь добавкой, например, таким образом

Обратите внимание, мы подписали секцию [MySQL_Virtual], если бы мы оставили [MySQL], то FireDAC не стал бы регистрировать новое описание драйверов.

Базовые и виртуальные драйвера

Базовый драйвер – это то, что уже заложено в FireDAC, базовые драйвера можно просмотреть, например из выпадающего списка компонента FDConnection. Создадим VCL приложение, добавим на него компонент FDConnection, кликнем по нему 2 раза и у нас появится окно редактирования соединения. Далее, кликнем на выпадающий список, напротив DriverID

Виртуальный драйвер в этом списке отсутствует, но мы можем добавить его в файле FDDrivers.ini “ручками”, прописав туда следующий код.

Далее, чтобы воспользоваться услугами этого драйвера, нам нужно в компоненте FDManager прописать свойство DriverDefFileName и поставить DriverDefFileAutoLoad в True. После этого, например, при создании ConnectionDefinition, мы можем, например указать, в свойстве DriverID свойство MySQL_Virtual

То есть, код мог бы быть таким…

А само подключение обработать таким образом

Зачем нужны виртуальные драйвера?

-работать с различными версиями DBMS (DataBase Management System) в разных соединениях (FDConnections), думаю, можно работать одновременно даже с разными БД в разных соединениях

-настраивать параметры драйверов, например параметры MySQL Embedded

Здесь все достаточно просто, нужно добавить компонент TFDPhysXxxDriverLink на форму и настроить следующие свойства

VendorLib, например C:\MySQLDriver\libmysql.dll


VendorHome это директория, в которую установлен сервер, например C:\Program Files\MySQL\MySQL Server 5.5

Если прописать VendorHome, то FireDac будет сначала искать libmysql.dll в этой директории.

Обратите внимание!

У меня, например 64 разрядная версия MySQL, и драйвер, соответственно там тоже 64 разрядный, если его использовать, будет выскакивать ошибка. Поэтому я свойство VendorHome не прописывал, а только свойство Vendorlib, здесь я прописал путь к 32 разрядной версии драйверов, так как в Delphi компилировал 32 разрядное приложение.

Разработка CGI приложений на Delphi

В последнее время в связи с растущей популярностью сети Интернет все чаше становится необходимость разработки приложений, которые бы могли работать непосредственно в www среде. Т.е. такие, которые бы полностью бы интегрировались в уже привычные нам веб-странички. По сути дела работа с таким приложением происходит полностью через любимый браузер пользователя и ничем не отличается от серфинга по страничкам. Ввод данных равно как и выдача обработанных результатов происходит через html-формы веб-страничек. Обработка же данных происходит на веб-сервере. Таким образом, мы получим самое что ни есть клиент-серверное приложение в его самом классическом понимании.

Необходимо отметить, что CGI-приложения разрабатываемые в средах разработки ориентированных на Win32 системы, в том числе и в Дельфи, а вернее серверная часть такого приложения может работать только под Win32 сервером, например IIS из NT или Personal Web Server из Windows98. Что касается клиентской части, то здесь никаких проблем совместимости не должно быть в принципе, т.к. клиентская часть представляет собой сгенерированный HTML код, который поддерживается любым браузером, не важно какую платформу использует пользователь, будь то Win32, OS/2, Unix и др.

Таким образом, программисту пишушему CGI-приложения придется столкнуться с двумя основными задачами — это разработка веб-интерфейса и разработка непосредственно математической части приложения.

Что касается веб-интерфейсов, то здесь желательно знать хотя бы основы языка HTML. Здесь мы не будем уделять этому особое внимание, хотя знание HTML для программиста CGI-приложений очень желательно. Сейчас же для нас будет вполне достаточным знание таких основопологающих тэгов как , и конструкции ===cut==

Далее идет пример непосредственно CGI приложения. Следует отметить, что приведенный в этом примере способ получения данных от веб формы (непосредственное чтение устройства стандартного ввода STD_INPUT) является наиболее наглядным, но не самым удобным, в Дельфи предусмотренны более удобные механизмы, которых мы каснемся позже.

Пример создания DivX драйвера на Delphi

Общая информация

Компиляция данного примера возможна только с Delphi 3. Delphi 2 не был опробован в связи с его отсутствием, объектные фалы созданные Delphi 4 отвергаются Microsoft ® Linker 5.12.8181 как файлы неизвестного формата.

При написании данного материала были использованы Microsoft ® Macro Assembler ver. 6.11d и Microsoft ® Incremental Linker ver. 5.12.8181 из поставки.

VxD драйвера делятся два типа:

  • Статические Загружаются в память при загрузке операционной системы и присутствуют в памяти постоянно
  • Динамические Загружаются в память при первом обращении к драйверу и могут быть выгружены при закрытии последнего дескриптора VxD.

Практически возможно создание драйвера поддерживающего оба типа загрузки.

Нам необходим динамически загружаемый VxD драйвер (далее «VxD») т.к. такой драйвер можно будет без перезагрузки Windows загружать из Win32 ® приложений используя процедуру CreateFile().

Когда Win32 приложение открывает дескриптор для VxD, виртуальное устройство VWIN32 используя сервис LoadDevice загружает VxD-драйвер в память и посылает информационное сообщение W32_DEVICEIOCONTROL загруженному VxD.

Таким образом для построения VxD необходимо обрабатывать как минимум три системных сообщения:

  • SYS_DYNAMIC_DEVICE_INIT
  • SYS_DYNAMIC_DEVICE_EXIT
  • W32_DEVICEIOCONTROL.

Собщение SYS_DYNAMIC_DEVICE_INIT посылается при попытке динамической загрузки VxD, SYS_DYNAMIC_DEVICE_EXIT посылается при попытке динамической выгрузке. Из обработчиков сообщений для подтверждения успеха необходимо вернуть VXD_SUCCESS в регистре AX

Сообщение W32_DEVICEIOCONTROL имеет следующие значения для параметра dwService.

  • DIOC_OPEN — посылается посылается при открытии дескриптора VxD функцией CreateFile() только после SYS_DYNAMIC_DEVICE_INIT. В случае успеха необходимо вернуть NO_ERROR (0);
  • DIOC_CLOSEHANDLE — посылается при закрытии дескриптора VxD функцией API CloseHandle() и только перед SYS_DYNAMIC_DEVICE_EXIT
  • (Значение > 0) — Номер функции, заданный в параметре dwIoControlCode при обращении к VxD функцией API DeviceIoControl

Загрузочный модуль (vxdmain.asm)

При обращении к процедурам находящимся в модулях Delphi надо учесть для fastcall-процедур к имени добавляется в начале символ «@»

Delphi создает код для инициализации/деинициализации модулей, обращаясь к внешним процедурам HandleFinaly и initialization даже если блоки initilization и finalization в модуле отсутствуют. Создадим пустую «заглушку» для этих процедур и объявим их доступными для внешних модулей.

Процедурный модуль (vxdProcs.pas)

Инструмент для загрузки/выгрузки VxD

Представляет из себя простую форму с двумя кнопками. Приведу лишь методы для открытия и закрытия VxD драйвера.

Выгрузку неиспользуемого модуля можно производить автоматически, указав в параметрах CreateFile(. FILE_FLAG_DELETE_ON_CLOSE,). В данном случае система при каждом открытии дескриптора к VxD будет увеличивать внутренний счетчик использования на 1 и вычитать 1 при закрытии дескриптора. При значении счетчика равном нулю VxD будет автоматически выгружен.

Драйвера на Delphi писать можно. Но вот только стоит ли?

Использование VxD имеет смысл только для использования Windows 3.1 и Windows 95. Да и доступ к аппаратным ресурсам в них гораздо прозрачнее чем Windows NT/2000/XP. Windows 98, NT 2000 и XP поддерживают новую модель драйверов WDM 1.0/2.0, использующую формат PE (Portable Executable) и (предположительно) проблем будет меньше, чем с VxD и его LE (Linear Executable) форматом драйверов.

Создание Web-броузера на Delphi

Читая и перечитывая вопросы и ответы, я все время натыкался на вопросы о компоненте TWebBrowser. Сначала я думал, что все просто, но когда самому понадобилось написать приложение с использованием TwebBrowser… оказалось, что не все так просто!

Эта статья не претендует на исчерпывающие руководство по написанию браузера в Delphi 5 — скорее всего она будет со временем дополняться и исправляться. Я постарался обобщить в одном работающем примере решения большинства вопросов, заданных на этом сайте (признаюсь, там были и мои). Также выражаю большую признательность Елене Филлиповой за исчерпывающие ответы на некоторые из них, и всему Королевству за столь хороший и полезный сайт.

Компонент TWebBrowser в Delphi 4 нужно было специально инсталлировать как Active X компонент. В 5-й версии нам пошли навстречу, и он сразу есть на вкладке Internet. Не буду останавливаться на особенностях интерфейса программы — он очень прост (надеюсь, не очень) и не вызовет трудностей. Пример сдесь.

Рассмотрим некоторые свойства и функции TwebBrowser.

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

Последняя команда самая интересная — в Help написано, что использовать ее не надо. Она завершает работу IE и очищает окно. Но я проверял — вроде вреда от ее использования не наблюдалось.

Далее идет целая группа процедур:

procedure Navigate(const URL: WideString); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant; var

TargetFrameName: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant;

var TargetFrameName: OleVariant; var PostData: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant;

var TargetFrameName: OleVariant; var PostData: OleVariant;


var Headers: OleVariant); overload;

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

procedure Navigate(const URL: WideString);

Для значения Flag определены такие константы:

navOpenInNewWindow 1 Открывает URL в новом окне браузера

navNoHistory 2 Не заносит адрес в список History.

navNoReadFromCache 4 Не использует сохраненную в кеше страницу, а загружает с сервера.

navNoWriteToCache 8 Не записывает страницу в дисковый кеш.

navAllowAutosearch 16 Если броузер не может найти указанный домен, он передает его в поисковый механизм.

Все, это можно также вручную установить в настройках браузера.

TargetFrameName указывает имя фрейма, куда надо загрузить страницу. Если присвоить NULL страница просто загрузиться в текущее окно.

PostData — указывает на данные, которые нужно отослать, используя метод HTTP POST. Если установить в NULL, процедура Navigate будет использовать метод HTTP GET.

Следующая довольно интересная и полезная процедура

procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT); overload;

Позволяет осуществить управление браузером и вызывать различные дополнительные функции — печать, сохранение и др. Использует IoleCommandTarget интерфейс для управления браузером.

CmdID — задает команду, которую нужно выполнить. Может принимать следующие значения:

OLECMDID_OPEN, OLECMDID_NEW, OLECMDID_SAVE, OLECMDID_SAVEAS, OLECMDID_SAVECOPYAS, OLECMDID_PRINT, OLECMDID_PRINTPREVIEW, OLECMDID_PAGESETUP, OLECMDID_SPELL, OLECMDID_PROPERTIES, OLECMDID_CUT, OLECMDID_COPY, OLECMDID_PASTE, OLECMDID_PASTESPECIAL, OLECMDID_UNDO, OLECMDID_REDO, OLECMDID_SELECTALL, OLECMDID_CLEARSELECTION, OLECMDID_ZOOM, OLECMDID_GETZOOMRANGE, OLECMDID_UPDATECOMMANDS, OLECMDID_REFRESH, OLECMDID_STOP, OLECMDID_HIDETOOLBARS, OLECMDID_SETPROGRESSMAX , OLECMDID_SETPROGRESSPOS, OLECMDID_SETPROGRESSTEXT, OLECMDID_SETTITLE, OLECMDID_SETDOWNLOADSTATE, OLECMDID_STOPDOWNLOAD, OLECMDID_FIND, OLECMDID_ONTOOLBARACTIVATED, OLECMDID_DELETE, OLECMDID_HTTPEQUIV, OLECMDID_ENABLE_INTERACTION, OLECMDID_HTTPEQUIV_DONE, OLECMDID_ONUNLOAD, OLECMDID_PROPERTYBAG2, OLECMDID_PREREFRESH

Если присмотреться, то можно увидеть, что некоторые из них дублируються процедурами Stop, Refresh и др. Но большенство очень даже нужные.

Cmdexecopt — указывает дополнительно, как команда должна исполняться. Может принимать значения:

OLECMDEXECOPT_DODEFAULT 0 Команда исполняеться так, как принято по умолчанию.

OLECMDEXECOPT_PROMPTUSER 1 Перед выполнением выводиться окно диалога или дополнительных настроек.

OLECMDEXECOPT_DONTPROMPTUSER 2 Не задается никаких вопросов.

OLECMDEXECOPT_SHOWHELP 3 Выводиться справка по запрошеному действии, но сама команда не выполняеться. Удобно для вызова из вашего приложения справки по IE.

Вызивать эту комманду желательно и даже нужно в блоке

Эта команда вызивает диалоговое окно печати документа. Если же опустить try…except, то при нажатии «Отмена» в этом окне будет сгенерировано уведомление об ошибке типа:

raised exception class EOleException with message «Невозможно установить свойство coISpan. Недопустимое значения свойства. Требуется ввести значение от 1 до 1000».

Теперь поговорим о свойствах.

PopupMenu; Как оконный элемент управления, TwebBrowser поддерживает всплывающие меню. НО! Ваше меню будет появляться только пока в браузер не загружена страница. Дальше — только меню IE.

В Конференции предложили такой вариант для запрета появления стандартного меню:

property OffLine : WordBool; Позволяет загружать документы из локального кеша — если присвоить True.

property LocationURL: WideString; Позначено как «только для чтения» и содержит URL ресурса, загруженого в браузер.

Среди самых важных/нужных есть:

OnDownloadBegin — происходит, когда вы, набрав URL, хотите перейти по нему. Тут можно задать например анимацию или ProgressBar для индикации процесса загрузки страницы (совмесно с OnProgressChange).

OnDownloadComplete, OnDownloadComplete, OnNavigateComplete2 — происходит, когда страница закончила грузиться.

Правда, здесь есть много нюансов при загрузке страниц с графикой и фреймами — для каждого загружаемого элемента будут генерироваться новые события начала/окончания загрузки, а кроме того, если отключить загрузку рисунков/анимации/видео, так вообще некоторые из них не будут происходить! Так что пользоваться ими нужно осторожно.

Илон Маск рекомендует:  Простой дизайн сайта – чем проще, тем лучше

OnBeforeNavigate2 — происходит когда вы переходите по щелчку на гиперссылке из основной страницы, загруженной в браузер. Сюда можно писать код, который например, анализирует — куда пользователь переходит, и соответственно, что-то делать. Или запретить открывание новых окно, или открывать свои окна (типа сделатьTtabbedNotebook c IE на каждой странице)

OnNewWindow2 — происходит, когда открывается новое окно браузера.

Я, конечно, много чего упустил — например, работу с интерфейсами, доступ к тегам страницы — но надеюсь, эта статья и пример помогут вам сделать работоспособный браузер для дальнейших эксперементов. Успехов!

Строковые типы в Delphi

В выражениях Delphi поддерживает три физических строковых формата: короткий (ShortString), длинный (LongString) и широкий (WideString). Их можно комбинировать в операторах присваивания и выражениях (все необходимые преобразования Delphi выполняет автоматически).

Переменные типов AnsiString и WideString — это динамически распределяемые массивы символов, максимальная длина которых ограничивается только наличием памяти. Разница между ними состоит в том, что в AnsiString знаки записываются в формате char, а в WideString— в формате WideChar. Обычно вполне достаточно одного типа AnsiString, однако при работе с международными наборами символов, такими как UNICODE, удобнее использовать WideString.

Тип ShortString—это, по существу, массив Array [0..255] of char.
Первый его элемент задает динамическую длину строки, которая может принимать значения от 0 до 255 символов. Символы, составляющие строку, занимают места от 1 до 255. Тип ShortString предназначен, в основном, для обеспечения совместимости с ранними версиями Delphi и Borland Pascal.

Логический строковый тип именуется просто String. Отнесение его к типу AnsiString или ShortString задается командой $Н. По умолчанию задается < $Н+>, и String совпадает с AnsiString. Если задать команду <$Н- >, то String будет совпадать с ShortString и иметь максимальную длину, равную 255 символам.

Для совместимости с другими языками программирования в Delphi поддерживается класс строк с конечным нулем. Зарезервированных слов или идентификаторов для этого класса не существует.

Строки с конечным нулем состоят из ненулевых символов и оканчиваются символом с порядковым номером 0 (#0). В отличие от типов AnsiString, ShortString и WideString, строки с нулевым окончанием не имеют указателя длины. Конец в этих стооках обозначается нулем.

Физически строки с нуль-окончанием подобны массивам символов с нумерацией элементов от нуля, наподобие array [ 0 . . X] of char, где Х — некоторое положительное целое, большее нуля, хотя никаких объявлении подобного рода не происходит. Вместо этого определяется переменная-указатель PChar и распределяется необходимый объем памяти. При необходимости строке AnsiString можно присвоить тип PChar.

В табл. 1 перечислены некоторые процедуры и функции обработки данных строковых типов.

Совет: Программисты, работающие на С, привыкли записывать все строки в массивы с нуль-окончанием. Фактически они применяют в выражениях не строковые переменные, а указатели на них. Программисты, работающие на Basic, привыкли использовать строку как одно целое. Для типа AnsiString из Delphi годятся оба подхода.

Таблица 1 — Строковые функции

Функция Описание
Concat(sl, s2, s3) Возвращает последовательное соединение строк. Эквивалентна оператору sl+s2+s3
Copy(s, pos, len) Возвращает подстроку длиной максимум len символов, начинающуюся в позиции pos строки s
Delete(s, pos, len) Удаляет максимум len символов из строки s, начиная с позиции pos
Insert(sourse, tar-get, pos) Вставляет строку source в строковую переменную target, начиная с позиции pos
Length (s) Возвращает динамическую длину строки. Подобна функциям LEN в Basic и strlen — в C/C++
Pos(substring, s) Возвращает место первого вхождения подстроки substring в строку s. Подобна функциям SUBSTR в Basic и strstr () — в C/C++
SetLength(s, newlen) Задает новую динамическую длину newlen строковой переменной s
SetString Задает содержимое и длину строки
Str(x, s) Преобразует численное значение х в строковую переменную s
StringOfChars Возвращает строку с конкретным числом символов
UniqueString Делает данную строку уникальной со счетом обращений 1
Val (s, v, code) Преобразует строку s в соответствующее численное представление v

Получение и установка текущей раскладки клавиатуры средствами Delphi

Ниже представлены 5 функций для получения/установки раскладки клавиатуры в своем или активном в текущий момент времени приложении:


  • function NameKeyboardLayout(layout : LongWord) : string; — Получает название раскладки из списка (для удобства сделал :)))
  • function GetActiveKbdLayout : LongWord; — Получает раскладку в своей программе
  • function GetActiveKbdLayoutWnd : LongWord; — Получает раскладку в активном окне
  • procedure SetKbdLayout(kbLayout : LongWord); — Устанавливает раскладку в своей программе
  • procedure SetLayoutActiveWnd(kbLayout : LongWord); — Устанавливает раскладку в активном окне

Разработка CGI приложений на Delphi

В последнее время в связи с растущей популярностью сети Интернет все чаше становится необходимость разработки приложений, которые бы могли работать непосредственно в www среде. Т.е. такие, которые бы полностью бы интегрировались в уже привычные нам веб-странички. По сути дела работа с таким приложением происходит полностью через любимый браузер пользователя и ничем не отличается от серфинга по страничкам. Ввод данных равно как и выдача обработанных результатов происходит через html-формы веб-страничек. Обработка же данных происходит на веб-сервере. Таким образом, мы получим самое что ни есть клиент-серверное приложение в его самом классическом понимании.

Необходимо отметить, что CGI-приложения разрабатываемые в средах разработки ориентированных на Win32 системы, в том числе и в Дельфи, а вернее серверная часть такого приложения может работать только под Win32 сервером, например IIS из NT или Personal Web Server из Windows98. Что касается клиентской части, то здесь никаких проблем совместимости не должно быть в принципе, т.к. клиентская часть представляет собой сгенерированный HTML код, который поддерживается любым браузером, не важно какую платформу использует пользователь, будь то Win32, OS/2, Unix и др.

Таким образом, программисту пишушему CGI-приложения придется столкнуться с двумя основными задачами — это разработка веб-интерфейса и разработка непосредственно математической части приложения.

Что касается веб-интерфейсов, то здесь желательно знать хотя бы основы языка HTML. Здесь мы не будем уделять этому особое внимание, хотя знание HTML для программиста CGI-приложений очень желательно. Сейчас же для нас будет вполне достаточным знание таких основопологающих тэгов как , и конструкции ===cut==

Далее идет пример непосредственно CGI приложения. Следует отметить, что приведенный в этом примере способ получения данных от веб формы (непосредственное чтение устройства стандартного ввода STD_INPUT) является наиболее наглядным, но не самым удобным, в Дельфи предусмотренны более удобные механизмы, которых мы каснемся позже.

Пример создания DivX драйвера на Delphi

Общая информация

Компиляция данного примера возможна только с Delphi 3. Delphi 2 не был опробован в связи с его отсутствием, объектные фалы созданные Delphi 4 отвергаются Microsoft ® Linker 5.12.8181 как файлы неизвестного формата.

При написании данного материала были использованы Microsoft ® Macro Assembler ver. 6.11d и Microsoft ® Incremental Linker ver. 5.12.8181 из поставки.

VxD драйвера делятся два типа:

  • Статические Загружаются в память при загрузке операционной системы и присутствуют в памяти постоянно
  • Динамические Загружаются в память при первом обращении к драйверу и могут быть выгружены при закрытии последнего дескриптора VxD.

Практически возможно создание драйвера поддерживающего оба типа загрузки.

Нам необходим динамически загружаемый VxD драйвер (далее «VxD») т.к. такой драйвер можно будет без перезагрузки Windows загружать из Win32 ® приложений используя процедуру CreateFile().

Когда Win32 приложение открывает дескриптор для VxD, виртуальное устройство VWIN32 используя сервис LoadDevice загружает VxD-драйвер в память и посылает информационное сообщение W32_DEVICEIOCONTROL загруженному VxD.

Таким образом для построения VxD необходимо обрабатывать как минимум три системных сообщения:

  • SYS_DYNAMIC_DEVICE_INIT
  • SYS_DYNAMIC_DEVICE_EXIT
  • W32_DEVICEIOCONTROL.

Собщение SYS_DYNAMIC_DEVICE_INIT посылается при попытке динамической загрузки VxD, SYS_DYNAMIC_DEVICE_EXIT посылается при попытке динамической выгрузке. Из обработчиков сообщений для подтверждения успеха необходимо вернуть VXD_SUCCESS в регистре AX

Сообщение W32_DEVICEIOCONTROL имеет следующие значения для параметра dwService.

  • DIOC_OPEN — посылается посылается при открытии дескриптора VxD функцией CreateFile() только после SYS_DYNAMIC_DEVICE_INIT. В случае успеха необходимо вернуть NO_ERROR (0);
  • DIOC_CLOSEHANDLE — посылается при закрытии дескриптора VxD функцией API CloseHandle() и только перед SYS_DYNAMIC_DEVICE_EXIT
  • (Значение > 0) — Номер функции, заданный в параметре dwIoControlCode при обращении к VxD функцией API DeviceIoControl

Загрузочный модуль (vxdmain.asm)

При обращении к процедурам находящимся в модулях Delphi надо учесть для fastcall-процедур к имени добавляется в начале символ «@»

Delphi создает код для инициализации/деинициализации модулей, обращаясь к внешним процедурам HandleFinaly и initialization даже если блоки initilization и finalization в модуле отсутствуют. Создадим пустую «заглушку» для этих процедур и объявим их доступными для внешних модулей.

Процедурный модуль (vxdProcs.pas)

Инструмент для загрузки/выгрузки VxD

Представляет из себя простую форму с двумя кнопками. Приведу лишь методы для открытия и закрытия VxD драйвера.

Выгрузку неиспользуемого модуля можно производить автоматически, указав в параметрах CreateFile(. FILE_FLAG_DELETE_ON_CLOSE,). В данном случае система при каждом открытии дескриптора к VxD будет увеличивать внутренний счетчик использования на 1 и вычитать 1 при закрытии дескриптора. При значении счетчика равном нулю VxD будет автоматически выгружен.

Драйвера на Delphi писать можно. Но вот только стоит ли?

Использование VxD имеет смысл только для использования Windows 3.1 и Windows 95. Да и доступ к аппаратным ресурсам в них гораздо прозрачнее чем Windows NT/2000/XP. Windows 98, NT 2000 и XP поддерживают новую модель драйверов WDM 1.0/2.0, использующую формат PE (Portable Executable) и (предположительно) проблем будет меньше, чем с VxD и его LE (Linear Executable) форматом драйверов.

Создание Web-броузера на Delphi

Читая и перечитывая вопросы и ответы, я все время натыкался на вопросы о компоненте TWebBrowser. Сначала я думал, что все просто, но когда самому понадобилось написать приложение с использованием TwebBrowser… оказалось, что не все так просто!

Эта статья не претендует на исчерпывающие руководство по написанию браузера в Delphi 5 — скорее всего она будет со временем дополняться и исправляться. Я постарался обобщить в одном работающем примере решения большинства вопросов, заданных на этом сайте (признаюсь, там были и мои). Также выражаю большую признательность Елене Филлиповой за исчерпывающие ответы на некоторые из них, и всему Королевству за столь хороший и полезный сайт.

Компонент TWebBrowser в Delphi 4 нужно было специально инсталлировать как Active X компонент. В 5-й версии нам пошли навстречу, и он сразу есть на вкладке Internet. Не буду останавливаться на особенностях интерфейса программы — он очень прост (надеюсь, не очень) и не вызовет трудностей. Пример сдесь.

Рассмотрим некоторые свойства и функции TwebBrowser.

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

Последняя команда самая интересная — в Help написано, что использовать ее не надо. Она завершает работу IE и очищает окно. Но я проверял — вроде вреда от ее использования не наблюдалось.

Далее идет целая группа процедур:

procedure Navigate(const URL: WideString); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant; var

TargetFrameName: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant;

var TargetFrameName: OleVariant; var PostData: OleVariant); overload;

procedure Navigate(const URL: WideString; var Flags: OleVariant;

var TargetFrameName: OleVariant; var PostData: OleVariant;

var Headers: OleVariant); overload;

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


procedure Navigate(const URL: WideString);

Для значения Flag определены такие константы:

navOpenInNewWindow 1 Открывает URL в новом окне браузера

navNoHistory 2 Не заносит адрес в список History.

navNoReadFromCache 4 Не использует сохраненную в кеше страницу, а загружает с сервера.

navNoWriteToCache 8 Не записывает страницу в дисковый кеш.

navAllowAutosearch 16 Если броузер не может найти указанный домен, он передает его в поисковый механизм.

Все, это можно также вручную установить в настройках браузера.

TargetFrameName указывает имя фрейма, куда надо загрузить страницу. Если присвоить NULL страница просто загрузиться в текущее окно.

PostData — указывает на данные, которые нужно отослать, используя метод HTTP POST. Если установить в NULL, процедура Navigate будет использовать метод HTTP GET.

Следующая довольно интересная и полезная процедура

procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT); overload;

Позволяет осуществить управление браузером и вызывать различные дополнительные функции — печать, сохранение и др. Использует IoleCommandTarget интерфейс для управления браузером.

CmdID — задает команду, которую нужно выполнить. Может принимать следующие значения:

OLECMDID_OPEN, OLECMDID_NEW, OLECMDID_SAVE, OLECMDID_SAVEAS, OLECMDID_SAVECOPYAS, OLECMDID_PRINT, OLECMDID_PRINTPREVIEW, OLECMDID_PAGESETUP, OLECMDID_SPELL, OLECMDID_PROPERTIES, OLECMDID_CUT, OLECMDID_COPY, OLECMDID_PASTE, OLECMDID_PASTESPECIAL, OLECMDID_UNDO, OLECMDID_REDO, OLECMDID_SELECTALL, OLECMDID_CLEARSELECTION, OLECMDID_ZOOM, OLECMDID_GETZOOMRANGE, OLECMDID_UPDATECOMMANDS, OLECMDID_REFRESH, OLECMDID_STOP, OLECMDID_HIDETOOLBARS, OLECMDID_SETPROGRESSMAX , OLECMDID_SETPROGRESSPOS, OLECMDID_SETPROGRESSTEXT, OLECMDID_SETTITLE, OLECMDID_SETDOWNLOADSTATE, OLECMDID_STOPDOWNLOAD, OLECMDID_FIND, OLECMDID_ONTOOLBARACTIVATED, OLECMDID_DELETE, OLECMDID_HTTPEQUIV, OLECMDID_ENABLE_INTERACTION, OLECMDID_HTTPEQUIV_DONE, OLECMDID_ONUNLOAD, OLECMDID_PROPERTYBAG2, OLECMDID_PREREFRESH

Если присмотреться, то можно увидеть, что некоторые из них дублируються процедурами Stop, Refresh и др. Но большенство очень даже нужные.

Cmdexecopt — указывает дополнительно, как команда должна исполняться. Может принимать значения:

OLECMDEXECOPT_DODEFAULT 0 Команда исполняеться так, как принято по умолчанию.

OLECMDEXECOPT_PROMPTUSER 1 Перед выполнением выводиться окно диалога или дополнительных настроек.

OLECMDEXECOPT_DONTPROMPTUSER 2 Не задается никаких вопросов.

OLECMDEXECOPT_SHOWHELP 3 Выводиться справка по запрошеному действии, но сама команда не выполняеться. Удобно для вызова из вашего приложения справки по IE.

Вызивать эту комманду желательно и даже нужно в блоке

Эта команда вызивает диалоговое окно печати документа. Если же опустить try…except, то при нажатии «Отмена» в этом окне будет сгенерировано уведомление об ошибке типа:

raised exception class EOleException with message «Невозможно установить свойство coISpan. Недопустимое значения свойства. Требуется ввести значение от 1 до 1000».

Теперь поговорим о свойствах.

PopupMenu; Как оконный элемент управления, TwebBrowser поддерживает всплывающие меню. НО! Ваше меню будет появляться только пока в браузер не загружена страница. Дальше — только меню IE.

В Конференции предложили такой вариант для запрета появления стандартного меню:

property OffLine : WordBool; Позволяет загружать документы из локального кеша — если присвоить True.

property LocationURL: WideString; Позначено как «только для чтения» и содержит URL ресурса, загруженого в браузер.

Среди самых важных/нужных есть:

OnDownloadBegin — происходит, когда вы, набрав URL, хотите перейти по нему. Тут можно задать например анимацию или ProgressBar для индикации процесса загрузки страницы (совмесно с OnProgressChange).

OnDownloadComplete, OnDownloadComplete, OnNavigateComplete2 — происходит, когда страница закончила грузиться.

Правда, здесь есть много нюансов при загрузке страниц с графикой и фреймами — для каждого загружаемого элемента будут генерироваться новые события начала/окончания загрузки, а кроме того, если отключить загрузку рисунков/анимации/видео, так вообще некоторые из них не будут происходить! Так что пользоваться ими нужно осторожно.

OnBeforeNavigate2 — происходит когда вы переходите по щелчку на гиперссылке из основной страницы, загруженной в браузер. Сюда можно писать код, который например, анализирует — куда пользователь переходит, и соответственно, что-то делать. Или запретить открывание новых окно, или открывать свои окна (типа сделатьTtabbedNotebook c IE на каждой странице)

OnNewWindow2 — происходит, когда открывается новое окно браузера.

Я, конечно, много чего упустил — например, работу с интерфейсами, доступ к тегам страницы — но надеюсь, эта статья и пример помогут вам сделать работоспособный браузер для дальнейших эксперементов. Успехов!

Строковые типы в Delphi

В выражениях Delphi поддерживает три физических строковых формата: короткий (ShortString), длинный (LongString) и широкий (WideString). Их можно комбинировать в операторах присваивания и выражениях (все необходимые преобразования Delphi выполняет автоматически).

Переменные типов AnsiString и WideString — это динамически распределяемые массивы символов, максимальная длина которых ограничивается только наличием памяти. Разница между ними состоит в том, что в AnsiString знаки записываются в формате char, а в WideString— в формате WideChar. Обычно вполне достаточно одного типа AnsiString, однако при работе с международными наборами символов, такими как UNICODE, удобнее использовать WideString.

Тип ShortString—это, по существу, массив Array [0..255] of char.
Первый его элемент задает динамическую длину строки, которая может принимать значения от 0 до 255 символов. Символы, составляющие строку, занимают места от 1 до 255. Тип ShortString предназначен, в основном, для обеспечения совместимости с ранними версиями Delphi и Borland Pascal.

Логический строковый тип именуется просто String. Отнесение его к типу AnsiString или ShortString задается командой $Н. По умолчанию задается < $Н+>, и String совпадает с AnsiString. Если задать команду <$Н- >, то String будет совпадать с ShortString и иметь максимальную длину, равную 255 символам.

Для совместимости с другими языками программирования в Delphi поддерживается класс строк с конечным нулем. Зарезервированных слов или идентификаторов для этого класса не существует.

Строки с конечным нулем состоят из ненулевых символов и оканчиваются символом с порядковым номером 0 (#0). В отличие от типов AnsiString, ShortString и WideString, строки с нулевым окончанием не имеют указателя длины. Конец в этих стооках обозначается нулем.

Физически строки с нуль-окончанием подобны массивам символов с нумерацией элементов от нуля, наподобие array [ 0 . . X] of char, где Х — некоторое положительное целое, большее нуля, хотя никаких объявлении подобного рода не происходит. Вместо этого определяется переменная-указатель PChar и распределяется необходимый объем памяти. При необходимости строке AnsiString можно присвоить тип PChar.

В табл. 1 перечислены некоторые процедуры и функции обработки данных строковых типов.

Совет: Программисты, работающие на С, привыкли записывать все строки в массивы с нуль-окончанием. Фактически они применяют в выражениях не строковые переменные, а указатели на них. Программисты, работающие на Basic, привыкли использовать строку как одно целое. Для типа AnsiString из Delphi годятся оба подхода.

Таблица 1 — Строковые функции

Функция Описание
Concat(sl, s2, s3) Возвращает последовательное соединение строк. Эквивалентна оператору sl+s2+s3
Copy(s, pos, len) Возвращает подстроку длиной максимум len символов, начинающуюся в позиции pos строки s
Delete(s, pos, len) Удаляет максимум len символов из строки s, начиная с позиции pos
Insert(sourse, tar-get, pos) Вставляет строку source в строковую переменную target, начиная с позиции pos
Length (s) Возвращает динамическую длину строки. Подобна функциям LEN в Basic и strlen — в C/C++
Pos(substring, s) Возвращает место первого вхождения подстроки substring в строку s. Подобна функциям SUBSTR в Basic и strstr () — в C/C++
SetLength(s, newlen) Задает новую динамическую длину newlen строковой переменной s
SetString Задает содержимое и длину строки
Str(x, s) Преобразует численное значение х в строковую переменную s
StringOfChars Возвращает строку с конкретным числом символов
UniqueString Делает данную строку уникальной со счетом обращений 1
Val (s, v, code) Преобразует строку s в соответствующее численное представление v

Получение и установка текущей раскладки клавиатуры средствами Delphi

Ниже представлены 5 функций для получения/установки раскладки клавиатуры в своем или активном в текущий момент времени приложении:

  • function NameKeyboardLayout(layout : LongWord) : string; — Получает название раскладки из списка (для удобства сделал :)))
  • function GetActiveKbdLayout : LongWord; — Получает раскладку в своей программе
  • function GetActiveKbdLayoutWnd : LongWord; — Получает раскладку в активном окне
  • procedure SetKbdLayout(kbLayout : LongWord); — Устанавливает раскладку в своей программе
  • procedure SetLayoutActiveWnd(kbLayout : LongWord); — Устанавливает раскладку в активном окне

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL