2014-03-07 42 views
2

說明如何在Windows會話解鎖後防止表單位置大小更改?

我有其形式在兩臺監視器拉伸一個一個Delphi XE2應用。當我鎖定Windows時,等到屏幕保護程序被激活,然後解鎖窗口時,我的應用程序的所有表單都將調整大小/重新定位以適應每個顯示器(這顯然是默認的Windows行爲並適用於大多數應用程序)。

意向

每當這個鎖定的情況發生時,我要麼想從預先被調整恢復我的形式位置或阻止我的形式。

步驟來重現

這些步驟爲我工作在Windows 7 64位系統。
我設置了1分鐘後激活的屏幕保護程序。我打開我的應用程序和適當的拉伸表單。我lock我的帳戶,並等待屏幕保護程序彈出。登錄後,我可以看到調整大小的窗體。

在其他機器上鎖定足以重現行爲。在一些機器上,激活的屏幕保護程序就足夠了。

附加信息

我做了什麼,到目前爲止觀察:

  • 使用Spy++我看到我的應用程序接收WM_SETTINGCHANGE消息WParam = SPI_SETWORKAREA。此時我的表單已經有了新的大小。
  • 我已註冊會話通知,以對會話鎖定,解鎖,註銷等作出反應。
    鎖定時接收會話更改,我的表單的大小似乎沒問題。當稍後收到WM_SETTINGCHANGE時,表格大小已被更改並縮小爲一個監視器。
  • 試圖在我收到解鎖事件時將表單調整爲原來的大小不成功(表單保持縮小,雖然其屬性已更改)。我使用了表單的位置和大小屬性以及SetWindowPos
  • 受影響窗體的窗口狀態爲wsNormal。我在兩臺顯示器上以編程方式拉伸窗體,但不要觸摸其窗口狀態。
  • 試圖恢復對WM_WTSSession_Change解鎖的消息舊的(內部保存)位置/大小,我曾試圖打電話給
    SetWindowPos(Handle, HWND_NOTOPMOST, FFormSizePos.Left, FFormSizePos.Top, FFormSizePos.Width, FFormSizePos.Height, SWP_NOACTIVATE or SWP_NOMOVE);
    或設置由專人大小的屬性,如Self.Left := FFormSizePos.Left;

任何人可以幫助解決我的意圖?

+1

您可以顯示嘗試還原的代碼。你能告訴我們什麼時候窗口狀態是什麼時候存儲,什麼時候恢復。它最大化了嗎? –

+0

我添加了信息。那裏沒什麼特別的。我試圖找出正確的事件作出響應或適當的時間重置位置,如果這是可能的。最好的辦法是攔截適當的信息,並防止我的表格被重新調整大小。 –

+0

也許這可以幫助http://bobobobo.wordpress.com/2008/02/10/intercepting-the-screensaver/ – Graymatter

回答

1

我找到了一個解決方案,併發布演示代碼(XE2)作爲這個問題的Delphi解決方案。

它是來自delphiDabbleranswer here和解決方案1的組合。

基本上我正在註冊Windows會話狀態更改事件(WM_WTSSESSION_CHANGE)。在提供的示例中(基於裸VCL表單應用程序),我使用WM_EXITSIZEPOS消息來保存當前表單的sizepos。

Windows在位置更改消息被觸發的時刻顯示出不同的行爲。這就是爲什麼我必須修改我的初稿,現在使用兩個變量。我在會議鎖定時阻止位置變化,並在會議解鎖後阻止第一次位置變更。位置更改通過使用WM_WINDOWPOSCHANGING消息截獲。

但是爲了不恢復正常位置,如果窗體是最大化我正在使用FRestoreNormalRect字段。

unit Unit1; 

interface 

uses 
    Winapi.Windows, 
    Winapi.Messages, 
    Vcl.Forms; 

type 
    TForm1 = class(TForm) 
    private 
    FSessionIsLocked: Boolean; 
    FSessionWasUnlocked: Boolean; 
    FRestoreNormalRect: Boolean; 
    FLeft: Integer; 
    FTop: Integer; 
    FWidth: Integer; 
    FHeight: Integer; 

    procedure WMWTSSessionChange(var Msg: TMessage); message WM_WTSSESSION_CHANGE; 

    protected 

    procedure CreateWnd; override; 
    procedure DestroyWnd; override; 

    procedure WMExitSizeMove(var Msg: TMessage); message WM_EXITSIZEMOVE; 
    procedure WMPosChanging(var Msg: TWmWindowPosChanging); message WM_WINDOWPOSCHANGING; 
    procedure WMSize(var Msg: TWMSize); message WM_SIZE; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

//-------------------------------------------------------------------------------------------------- 

procedure TForm1.CreateWnd; 
begin 
    inherited; 

    WTSRegisterSessionNotification(WindowHandle, NOTIFY_FOR_THIS_SESSION); 
end; 

//-------------------------------------------------------------------------------------------------- 

procedure TForm1.DestroyWnd; 
begin 
    WTSUnRegisterSessionNotification(WindowHandle); 

    inherited; 
end; 

//-------------------------------------------------------------------------------------------------- 

procedure TForm1.WMExitSizeMove(var Msg: TMessage); 
var 
    WP: TWindowPlacement; 
    NormalRect: TRect; 

begin 
    WP.Length := SizeOf(TWindowPlacement); 
    GetWindowPlacement(Self.Handle, @WP); 
    NormalRect := WP.rcNormalPosition; 

    FLeft := NormalRect.Left; 
    FTop := NormalRect.Top; 
    FWidth := NormalRect.Right - NormalRect.Left; 
    FHeight := NormalRect.Bottom - NormalRect.Top; 
end; 

//-------------------------------------------------------------------------------------------------- 

procedure TForm1.WMPosChanging(var Msg: TWmWindowPosChanging); 
begin 
    { Sizepos changes might occur due to locks or unlocks. We need do prohibit both. 
    While the session is locked we ignore all position changes. 
    When the session has been unlocked we will ignore the next PosChanging message. } 
    if FSessionIsLocked or FSessionWasUnlocked then 
    begin 
    { overwrite with the old settings } 
    if FRestoreNormalRect then 
    begin 
     Msg.WindowPos.x := FLeft; 
     Msg.WindowPos.y := FTop; 
     Msg.WindowPos.cx := FWidth; 
     Msg.WindowPos.cy := FHeight; 

     Msg.Result := 0; 
    end; 

    { reset the variable, otherwise a manual resize would not be possible } 
    if FSessionWasUnlocked then 
     FSessionWasUnlocked := False; 
    end; 
end; 

//-------------------------------------------------------------------------------------------------- 

procedure TiQForm.WMSize(var Msg: TWMSize); 
begin 
    inherited; 

    { We need to restore our normal rect only if the form is not maximized. Because 
    if it is maximized it only positioned on one monitor and will not be moved 
    by windows. If we do not repsect this case we would be restoring the normal 
    rect unintentionally in WMPosChanging for every maximized form. } 
    FRestoreNormalRect := not (Msg.SizeType = SIZE_MAXIMIZED); 
end; 

//-------------------------------------------------------------------------------------------------- 

procedure TForm1.WMWTSSessionChange(var Msg: TMessage); 
begin 
    case Message.WParam of 
    WTS_CONSOLE_DISCONNECT, WTS_REMOTE_DISCONNECT, WTS_SESSION_LOCK, WTS_SESSION_LOGOFF: 
     begin 
     FSessionIsLocked := True; 
     end; 
    WTS_CONSOLE_CONNECT, WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK, WTS_SESSION_LOGON: 
     begin 
     FSessionIsLocked := False; 
     FSessionWasUnlocked := True; 
     end; 
    end; 

    inherited; 
end; 

//-------------------------------------------------------------------------------------------------- 

end. 
相關問題