Почему TForm.Handle является геттером, а не полем?

Недавно я устранял сложную ошибку. Это было вызвано доступом к несуществующему Form.Handle (мусорному указателю). Ошибка обнаружилась довольно неожиданным для меня образом - доступ к формам Handle вызывал изменение размеров и перерисовку.

Я ожидаю, что доступ к Form.Handle с помощью указателя мусора просто вернет какой-то мусор THandle. Ожидается, что Handle создается один раз при создании формы и остается неизменным до тех пор, пока форма не будет уничтожена.

Вопрос

Почему так, что TForm.Handle не является полем, которое инициализируется при создании формы и доступно через

property Handle: Integer read FHandle;

, но является геттером

property Handle: Integer read GetHandle;

который создает дескриптор и даже окно (CreateWnd) при первом доступе?


person Kromster    schedule 03.06.2016    source источник
comment
См. Delphi XE2, стили vcl, воссоздающие дескриптор окна и PostMessage возвращает "недопустимый дескриптор окна" в потоке. Короче говоря, окнам необходимо воссоздать дескриптор в определенных ситуациях.   -  person LU RD    schedule 03.06.2016
comment
Читать о восстановлении окна VCL   -  person David Heffernan    schedule 03.06.2016
comment
Потому что изменение определенных свойств окна требует его уничтожения и воссоздания (см. RecreateWnd и подсчитайте, сколько раз оно вызывается в модуле Forms). сложная ошибка была вызвана тем, что вы неправильно поняли Form.Handle, а не проблемой того, как TForm использует свой дескриптор. :-)   -  person Ken White    schedule 03.06.2016
comment
Вопрос, кажется, связывает/смешивает структуру свойства с [повторным] созданием окна. Вот почему вы получаете комментарии по одной из тем и ответ по другой.   -  person Sertac Akyuz    schedule 03.06.2016
comment
Не баг, а серьезное заблуждение. Ваше предположение просто неверно. См. stackoverflow.com/questions/21011780 и stackoverflow. .com/questions/582903   -  person Free Consulting    schedule 03.06.2016
comment
@FreeConsulting Вы прочитали вопрос? Текст, выделенный курсивом, не проблема, это просто вступление.   -  person Kromster    schedule 03.06.2016
comment
@Кромстер, да, я сделал. Это предусмотрено дизайном, поскольку некоторые стили окон/элементов управления не устанавливаются SetWindowLong в реальном времени HWND, но действуют только при CreateWindow вызове. Итак, VCL владеет дескриптором через HandleAllocated, HandleNeeded, CreateHandle и т. д.   -  person Free Consulting    schedule 03.06.2016


Ответы (1)


Форма object может существовать, даже если окно базовой ОС отсутствует. В это время поле Handle будет равно 0, что бесполезно для кода, которому требуется действительный дескриптор окна. Чтобы убедиться, что вы получаете действительный дескриптор каждый раз, когда он вам нужен, вам нужно будет вызвать HandleNeeded перед обращением к полю Handle. Как свойство с геттером, свойство может автоматически вызывать HandleNeeded, что упрощает использование свойства Handle.

person Rob Kennedy    schedule 03.06.2016
comment
сделать это проще, за исключением случаев, когда доступ к Handle из другого потока, что сейчас выглядит очень плохой идеей. - person Kromster; 03.06.2016
comment
Ага. В этих случаях сначала вызовите HandleAllocated, чтобы угадать, может ли последующий доступ Handle быть действительным. Вы не можете узнать, потому что основной поток может уничтожить окно между временем проверки и временем использования. В конечном счете, о создании пользовательского интерфейса в других потоках. Если другому потоку нужно знать дескриптор окна, сделайте так, чтобы основной поток предоставлял дескриптор другому потоку (а не другой поток, извлекающий сам дескриптор), а также поручите основному потоку взять на себя ответственность обеспечения того, чтобы предоставленный дескриптор оставался действительным до тех пор, пока он нужен другому потоку. - person Rob Kennedy; 03.06.2016
comment
@Kromster, если вам нужен доступ к дескриптору формы из потока для отправки / публикации сообщений, вероятно, было бы лучше выделить дескриптор с AllocateHwnd() в основном потоке и позволить потоку отправлять сообщения этому дескриптору. Оттуда сообщения могут быть перенаправлены в VCL. - person LU RD; 03.06.2016
comment
Я бы сказал это сильнее, чем @LURD. Правило состоит в том, что вы никогда не используете дескриптор окна VCL вне основного потока, потому что он может быть воссоздан. Таким образом, вы используете дескриптор окна, которого нет, например, из AllocateHWnd. - person David Heffernan; 03.06.2016