Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

TLMDDockSite.Paint raises exception if called in minimised RDP session

The call to BitBlt in TBufDrawData.Flush results in system error raised if TLMDDockSite.Paint get called when in a minimized remote desktop session.

No other Paint calls in the VCL or other 3rd party components we use here seem to do this (at we haven't seen this before!)

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


Tagged:

Comments

  • 10 Comments sorted by Votes Date Added
  • Please specify your OS. I know about similar problem on XP after long session sleep...
  • Apologies, its Windows 7 x64 Enterprise SP1 for both the client and server.

    It does not require any length of session sleep... But that is where we first noticed the problem... Someone would load the application and go off for a cup of tea then return to their desk, wake the RDP session and see the error.

    After some head scratching, I narrowed it down to a simple script... Launch the application on the remote machine and minimize the remote desktop session before the application has loaded. Wait a few seconds (for loading to finish) and maximise the remote desktop window... the exception dialog will be there waiting. Then I produced the simple test application to mimic the same behavior in the simplest possible way (with a Sleep replacing the lengthy loading times of our real application).

    Hope that helps.
  • I'll try to do something with such errors in the next version.
  • edited June 2015 Posts: 0Vote Up0Vote Down
    I've also encountered this bug in a slightly different context. It's easy to reproduce:

    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?
  • Hi,

    I've checked it on my setup (PC and notebook, Win8.1 on both); and I can't reproduce the issue.

    Eugene,
    LMD Innovative.
  • The crash occurs because the call to BitBlt made from TBufDrawData.Flush fails with an invalid handle error, which results in GDICheck raising the exception.

    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.
  • Hi,

    IanGoldby, can you modify the source of TBufDrawData.Flush procedure as shown below and recheck:

    procedure TBufDrawData.Flush;
    var
      x, y: Integer;
      w, h: Integer;
    begin
      Assert(FInited);
      RestoreCanvas;

      x := FR.Left; // Source origin should be equal to dest origin,
      y := FR.Top;  // because buffer DC viewport origin is still
                    // offset.
      w := FR.Right - FR.Left;
      h := FR.Bottom - FR.Top;

      if GetObjectType(FCanvas.Handle) = OBJ_DC then
        GDICheck(BitBlt(FCanvas.Handle, x, y, w, h,
                        FBufDC.DC, x, y, SRCCOPY));
    end;

    If error will be eliminated, can you check that all drawings are correct, and there no un-drawed areas on the site or panels?...

    Eugene,
    LMD Innovative.
  • edited June 2015 Posts: 0Vote Up0Vote Down
    I tried this. Unfortunately GetObjectType() returns OBJ_DC even when BitBlt() fails with ERROR_INVALID_HANDLE.

    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().
  • Hi,

    Ok, thanks for debugging. You, probably, right; I've removed GDICheck.

    Eugene,
    LMD Innovative.
Sign In or Register to comment.