Delphi: Что такое Application.Handle? - PullRequest
       43

Delphi: Что такое Application.Handle?

47 голосов
/ 05 февраля 2010

Что такое TApplication.Handle?

  • Откуда это?
  • Почему он существует?
  • И самое главное: почему все формы имеют его в качестве дескриптора родительского окна?

В справке Delphi написано:

TApplication.Handle

Предоставляет доступ к дескриптору окна основной формы (окна) применение.

property Handle: HWND;

Описание

Использовать дескриптор при вызове Windows API функции, которые требуют родительского окна справиться. Например, DLL, которая отображает свое собственное всплывающее окно верхнего уровня Windows нужно родительское окно для показать свои окна в приложение. Использование свойства Handle делает такие окна частью приложение, так что они свернуто, восстановлено, включено и отключено с помощью приложения.

Если я остановлюсь на словах " дескриптор окна основной формы приложения ", и я понимаю, что это означает дескриптор окна основной формы приложения Тогда я могу сравнить:

  • «оконная ручка основной формы заявки», с
  • оконная ручка MainForm из Application

но они не совпадают:

Application.MainForm.Handle: 11473728
Application.Handle: 11079574

Так что же такое Application.Handle?

  • Откуда это?
  • Что такое Windows & reg; дескриптор окна это?
  • Если - это Windows & reg; дескриптор окна Application MainForm, тогда почему они не совпадают?
  • Если это , а не дескриптор окна Application MainForm, тогда что это?
  • Что еще более важно: почему это конечный родитель владелец каждой формы?
  • И самое главное: почему все идет наперекосяк, если я пытаюсь сделать форму непаренной неизвестной (чтобы я мог появиться на панели задач), или попытаться использовать что-то вроде IProgressDialog

На самом деле я спрашиваю: что такое логическое обоснование, по которому Application.Handle существует? Если я могу понять, почему, то как должно стать очевидным.


Обновление Понимание через игру двадцати вопросов:

Говоря о решении сделать так, чтобы окно появилось на панели задач, сделав его владельцем null, Питер Белоу в 2000 году сказал :

Это может вызвать некоторые проблемы с модальными формами, показанными вторичные формы.

Если пользователь отключается от приложения во время модального форма, а затем обратно к форме, которая показала это, модальная форма может скрыться под формой. С этим можно справиться, убедившись, что модальная форма является парентеральной [sic; он имел в виду принадлежал] к форме, которая показала это (используя params.WndParent как указано выше)

Но это невозможно со стандартным диалоги от Dialogs и исключений , которые требуют больше усилий для заставить их работать правильно (в основном обработка Application.OnActivate, ищем модальные формы для родителей Приложение через GetLastActivePopup и приведение их к вершине Z-порядка через SetWindowPos).

  • Почему модальная форма застревает позади других форм?
  • Какой механизм обычно выводит модальную форму на передний план, и почему он здесь не работает?
  • Windows & рег; отвечает за показ окна сложены. Что пошло не так, что Windows & reg; не отображаются правильные окна?

Он также говорил об использовании нового расширенного стиля Windows, который заставляет окно появляться на панели задач (когда обычные правила сделать его не принадлежащим, недостаточным, непрактичным или нежелательным), добавляя расширенный стиль WS_EX_APPWINDOW :

procedure TForm2.CreateParams(var Params: TCreateParams); 
begin 
   inherited CreateParams( params ); 

   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 
end; 

Но тогда он предупреждает:

Если вы нажмете кнопку панели задач вторичных форм, когда другое приложение active это все равно выведет все формы заявок на передний план. если ты не хочу чтобы была опция

Кто выводит все формы на фронт, когда владелец формы все еще Application.Handle. Приложение делает это? Почему он это делает? Вместо того, чтобы делать это, разве это не должно не делать это? В чем недостаток , а не , делающего это; я вижу недостаток в выполнении (системное меню работает неправильно, эскизы кнопок на панели задач неточны, оболочка Windows & reg не может свернуть окна.


В другом посте, посвященном Application, Майк Эденфилд говорит, что родительское окно отправляет другим окнам их сообщения о сворачивании, максимизации и восстановлении :

Это добавит кнопку панели задач для вашей формы, но есть несколько других мелких деталей справиться. Совершенно очевидно, что ваша форма по-прежнему получает минимизацию / максимизацию, которые отправляются родителю Форма (основная форма заявки). Во избежание этого вы можете установить сообщение обработчик для WM_SYSCOMMAND, добавив строку, такую ​​как:

procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND; 

procedure TParentForm.WMSysCommand(var Msg: TMessage); 
begin 
   if Msg.wParam = SC_MINIMIZE then 
   begin 
      // Send child windows message, don't 
      // send to windows with a taskbar button. 
   end; 
end; 

Обратите внимание, что этот обработчик идет в форме PARENT той, которую вы хотите вести независимо от остальной части приложения, чтобы избежать передачи сообщения минимизации. Вы можете добавить похожий> код для SC_MAXIMIZE, SC_RESTORE и т. Д.

Как минимизировать / развернуть / восстановить сообщения для моей Windows & reg; окна не идут к моему окну? Это потому, что сообщения, предназначенные для окна, отправляются Windows & reg; владельцу окна? И в этом случае все формы в приложении Delphi «принадлежат» Application? Не значит ли это, что обнулить владельца:

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
   inherited;
   Params.WndParent := 0; //NULL
end;

удалит Application и его окно Handle не будет вмешиваться в мою форму, и Windows снова должна отправить мне мои сообщения об уменьшении / увеличении / восстановлении?


Возможно, если бы мы теперь сравнивали и сравнивали «нормальное» приложение Windows, то с тем, как Borland изначально проектировал приложения Delphi для работы - в отношении этого объекта Application и его основного цикла.

  • Какое решение было Application объектным решением?
  • Какие изменения были внесены в более поздние версии Delphi, чтобы эти же проблемы не существовали?
  • Разве изменения в более поздних версиях Delphi не привели к другим проблемам, которые так трудно было решить первоначальным дизайном приложения?
  • Как эти новые приложения могут по-прежнему функционировать без приложения, мешающего им?

Очевидно, что Borland понял недостаток в их первоначальном дизайне. Каков был их первоначальный дизайн, какую проблему он решал, в чем недостаток, что было переделывать, и как это решает проблему?

Ответы [ 3 ]

48 голосов
/ 05 февраля 2010

Причина, по которой окно приложения имеет немного грязную историю. При разработке Delphi 1 мы знали, что хотим использовать модель интерфейса пользователя "SDI" (окна разбросаны по всему рабочему столу) для IDE. Мы также знали, что Windows сосала (и все еще делает) в этой модели. Однако мы также заметили, что Visual Basic в то время использовал эту модель, и она, казалось, работала хорошо. При дальнейшем рассмотрении мы обнаружили, что VB использовал специальное «скрытое» парковочное окно, которое использовалось как «владелец» (Windows иногда размывает понятие родителя и владельца, но различие похоже на VCL) для всех других видимых окон .

Вот как мы решили «проблему», когда окна, содержащие главное меню, были редко когда-либо сфокусированы, поэтому обработка Alt-F для меню «Файл» просто не работала. Используя это центральное парковочное окно в качестве посредника, мы могли бы легче отслеживать и направлять сообщения в соответствующие окна.

Эта договоренность также решила другую проблему, где обычно несколько окон верхнего уровня были полностью независимы. Заставив приложение обрабатывать «владельца» всех этих окон, они будут вести себя согласованно. Например, вы могли заметить, что когда вы выбираете любое окон приложения, все окна приложения перемещаются вперед и сохраняют свой z-порядок относительно друг друга. Это также приведет к минимизации и восстановлению приложения в виде функциональной группировки.

Это является следствием использования этой модели. Мы могли бы вручную проделать всю эту работу, чтобы все было просто, но философия дизайна заключалась не в том, чтобы заново изобретать Windows, а в том, чтобы использовать ее там, где мы могли. По этой же причине TButton или TEdit действительно являются классом и стилем окна "КНОПКА" и РЕДАКТИРОВАНИЕ Windows "Пользователь" соответственно.

По мере развития Windows эта модель "SDI" начала терять популярность. Фактически, сама Windows стала «враждебной» к этому стилю приложения. Начиная с Windows Vista и далее до 7, пользовательская оболочка, похоже, не очень хорошо работает с приложением, использующим окно парковки. Итак, мы решили перемешать вещи в VCL, чтобы убрать окно парковки и перенести его функцию в основную форму. Это создало несколько проблем типа «курица и яйцо», из-за которых нам нужно было иметь окно парковки достаточно рано при инициализации приложения, чтобы другие окна могли «прикрепиться» к нему, но сама основная форма может быть построена недостаточно быстро. TApplication должен перепрыгнуть через несколько обручей, чтобы заставить это работать, и было несколько тонких крайних случаев, которые вызвали проблему, но большинство проблем было решено. Однако для любого приложения, которое вы продвигаете, оно будет использовать старую модель парковочного окна.

12 голосов
/ 05 февраля 2010

Все приложения VCL имеют «скрытое» окно верхнего уровня, которое называется Приложение. Это создается автоматически при запуске приложения. Среди прочего это обработчик сообщений главного окна для VCL - отсюда Application.ProcessMessages.

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

Однако не все окна должны иметь его как родительский, Windows просто работает лучше, если он есть. Однако любая форма, созданная с помощью Application.CreateForm, будет иметь ее в качестве родительской, и она также будет принадлежать объекту Application. Поскольку они принадлежат, они будут освобождены после освобождения приложения. Это происходит за кулисами в Forms.DoneApplication

8 голосов
/ 05 февраля 2010

Из рассмотрения источника в forms.pas (Delphi 2009) видно, что они создают «главное» окно в графических приложениях win32, чтобы разрешить вызовы

  • TApplication.Minimize
  • TApplication.Restore
  • и т.д.

Похоже, что сообщения, переданные на Application.Handle, перенаправляются в соответствии с MainForm, если он существует. Это позволит приложению реагировать на сворачивание и т. Д., Если главное окно не было создано. Изменяя исходный код проекта, вы можете создать приложение Delphi без главного окна.

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

По вашим вопросам:

  • Откуда это? Это дескриптор окна, созданного в TApplication.Create

  • Что это за дескриптор окна? поддельное окно, которое требуется каждому приложению gui delphi как часть абстракции TApplication

  • Это дескриптор окна основной формы приложения Нет

  • Если это не дескриптор главной формы приложения, то что это? См. Выше

  • более важно: почему это конечный родитель для каждой формы? если вы правы, что это конечный родитель, я предполагаю, что это так, потому что это облегчает поиск всех форм в вашем заявлении (перечисление детей этой «основной» формы).

  • и самое важное: почему все идет наперекосяк, если я пытаюсь сделать форму непаренной? 1058 * передать его дочерним элементам и / или основной форме, но не может найти непареную форму.

Во всяком случае, это мое мнение. Вы можете узнать больше, посмотрев объявление и код TApplication в forms.pas. Суть в том, что я вижу, это удобная абстракция.

С уважением,

Don

...