I have created a simple application that sleeps for 5 seconds before showing a form (to give time to minimize the remote desktop) then calls repaint on a dock site manually the first time application.onidle is triggered. (Sending via e-mail).
At the moment, The only solution I have to this problem is to skip the call to GDICheck... which seems like a shame and isn't really addressing the root cause.
The root cause of Paint being called before the remote desktop in the real application here is difficult to determine as the stack trace we get goes only as far as the message handler... But it may help you anyway (see end of message).
Any advice/thoughts?
Thanks in advance,
Eddie.
Exception class: EOSError
Exception address: 00436947
----------------------------------------------------------------------------------------------------
Stack list, generated 24/04/13 18:14:44
[00436942] System.SysUtils.RaiseLastOSError (Line 22576, "System.SysUtils.pas" + 6) + $2
[004368BF] System.SysUtils.RaiseLastOSError (Line 22559, "System.SysUtils.pas" + 0) + $7
[00B01DB5] LMDDckStyles.GDICheck (Line 613, "LMDDckStyles.pas" + 2) + $0
[00B08482] LMDDckStyles.TBufDrawData.Flush (Line 3049, "LMDDckStyles.pas" + 10) + $40
[00B07E34] LMDDckStyles.TLMDBuffer.EndDraw (Line 2867, "LMDDckStyles.pas" + 5) + $3
[00B22F0C] LMDDckSite.TLMDDockZoneTree.Paint (Line 5531, "LMDDckSite.pas" + 9) + $5
[00B25D39] LMDDckSite.TLMDDockSite.Paint (Line 7052, "LMDDckSite.pas" + 2) + $12
[0065DE3B] Vcl.Controls.TCustomControl.PaintWindow (Line 13841, "Vcl.Controls.pas" + 6) + $5
[00658129] Vcl.Controls.TWinControl.PaintHandler (Line 10123, "Vcl.Controls.pas" + 4) + $14
[0065891C] Vcl.Controls.TWinControl.WMPaint (Line 10324, "Vcl.Controls.pas" + 6) + $5
[0062617D] Vcl.Forms.TCustomForm.WMSettingChange (Line 7164, "Vcl.Forms.pas" + 3) + $4
[006534C9] Vcl.Controls.TControl.WndProc (Line 7224, "Vcl.Controls.pas" + 91) + $6
[00433939] System.SysUtils.TFormatSettings.Create (Line 18843, "System.SysUtils.pas" + 33) + $15
[0065DDD5] Vcl.Controls.TCustomControl.WMPaint (Line 13830, "Vcl.Controls.pas" + 2) + $4
[006534C9] Vcl.Controls.TControl.WndProc (Line 7224, "Vcl.Controls.pas" + 91) + $6
[00657F5D] Vcl.Controls.TWinControl.WndProc (Line 10039, "Vcl.Controls.pas" + 153) + $6
[006575A0] Vcl.Controls.TWinControl.MainWndProc (Line 9751, "Vcl.Controls.pas" + 3) + $6
[004D9CAC] System.Classes.StdWndProc (Line 16891, "System.Classes.pas" + 8) + $0
[0064E32A] Vcl.Controls.FindControl (Line 3559, "Vcl.Controls.pas" + 6) + $9
[0062A60B] Vcl.Forms.TApplication.ProcessMessage (Line 10208, "Vcl.Forms.pas" + 23) + $1
[0062A64E] Vcl.Forms.TApplication.HandleMessage (Line 10238, "Vcl.Forms.pas" + 1) + $4
[0062A989] Vcl.Forms.TApplication.Run (Line 10376, "Vcl.Forms.pas" + 26) + $3
Comments
1. Create a new VCL test application, add a TLMDDockSite, and build it.
2. Start a remote desktop session into the PC (which causes the console session to become locked) and launch the test application.
3. Unlock the console session. The remote session ends, and the test application crashes with exactly the same stack trace as in Eddie's message above.
(You can do the above using a virtual machine for the PC you remote desktop into. Reproducible with Windows 7 and XP at least.)
I can't see anything in the history. Is this bug fixed yet?
This is the same error noted by Eddie above, so I'd like to know if you have changed this code since version 2013.6? If so then perhaps it is worth me upgrading to the latest release.
After much investigation, I've concluded that the best solution is to remove the GDICheck() altogether.
It's documented that BltBlt() and other GDI functions fail with ERROR_INVALID_HANDLE if the session is disconnected, and this is quite normal behaviour. So I tried to modify GDICheck() to ignore ERROR_INVALID_HANDLE specifically in this situation.
Unfortunately it turned out to be impossible. I wrote a test C++ application that calls BitBlt() in its WM_PAINT handler and ran this from a console session in a Win7 VM. I then remoted in (as the same user), which ends the console session and begins a new remote session. The sequence of events was as follows:
WM_PAINT
BitBlt failed: ERROR_INVALID_HANDLE
WM_PAINT
BitBlt failed: ERROR_INVALID_HANDLE
WM_WTSSESSION_CHANGE - WTS_CONSOLE_DISCONNECT
WM_PAINT
BitBlt failed: ERROR_INVALID_HANDLE
WM_PAINT (succeeds)
WM_WTSSESSION_CHANGE - WTS_REMOTE_CONNECT
In short, the window receives two WM_PAINT messages before it is notified that the session is changing but already by this time BitBlt() fails. So the WM_WTSSESSION_CHANGE messages are sent too late to be of use. It is the same if you call WTSQuerySessionInformation() - you get the previous state, WTSActive.
So it looks like there is no way to distinguish an ERROR_INVALID_HANDLE error due to a session change, and one due to some real fault.
I don't think that LMD Docking Pack is doing anything wrong in its drawing. The only 'mistake' is that it is bothering to check the return code from BitBlt().