Eri*_*tel 5 windows delphi multiple-monitors
描述
我有一个 Delphi XE2 应用程序,其窗体之一横跨两个显示器。当我锁定 Windows 时,等到屏幕保护程序被激活然后解锁窗口,我的应用程序的所有窗体都将调整大小/重新定位以适合每个显示器(这显然是默认的 Windows 行为并适用于大多数应用程序)。
意图
每当发生这种锁定情况时,我要么想要恢复表单位置,要么阻止预先调整表单大小。
重现步骤
这些步骤适用于 Windows 7 x64。
我正在设置 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;
有人可以帮助解决我的意图吗?
我找到了一个解决方案,并发布了演示代码(XE2)作为该问题的 Delphi 解决方案。
它是此处答案和delphiDabbler解决方案 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.
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2181 次 |
最近记录: |