gpt4 book ai didi

windows - Windows session 解锁后如何防止窗体位置大小发生变化?

转载 作者:可可西里 更新时间:2023-11-01 14:18:32 27 4
gpt4 key购买 nike

描述

我有一个 Delphi XE2 应用程序,其中一种形式跨越两个显示器。当我锁定 Windows 时,等到屏幕保护程序被激活,然后解锁窗口,我的所有应用程序的窗体都将调整大小/重新定位以适应每个显示器(这显然是默认的 Windows 行为并适用于大多数应用程序)。

意图

每当发生这种锁定情况时,我要么想恢复我的表单位置,要么阻止我的表单事先调整大小。

重现步骤

这些步骤适用于 Windows 7 x64。
我正在设置一个在 1 分钟后激活的黑屏保护程序。我打开我的应用程序和适当的拉伸(stretch)形式。我锁定我的帐户并等待屏幕保护程序弹出。登录后,我可以看到已调整大小的表单。

在其他机器上锁定足以重现该行为。在某些机器上,激活的屏幕保护程序就足够了。

附加信息

到目前为止我所做的和观察到的:

  • 使用 Spy++ 我发现我的应用程序收到了 WM_SETTINGCHANGE 消息,其中 WParam = SPI_SETWORKAREA。此时我的表单已经有了新的大小。
  • 我已注册 session 通知以对 session 锁定、解锁、注销等作出 react 。
    锁定时接收 session 更改,我的表单大小似乎没问题。稍后收到 WM_SETTINGCHANGE 时,表单大小已更改并缩小到一个显示器。
  • 当我收到解锁事件时,尝试将我的表单大小调整到原来的大小没有成功(虽然表单的属性已更改,但表单仍然缩小)。我使用了窗体的位置和大小属性以及 SetWindowPos
  • 受影响窗体的窗口状态是wsNormal。我以编程方式将窗体拉伸(stretch)到两个显示器上方,但不触及它的窗口状态。
  • 尝试在 WM_WTSSession_Change 解锁消息上恢复旧的(内部保存的)位置/大小,我尝试调用
    SetWindowPos(Handle, HWND_NOTOPMOST, FFormSizePos.Left, FFormSizePos.Top, FFormSizePos.Width, FFormSizePos.Height, SWP_NOACTIVATE or SWP_NOMOVE);
    或者手动设置大小属性,如 Self.Left := FFormSizePos.Left;

谁能帮忙解决我的意图?

最佳答案

我找到了解决方案并发布了演示代码 (XE2) 作为此问题的 Delphi 解决方案。

它是 answer here 的组合和解决方案 1 来自 delphiDabbler .

基本上我正在注册 Windows session 状态更改事件 (WM_WTSSESSION_CHANGE)。在提供的示例(基于裸 VCL 表单应用程序)中,我使用 WM_EXITSIZEPOS 消息来保存当前表单 sizepos。

Windows 在触发位置更改消息时表现出不同的行为。这就是为什么我不得不修改我的初稿并且现在使用两个变量。我在 session 锁定时防止位置更改,并在 session 解锁后防止第一次位置更改。使用 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.

关于windows - Windows session 解锁后如何防止窗体位置大小发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22249149/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com