PeaShooter_OMO 34 Posted 8 hours ago (edited) In Delphi 11, Windows 10... I have a small project where I create a form (the same Form object) with two different states; a Normal form and a Borderless Shadowed form (created via CreateParams and CS_DROPSHADOW). After starting the program, if I create the Borderless form first then the shadow will be there. If I create the Normal form first and then the Borderless form then the shadow of the Borderless form will not be there. Attached you will find a .zip file with the project. Project.zip Steps to produce the strange behaviour... Start the program Create the Normal form first Close the Normal form via the "Close" button. Create the Borderless Shadowed Popup form. Notice the shadow does not appear. You can close and create all you like. The shadow never appears beneath the Borderless form. Steps to produce a shadow at all times... Start the program Create the Borderless Shadowed Popup form first. Notice the shadow is correctly appearing. Close the Borderless form. Create the Normal form. Close the Normal form. Create the Borderless Shadowed Popup form again. Notice the shadow is correctly appearing. You can flip-clop between the two as much as you like, the shadow will always be there. Obviously I would expect the Borderless form to always have its shadow. Am I doing something wrong? type TFormMain = class(TForm) ButtonCreateNormal: TButton; ButtonCreateBorderless: TButton; procedure ButtonCreateNormalClick(Sender: TObject); procedure ButtonCreateBorderlessClick(Sender: TObject); private public end; var FormMain: TFormMain; implementation {$R *.dfm} uses UnitPopup; procedure TFormMain.ButtonCreateBorderlessClick(Sender: TObject); begin FormPopup := TFormPopup.Create(True); FormPopup.Show; end; procedure TFormMain.ButtonCreateNormalClick(Sender: TObject); begin FormPopup := TFormPopup.Create(False); FormPopup.Show; end; type TFormPopup = class(TForm) Panel1: TPanel; ButtonClose: TButton; procedure ButtonCloseClick(Sender: TObject); private FIsBorderlessPopup : Boolean; protected procedure CreateParams(var Params: TCreateParams); override; public constructor Create(AIsBorderlessPopup : Boolean); reintroduce; end; var FormPopup: TFormPopup; implementation {$R *.dfm} procedure TFormPopup.ButtonCloseClick(Sender: TObject); begin FreeAndNil(FormPopup); end; constructor TFormPopup.Create(AIsBorderlessPopup : Boolean); begin FIsBorderlessPopup := AIsBorderlessPopup; inherited Create(nil); If FIsBorderlessPopup then begin Panel1.BorderStyle := bsSingle; Panel1.Caption := 'Borderless Shadowed'; end else begin Panel1.BorderStyle := bsNone; Panel1.Caption := 'Normal Form'; end; end; procedure TFormPopup.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); If FIsBorderlessPopup then begin Params.Style := WS_POPUP; Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW; Params.ExStyle := WS_EX_TOPMOST; end; end; Edited 8 hours ago by PeaShooter_OMO Share this post Link to post
Kas Ob. 138 Posted 7 hours ago 28 minutes ago, PeaShooter_OMO said: Am I doing something wrong? Nothing wrong, just missed "RecreateWnd;" after setting the Params. Share this post Link to post
Anders Melander 1988 Posted 7 hours ago 8 minutes ago, Kas Ob. said: Nothing wrong, just missed "RecreateWnd;" after setting the Params. I don't get it. Isn't CreateParams called before the window handle is created? Then why would RecreateWnd be necessary? Share this post Link to post
Kas Ob. 138 Posted 7 hours ago 24 minutes ago, Anders Melander said: I don't get it. Isn't CreateParams called before the window handle is created? Then why would RecreateWnd be necessary? It is beyond me why it is needed, short coming in CM_RECREATEWND that used to trigger the recreation and when it is received, (i think ) It could be made better but will break things, also may be things changed in newer VCLs but in the older ones RecreateWnd is needed, even it means the recreation will happen twice. 1 Share this post Link to post
Kas Ob. 138 Posted 6 hours ago Testing the real project and now i see even with RecreateWnd it is not reliable, and acting as there is something is not initialized. On XE8, the same code with RecreateWnd, act differently with or without debug dcu included in project settings !, and if there is a break point that halted the code execution then the shadow might appear more frequently. Share this post Link to post
Kas Ob. 138 Posted 5 hours ago Found the culprit of this discrepancy, but don't have a solution, or lets say nice solution, on top of that my old VCL is irrelevant to the most , so , someone else should have a deeper look into this. There is two different RegisterClass functions, one belong to Delphi RTL and the other is an OS API, Delphi Forms like other controls do register them selves with RegisterClass with unique name, on both API and RTL, the one is causing this problem is API how Windows store the style, Delphi RTL doesn't handle UnregisterClass (API) correctly or not calling it at all, hence CreateParams and the following creating the control (and setting its modern and advanced style) stay short from performing as intended. As a workaround a suggest to refactor your popup into base and two inherited ones hence forcing the class name used by RegisterClass to be different, one with shadow and the other without, this will be the most clean way, though it must be tested. ps: @PeaShooter_OMO don't call "FreeAndNil(FormPopup);" on Self, this is problematic and dangerous, just use "Release;" and it will be released in orderly form, and you can skip the var usage altogether by using with TFormPopup.Create(True) do Show; // or with TFormPopup.Create(False) do Show; Share this post Link to post
PeaShooter_OMO 34 Posted 5 hours ago @Kas Ob. Deriving another class for the Borderless form did the trick. It is an interesting one, indeed. Thank you for your input. Share this post Link to post