А. Григорьев - О чём не пишут в книгах по 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").
Интервал:
Закладка: