А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Для получения названия окна в приведенном коде используется функция GetWindowText
. Эта функция безопасна при работе с зависшими приложениями, поскольку она гарантирует, что вызвавшее ее приложение не зависнет само, пытаясь получить ответ от зависшего приложения. Но GetWindowText
не всегда может получить названия элементов управления, расположенных в окнах чужих приложений (точнее, в MSDN написано, что она вообще не может получать названия элементов управления в чужих окнах, но практика показывает, что нередко GetWindowText
все же делает это). Существует альтернативный способ получения названия окна — отправка ему сообщения WM_GETTEXT
. При этом ограничений на работу с чужими элементами управления нет, но и гарантии, что из-за отсутствия ответа от чужого приложения программа не зависнет, тоже нет.
Использование WM_GETTEXT
показано в другой части программы — при заполнении списка параметров окна, отображающегося в правом нижнем углу формы. Чтобы программа не зависала, вместо SendMessage
для отправки WM_GETTEXT
применяется SendMessageTimeout
. Код получения имени показан в листинге 1.44.
if SendMessageTimeout(Wnd, WM_GETTEXTLENGTH, 0, 0,
SMTO_NORMAL or SMTO_ABORTIFHUNG, 5000, TextLen) = 0 then
begin
LastError := GetLastError;
if LastError = 0 then Text := 'Приложение не отвечает'
else
Text:= 'Ошибка при получении длины заголовка: ' + IntToStr(LastError);
end
else
begin
SetLength(Text, TextLen);
if TextLen > 0 then
if SendMessageTimeout(Wnd, WM_GETTEXT, TextLen + 1, LParam(Text),
SMTO_NORMAL or SMTO_ABORTIFHUNG, 5000, TextLen) = 0 then
begin
LastError := GetLastError;
if LastError = 0 then Text := 'Приложение не отвечает'
else Text := 'Ошибка при получении заголовка:' + IntToStr(LastError);
end;
end;
Для каждого окна программа выводит имя оконного класса и реальный класс окна. В большинстве случаев эти два класса совпадают. Они различаются только для тех окон, чьи классы "унаследованы" от стандартных классов, таких как EDIT
, COMBOBOX
и т.п.
Вообще, наследования оконных классов в Windows нет. Но существует один нехитрый прием, который позволяет имитировать наследование. Оконная процедура обычно не обрабатывает все сообщения, а передает часть их в одну из стандартных оконных процедур ( DefWindowProc
, DefFrameProc
и т.п.). Программа может с помощью функции GetClassInfo
узнать адрес оконной процедуры, назначенной стандартному классу, и использовать ее вместо стандартной оконной процедуры. Так как большая часть свойств окна определяется тем, как и какие сообщения оно обрабатывает, использование оконной процедуры другого класса позволяет почти полностью унаследовать свойства этого класса. (В VCL для наследования оконных классов существует метод TWinControl.CreateSubClass
.) Функция RealGetWindowClass
позволяет узнать имя класса-предка, если такой имеется. Соответствующая часть кода примера приведена в листинге 1.45.
GetClassName(Wnd, ClassName, ClassNameLen);
ClassName[ClassNameLen - 1] := #0;
ListParams.Items[2].SubItems[0] := ClassName;
RealGetWindowClass(Wnd, ClassName, ClassNameLen);
ClassName[ClassNameLen - 1] := #0;
ListParams.Items[3].SubItems[0] := ClassName;
У окна, если оно имеет стиль WS_CHILD
, должно быть родительское окно. Если такого стиля нет, то окно располагается непосредственно на рабочем столе. Кроме того, такое окно может (но не обязано) иметь владельца. Получить дескриптор родительского окна можно с помощью функции GetParent
. Владельца — с помощью функции GetWindow
с параметром GW_OWNER
.
Кроме GetParent
существует функция GetAncestor
, которая также возвращает дескриптор родительского окна, если она вызвана с параметром GA_PARENT
. Разница между этими функциями заключается в том. что для окон верхнего уровня (т.е. расположенных непосредственно на рабочем столе) GetParent
возвращает 0, a GetAncestor
— дескриптор рабочего стопа (этот дескриптор можно получить через функцию GetDesktopWindow
).
Значительную часть кода программы составляет анализ того, какие флаги присутствуют в стиле окна. В этом нет ничего сложного, но он громоздкий из-за большого числа флагов. Следует также учесть, что для стандартных классов одни и те же числовые значения могут иметь разный смысл. Так, например, константы ES_NOHIDESEL
и BS_LEFT
имеют одинаковые значения. Поэтому при расшифровке стиля следует также учитывать класс окна. Приводить здесь этот код мы не будем по причине его тривиальности. Его можно посмотреть в примере на компакт-диске.
1.3.2. Обобщающий пример 2 — Ассоциированные файлы и предотвращение запуска второй копии приложения
Расширения файлов могут быть связаны (ассоциированы) с определенной программой. Такие ассоциации помогают системе выбрать программу для выполнения различных действий с файлом из Проводника. Так, например, если на компьютере установлен Microsoft Office, двойной щелчок в Проводнике на файле с расширением xls приведет к запуску Microsoft Excel и открытию файла в нем. Это происходит потому, что расширение xls ассоциировано с приложением Microsoft Excel.
Добиться аналогичного эффекта в своей программе можно используя функцию ShellExecute
(стандартная системная функция, в Delphi импортируется в модуле ShellAPI
). Эта функция запускает файл, имя которого передано ей как параметр. Если это исполняемый файл, он запускается непосредственно, если нет — функция ищет ассоциированное с расширением файла приложение и открывает файл в нем.
Пример, который мы здесь рассмотрим (программа DKSView), умеет ассоциировать файлы с расширением dks с собой, а также проверять, не были ли они ассоциированы с другим приложением. DKSView является MDI-приложением, т.е. может открывать одновременно несколько файлов. Если приложение уже запущено, а пользователь пытается открыть еще один dks-файл, желательно, чтобы он открывался не в новом экземпляре DKSView, а в новом окне уже имеющегося. Поэтому наш пример будет также уметь обнаруживать уже запущенный экземпляр программы и переадресовывать открытие файла ему.
1.3.2.1. Ассоциирование расширения с приложением
Файловые ассоциации прописываются в реестре, в разделе HKEY_CLASSES_ROOT
. Чтобы связать расширение с приложением, необходимо выполнить следующие действия:
1. В корне раздела HKEY_CLASSES_ROOT
нужно создать новый раздел, имя которого совладает с расширением с точкой перед ним (в нашем случае это будет раздел с именем ".dks"). В качестве значения по умолчанию в этот раздел должна быть записана непустая строка, которая будет идентифицировать соответствующий тип файла. Содержимое этой строки может быть произвольным и определяется разработчиком (в нашем случае эта строка имеет значение "DKS_View_File").
Интервал:
Закладка: