[SOLVED] Win32: Problems with aero screen snap

Discussion in 'Mixed Languages' started by Michaela Joy, Jul 24, 2016.

  1. Michaela Joy

    Michaela Joy MDL Crazy Lady

    Jul 26, 2012
    3,557
    3,777
    120
    #1 Michaela Joy, Jul 24, 2016
    Last edited by a moderator: Apr 20, 2017
    Hi All,
    I'm posting this because I -know- that someone will run into this problem when writing code.

    The Problem: How to move a Window (form) around the screen by dragging it by its' client area.

    Seasoned programmers will think they know the solution to this, and typically, they'd suggest handling the WM_NCHITTEST
    message. However, by doing this, you buy into Microsofts aero screen snap bug.

    What I have found that Windows dragged using the WM_NCHITTEST message will clip when dragged off of the top of the screen. I have tested this under Delphi 7, Lazarus (latest version, and TDM-GCC)

    Well...Here's a workaround for anyone who runs into this problem:

    Instead of responding to the WM_NCHITTEST message, use the WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_MOUSEUP messages.

    Here's the code in pascal, but the same thing applies to just about every programming language that supports Windows messages.

    Code:
    unit Unit1;
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
     Windows,LCLType, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
    
    type
    { TForm1 }
      TForm1 = class(TForm)
     procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
     procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
      private
      public
    end;
    
    var
      Form1: TForm1;
    
    implementation
    
    var
      OldCoords: TPoint;
      bMouseDown: Boolean = False;
    
    {$R *.lfm}
    
    { TForm1 }
    
    procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
    Windows.GetCursorPos(OldCoords);
    Windows.ScreenToClient(Self.Handle,OldCoords);
    Windows.SetCapture(Self.Handle);
    bMouseDown := True;
    end;
    
    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    var
      ptMouse,pt: TPoint;
    begin
    inherited;
    GetCursorPos(ptMouse);
    Windows.ScreenToClient(Self.Handle,ptMouse);
    
    //
    // A trick to capture the 'delta' that the mouse moved...
    // This is best done in client coordinates.
    //
    
    if bMouseDown = True then
    begin
         pt.x := (ptMouse.x - OldCoords.x);
         pt.y := (ptMouse.y - OldCoords.y);
    
         Self.Left := Self.Left + pt.x;
         Self.Top := Self.Top + pt.y;
    end;
    end;
    
    
    procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
    bMouseDown := False;
    Windows.ReleaseCapture;
    end;
    end.
    
    
    I hope this saves someone time, grief, and aggravation.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...