Jump to content

pyscripter

Members
  • Content Count

    425
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by pyscripter

  1. pyscripter

    Remote desktop friendly

    In light of @David Heffernan remarks here is a shorter version of @Stephen Ball code: type TForm1 = class(TForm) procedure CreateWnd; override; procedure WMWTSSessionChange (var Message: TMessage); message WM_WTSSESSION_CHANGE ; procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.WMDestroy(var Message: TWMDestroy); begin inherited; WTSUnRegisterSessionNotification(Handle); end; procedure TForm1.WMWTSSessionChange(var Message: TMessage); begin case Message.wParam of WTS_SESSION_LOCK, WTS_REMOTE_DISCONNECT: Application.UpdateMetricSettings := False; WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK: TThread.ForceQueue(nil, procedure begin Application.UpdateMetricSettings := True; end, 30000); end; end; procedure TForm1.CreateWnd; begin inherited; WTSRegisterSessionNotification(Handle, NOTIFY_FOR_THIS_SESSION); end; Instead of CreateWnd you could override the CreateWindowHandle method.
  2. pyscripter

    Remote desktop friendly

    See DestroyWnd not called at destruction of WinControls - VCL - Delphi-PRAXiS [en]
  3. pyscripter

    Remote desktop friendly

    Thanks! DestroyWnd is not called when the application exits. Is this an issue here? You could call the WTSUnRegisterSessionNotification at the WM_DESTROY handler instead.
  4. pyscripter

    Remote desktop friendly

    @Stephen BallThank you very much! Is there a need to have a separate window to receive the notifications? Isn't the code below equivalent to yours? type TForm1 = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure WMWTSSessionChange (var Message: TMessage); message WM_WTSSESSION_CHANGE ; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormDestroy(Sender: TObject); begin WTSUnRegisterSessionNotification(Handle); end; procedure TForm1.WMWTSSessionChange(var Message: TMessage); begin inherited; case Message.wParam of WTS_SESSION_LOCK, WTS_REMOTE_DISCONNECT: Application.UpdateMetricSettings := False; WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK: TThread.ForceQueue(nil, procedure begin Application.UpdateMetricSettings := True; end, 30000); end; end; procedure TForm1.FormCreate(Sender: TObject); begin WTSRegisterSessionNotification(Handle, NOTIFY_FOR_THIS_SESSION); end;
  5. pyscripter

    TTreeNode leak when VCL styles are active

    This is not true. StyleEngine.Destroys calls FreeControlHooks which destroys all remaining hooks. However what @Attila Kovacs suggests is problematic, since you keep accumulating unreleased hooks if the application creates and destroys styled controls.
  6. pyscripter

    TTreeNode leak when VCL styles are active

    Could you tell us how?
  7. pyscripter

    TTreeNode leak when VCL styles are active

    I did a bit of research to assess whether other parts of Vcl could be suffering from the same issue. The only controls that recreate themselves in response to the CM_STYLECHANGED message are the TListView and the ActionManager controls (ActionToolbar etc.). I think there are not scrollbars and the like there, but I wonder why there is a need to do that. So the issue may be confined to the ListView and if the call to RecreateWnd can be avoided that would be the simplest solution.
  8. pyscripter

    TTreeNode leak when VCL styles are active

    Update: This does not work well. One suggestion I have is the following: Change TStyleEngine.DoRemoveControl(Control: TWinControl) from: class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); var I: Integer; LControl: TControl; begin if (FControls <> nil) and FControls.ContainsKey(Control) then begin for I := 0 to Control.ControlCount - 1 do begin LControl := Control.Controls[I]; if LControl is TWinControl then DoRemoveControl(TWinControl(LControl)); end; FControls.Items[Control].Free; FControls.Remove(Control); end; end; to class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); var I: Integer; LControl: TControl; begin if not (csRecreating in Control.ControlState) and (FControls <> nil) and FControls.ContainsKey(Control) then begin for I := 0 to Control.ControlCount - 1 do begin LControl := Control.Controls[I]; if LControl is TWinControl then DoRemoveControl(TWinControl(LControl)); end; FControls.Items[Control].Free; FControls.Remove(Control); end; end; or even to: class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); begin if not (csRecreating in Control.ControlState) and (FControls <> nil) and FControls.ContainsKey(Control) then begin FControls.Items[Control].Free; FControls.Remove(Control); end; end; There seems to be no reason to destroy the hook if the control is recreating. Also hooks of child controls would be removed when they get destroyed, so there is no need to do this in advance. Do you see anything wrong with the above? With the above change the test app runs fine and without memory leaks. And the change would save a lot of hook destruction and reconstruction. To test copy Vcl.Styles.pas, StyleAPI.inc and StyleUtils.inc to the project source directory, make the change and re-build the project.
  9. pyscripter

    TTreeNode leak when VCL styles are active

    We now understand the cause of this issue. Great work @balabuev. But now we need to come up with a good fix to propose to Embarcadero. My earlier question "Shouldn't the ListView TScrollWindows be above the ListView after it gets recreated?" still stands. If the order was not messed up, the error would not occur. Or can the recursive calling of DestroyWindow window be avoided without introducing other bugs? Although in the case of the ListView the RecreateWnd as a response ot CM_STYLECHANGED the call to RecreateWnd appears to be redundant, RecreateWnd happens often with many controls and for all sort of reasons (e.g. a property change). So Vcl should be able to handle such calls robustly.
  10. pyscripter

    Can't load package Python$(Auto).bpl

    You need to update to 10.4.1 or better to 10.4.2.
  11. pyscripter

    TTreeNode leak when VCL styles are active

    Shouldn't the ListView TScrollWindows be above the ListView after it gets recreated? This is what happens when it is originally created Why are they not on top? By the way readers of this thread may be interested in a related old post of mine:
  12. pyscripter

    VCL and VCL styles - bugs and future

    Although Vcl.Styles is not mature. I would say it is usable. The Delphi IDE is a proof of that. I have been producing PyScripter with Vcl.Styles for the last five years, and I had no issues that could not be overcome. And now you can have per monitor aware, styled Delphi applications. And since this this discussion started about flicker, there are ways of working around that. The Delphi IDE and PyScripter have minimal flicker. The great thing about Vcl is that applications developed almost 20 years ago, can still work well and look modern, just by recompiling pretty much the same old code. I have mentioned this before, just compare to the Microsoft Desktop application landscape. A new framework is introduced every 3-4 years, mostly incompatible with the others: - Visual Basic with ActiveX controls - C++ with Windows API - WinForms - WPF - Silverlight - Xamarin - UWP - WinUI - MAUI - Project Reunion - etc. Where would you be if you invested in Visual Basic and ActiveX controls for example? Ironically, you can still use ActiveX controls in Delphi if you so wish.
  13. pyscripter

    Window hooking

    See python4delphi/Tutorials/Webinar II at master · pyscripter/python4delphi (github.com) Both video and source code.
  14. pyscripter

    Remote desktop friendly

    Looking forward to reading it!
  15. pyscripter

    TTreeNode leak when VCL styles are active

    The question still remains why the change in the order results in the Treeview not receiving the WM_DESTROY message. Why is the order important anyway in this issue?
  16. pyscripter

    TTreeNode leak when VCL styles are active

    @Vincent Parrett@Attila KovacsI am afraid you are both off-topic. If you want to rant about Vcl, Vcl.Styles, Embarcadero etc. please do it in a new thread.
  17. pyscripter

    ANN: Parnassus Parallel Debugger

    @David MillingtonThe features of Parnassus Debugger are great, but I am getting assertion errors with the Parnassus Debugger and Delphi 10.4.2. I am also getting Index out of bounds errors. These occurred while debugging simple Vcl apps (nothing fancy) and they don't occur in the absence of the Parnassus Debugger. Is https://quality.embarcadero.com/ the right place to report issues related to the Parnassus Debugger.
  18. pyscripter

    TTreeNode leak when VCL styles are active

    The issue results from the TListView being recreated as a response to the CM_STYLECHANGED message (see CustomListView.WndProc). If you add the following at the top of UMainForm.pas TListView = class(Vcl.ComCtrls.TListView) protected procedure WndProc(var Message: TMessage); override; end; with the following implementation procedure TListView.WndProc(var Message: TMessage); begin if (Message.Msg = CM_STYLECHANGED) then begin if ViewStyle = vsReport then UpdateColumns; end else inherited; end; the error does not happen. There does not appear to be much point in recreating the ListView, since its handle would have already been recreated, when the form it resides gets recreated. Still it remains a mystery why the recreation of the ListView affects the TreeView! The memory leak is also prevented by calling RecreateWnd after changing the style. In the process of debugging, I discovered another Vcl bug: [RSP-33221] CM_STYLEDCHANGE is broadcast twice - Embarcadero Technologies
  19. pyscripter

    TTreeNode leak when VCL styles are active

    You need to remove the build event from the project options. This was stated earlier in this thread.
  20. pyscripter

    TTreeNode leak when VCL styles are active

    This is indeed weird. In fact, just turning the Visible property of the ListView to False prevents the error. Some further observations: I confirm that WMDestroy is not received by the treeview The bug is definitely related to Vcl.Styles. If you change the style to a Vcl.Style and then back to Windows, the error does not occur You can prevent the error by calling Treeview.Items.Clear in the FormCloseQuery event handler. Strangely calling RecreateWnd in the same handler also prevents the error.
  21. pyscripter

    Issues running Demo Projects on D10.4.2 / Python 3.9.2

    You need to add: {$I Definition.inc} to the Demo 31 Unit1.pas It was accidentally deleted in a recent commit. This is now fixed.
  22. pyscripter

    Remote desktop friendly

    @David MillingtonMaybe you could enlighten us as to the nature of the changes that made the Delphi IDE behave better with RD. Are there any lessons to be learnt by Delphi developers?
  23. XML used to be considered the universal data format. Now is a bit passé with JSON, YAML etc being "in". I got involved in XML parsing, since SVG files are in XML format. XML Delphi support At the surface the XML support in Delphi is very good: You have TXMLDocument/IXMLDocument offering high-level support (Xml.xmldoc) Support for the standard DOM interfaces (Xml.XmlDom) Multiple implementations including (MSXML, OmniXML, OpenXML and more) Ability to plug in your own implementation Multiple platform support. The most common way of accessing XML is through TXMLDocument/IXMLDocument. However there is a big catch: PERFORMANCE. Say you want to use MSXML and you specify 'MSXML' as your DefaultDomVendor. (or you simply include the implementation unit Xml.Win.msxmldom in your uses clause). Your create an XML document and you access the top node: var Doc: IXMLDocument = TXMLDocument.Create(nil); var Node: IXMLNode := Doc.DocumentElement; Node is an IXMLInterface implemented by TXMLNode (TInterfacedObject defined in Xml.XmlDoc). TXMLNode wraps an IDOMNode stored in a private field FDOMNode. IDOMNode is defined in Xml.Xmldom. The IDOMNode is implemented by the used vendor in this case Xml.Win.msxmldom by a class TMSDOMNode TMSDOMNode (also a TInterfacedObject) wraps IXMLDOMNode stored in a private field FMSNode. IXMLDOMNode is defined in Winapi.msxml. As a result when you create any IXMLNode, a TXMLNode is created and this creates a TMSDOMNode which points to an IXMLDOMNode. Any call/property access to IXMLNode translates in a call of IDOMNode which then calls IXMLDOMNode. The created TInterfaced objects also need to be destroyed when you release your XML Node. The same two-level indirection applies to all XML objects (attributes, Children) and cause a huge degradation of performance. Conclusion If you care about speed forget about TXMLDocument. You can access the Vendor implementation or even better in the case of MSXML the Microsoft ActiveX objects directly: uses WinAPI.msxml var XML: IXMLDOMDocument3 := CoDOMDocument60.Create; XML.loadXML(XMLString); var DocNode: IXMLDOMNode := XML.documentElement; In SVG parsing and processing accessing directly the ActiveX objects reduced processing time by more than 50%. Additional tip A common performance pitfall with MSXML is explained in http://www.gerixsoft.com/blog/delphi/msxml. The fastest way to iterate through ChildNodes is via getFirstChild/nextSibling and Attributes via nextNode.
  24. pyscripter

    Issues running Demo Projects on D10.4.2 / Python 3.9.2

    Please update to the most recent version. Demo7 is fixed. I can run Demo31 without any issues.
  25. @Darian Millerhas published a very nice article about the state of TThreadedQueue and TMonitor in Delphi. He has also published at Github a stress test that shows how TThreadQueue still fails under stress. I have played with his stress test and concluded that the problem is almost certainly in TMonitor. TMonitor implements a lock-free stack to recycle events created with the CreateEvent function. The relevant code in SysUtils is var EventCache: PEventItemHolder; EventItemHolders: PEventItemHolder; procedure Push(var Stack: PEventItemHolder; EventItem: PEventItemHolder); var LStack: PEventItemHolder; begin repeat LStack := Stack; EventItem.Next := LStack; until AtomicCmpExchange(Pointer(Stack), EventItem, LStack) = LStack; end; function Pop(var Stack: PEventItemHolder): PEventItemHolder; begin repeat Result := Stack; if Result = nil then Exit; until AtomicCmpExchange(Pointer(Stack), Result.Next, Result) = Result; end; This lock-free stack is used by NewWaitObj and FreeWaitObj which are part of the Monitor support protocol and used by TMonitor. This works reasonably well, but under stress it fails. The reason it fails is known as the ABA problem and is discussed in a similar context by a series of excellent blog posts by @Primož Gabrijelčič: blog post 1, blog post 2, blog post 3. His OmniThreadLibrary contains the following routine that he uses to deal with this problem. /either 8-byte or 16-byte CAS, depending on the platform; destination must be propely aligned (8- or 16-byte) function CAS(const oldData: pointer; oldReference: NativeInt; newData: pointer; newReference: NativeInt; var destination): boolean; asm {$IFNDEF CPUX64} push edi push ebx mov ebx, newData mov ecx, newReference mov edi, destination lock cmpxchg8b qword ptr [edi] pop ebx pop edi {$ELSE CPUX64} .noframe push rbx //rsp := rsp - 8 ! mov rax, oldData mov rbx, newData mov rcx, newReference mov r8, [destination + 8] //+8 with respect to .noframe lock cmpxchg16b [r8] pop rbx {$ENDIF CPUX64} setz al end; { CAS } I have tried to use this function to provide a solution for TMonitor similar to the one in OmniThreadLibrary. (see attached iaStressTest.TThreadedQueue.PopItem that can be used with the original stress test). Whilst still not perfect it helps a lot in 32 bits with say up to 100 threads. However it crashes in 64bits and I do not know why. I am posting this here in case anyone with better knowledge than mine of assembler and thread programming can help with the challenge of fixing TMonitor. It would be nice to try and get a fix included in 10.4. And even if it is not included, it can be easily used as a patch in the same way as in the attached code. iaStressTest.TThreadedQueue.PopItem.pas
×