О чём не пишут в книгах по Delphi - [17]
> begin
> if Parent <> nil then Parent.HandleNeeded;
> CreateHandle;
> end;
>end;
>function TWinControl.GetHandle: HWnd;
>begin
> HandleNeeded;
> Result := FHandle;
>end;
При каждом обращении к свойству >Handle вызывается метод >HandleNeeded, который проверяет, создано ли уже окно, и если нет, создает его, попутно создавая, при необходимости, родительское окно. Таким образом, окно создается при первом обращении к свойству >Handle.
Метод >CreateHandle, который вызывается из >HandleNeeded, выполняет непосредственно лишь несколько вспомогательных операций, а для создания окна вызывает еще один метод — >CreateWnd (листинг 1.9).
>CreateWnd>procedure TWndControl.CreateWnd;
>var
> Params: TCreateParams;
> TempClass: TWndClass;
> ClassRegistered: Boolean;
>begin
> CreateParams(Params);
> with Params do
> begin
> if (WndParent = 0) end (Style and WS_CHILD <> 0) then
> if (Owner <> nil) end (csReading in Owner.ComponentState) and (Owner is TWinControl) then
> WndParent TWinControl(Owner).Handle
> else
> raise EInvalidOperation.CreateFmt(SParentRequired, [Name]);
> FDefWndProc := WindowClass.lpfnWndProc;
> ClassRegistered := GetClassInfo(WindowClass.hInstance, WinClassName, TempClass);
> if not ClassRegistered or (TempClass.lpfnWndProc <> @InitWndProc) then
> begin
> if (ClassRegistered then
> Windows.UnregisterClass(WinClassName, WindowClass.hInstance);
> WindowClass.lpfnWndProc := InitWndProc;
> WindowClass.lpszClassName := WinClassName;
> if Windows.RegisterClass(WindowClass) = 0 then RaiseLastOSError;
> end;
> CreationControl := Self;
> CreateWindowHandle(Params);
> if FHandle = 0 then RaiseLastOSError;
> if (GetWindowLong(FHandle, GWL_STYLE) and WS_CHILD <> 0) and (GetWindowLong(FHandle, GWL_ID) = 0) then
> SetWindowLong(FHandle, GWL_ID, FHandle);
> end;
> StrDispose(FText);
> FText := nil;
> UpdateBounds;
> Perform(WM_SETFONT, FFont.Handle, 1);
> if AutoSize then AdjustSize;
>end;
Собственно создание окна опять происходит не здесь, а в методе >CreateWindowHandle, который очень прост: он состоит из одного только вызова API-функции >CreateWindowEx с параметрами, значения которых берутся из полей записи >Params типа >TCreateParams (листинг 1.10)
>TCreateParams>TCreateParams = record
> Caption: PChar;
> Style: WORD;
> ExStyle: DWORD;
> X, Y: Integer;
> Width, Height: Integer;
> WndParent: HWnd;
> Param: Pointer;
> WindowClass: TWndClass;
> WinClassName: array[0..63] of Char;
>end;
В записи >Params хранятся параметры как окна, передаваемые в функцию >WindowCreateEx, так и оконного класса (поля >WindowClass и >WndClassName). Все поля инициализируются методом >CreateParams на основе значений свойств оконного компонента. Данный метод виртуальный и может быть перекрыт в наследниках, что бывает полезно, когда необходимо изменить стиль создаваемого окна. Например, добавив расширенный стиль >WS_EX_CLIENTEDGE (или, как вариант, >WS_EX_STATICEDGE), можно получить окно с необычной рамкой (листинг 1.11).
>CreateParams>procedure TForm1.CreateParams(var Params: TCreateParams);
>begin
> // Вызов унаследованного метода заполнения всех полей
> // записи Params
> inherited CreateParams(Params);
> // Добавляем флаг WS_EX_CLIENTEEDGE к расширенному стилю окна
> Params.ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
>end;
В разд. 1.1.4 мы говорили, что имя оконного класса, который VCL создает для оконного компонента, совпадает с именем класса этого компонента. Здесь мы видим, что на самом деле имя оконного класса можно сделать и другим, для этого достаточно изменить значение поля >Params.WinClassName.
Обратите внимание, что всем без исключения классам метод >CreateWnd назначает одну и ту же оконную процедуру — >InitWndProc. Это является основой в обработке сообщений с помощью VCL, именно поэтому оконная процедура назначается не в методе >CreateParams, а в методе >CreateWnd, чтобы в наследниках нельзя было изменить это поведение (метод >CreateWnd тоже виртуальный, но при его переопределении имеет смысл только добавлять какие-то действия, а не изменять поведение унаследованного метода).
Чтобы понять, как работает процедура >InitWndProc, обратите внимание на еще одну особенность метода >CreateWnd: перед вызовом >CreateWindowHandle (т.е. непосредственно перед созданием окна) он записывает ссылку на текущий объект в глобальную переменную >СreationСontrol. Эта переменная затем используется процедурой >InitWndProc (листинг 1.12).
>InitWndProc>function InitWndProc(HWindow: HWnd; Message, WParam, LParam: LongInt): LongInt;
>begin
> CreationControl.FHandle := HWindow;
> SetWindowLong (HWindow, GWL_WNDPROC, LongInt(CreationControl.FObjectInstance));
> if (GetWindowLong(HWindow, GWL_STYLE) and WS_CHILD <> 0) and (GetWindowLong(HWindow, GWL_ID) = 0) then
> SetWindowLong(HWindow, GWL_ID, HWindow);
> SetProp(HWindow, MakeIntAtom(ControlAtom), THandle(CreationControl));
> SetProp(HWindow, MakeIntAtom(WindowAtom), THandle(CreationControl));
> asm
> PUSH LParam
> PUSH WParam
> PUSH Message
> PUSH HWindow
> MOV EAX, CreationControl
> MOV CreationControl, 0
> CALL [EAX].TWinControl.FObjectInstance
В практике разработки ПО зачастую встает задача динамической модификации программного кода в зависимости от текущих или настраиваемых значений параметров. Для решения этой задачи широко используются обратные вызовы. В языке C++ обратные вызовы реализуются различными способами, и далеко не всегда очевидно, какой из них лучший для конкретной ситуации. В книге рассмотрены теоретические и практические аспекты организации обратных вызовов, проанализированы достоинства и недостатки различных реализаций, выработаны рекомендации по выбору в зависимости от требований к проектируемому ПО.
Хватит тратить время на скучные академические фолианты! Изучение Computer Science может быть веселым и увлекательным занятием. Владстон Феррейра Фило знакомит нас с вычислительным мышлением, позволяющим решать любые сложные задачи. Научиться писать код просто — пара недель на курсах, и вы «программист», но чтобы стать профи, который будет востребован всегда и везде, нужны фундаментальные знания. Здесь вы найдете только самую важную информацию, которая необходима каждому разработчику и программисту каждый день. «Эта книга пригодится и для решения повседневных задач.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Хорошее программное обеспечение создается людьми. Так же как и плохое. Именно поэтому основная тема этой книги — не аппаратное и не программное обеспечение, а человеческий фактор в программировании (peopleware). Первое издание «Constantine on Peopleware» признано классическим трудом в области информационных технологий. Новая книга Ларри Константина включает все 52 легендарные статьи из предыдущей книги и 25 новых эссе.Peopleware охватывает все аспекты, связанные с ролью людей в разработке программного обеспечения.
United system for program documentation. Technical specification for development. Requirements to contents and form of presentation Настоящий стандарт устанавливает порядок построения и оформления технического задания на разработку программы или программного изделия для вычислительных машин, комплексов и систем независимо от их назначения и области применения.Стандарт полностью соответствует СТ СЭВ 1627-79.Переиздание (Ноябрь 1987 г.) с Изменением № 1, утвержденным в июле 1981 г (ИУС 7-81)
Очень часто под рукой не оказывается ни отладчика, ни дизассемблера, ни даже компилятора, чтобы набросать хотя бы примитивный трассировщик. Разумеется, что говорить о взломе современных защитных механизмов в таких условиях просто смешно, но что делать если жизнь заставляет?..