如何创建一个系统模态窗口?

3

是否可以将应用程序的主窗体设置为系统模态?我的应用程序将从远程公司PC上FTP文件。在此过程进行时,用户不应被允许与桌面交互。

Application.MainFormOnTaskbar := True;
Application.ShowMainForm := False;
...
FormChild.ShowModal;

10
拥有模态表单意味着您将无法与其后面的表单进行交互。由于主表单后面没有表单,因此我看不出有什么意义。 - Sertac Akyuz
你是否考虑在远程电脑旁安装牛棒? - David Heffernan
2
你不需要模态,你需要“展示模式”。在这种情况下,你应该考虑使用KASSL的dWinLock。 - Warren P
@Warren 当然,如果他使用dWinLock,他也必须禁止64位的Windows! - David Heffernan
1
Pieter,你现在已经意识到,即使你可以拥有一个简单的模态窗口——即使通过隐藏主窗体并创建另一个模态窗口——你也无法实现你想要做的事情。Andreas 正确地提到了“系统模态”的概念,这是你需要的,如果你想防止访问其他程序。即使是普通的模态子窗口也只会对你的应用程序具有模态性(这是没有意义的,因为不会有任何其他窗口来阻止访问)。我编辑了你的问题,让它询问你真正想要的东西。 - Rob Kennedy
显示剩余7条评论
4个回答

12

将主窗体设为模态窗口是没有意义的。实际上,如果你有一个普通应用程序,其中包含一个(正常的)主窗体,然后显示一个模态窗体(例如对话框或TOpenDialog),那么“模态性”意味着主窗体和其余您的应用程序在模态窗体关闭之前都会被“禁用”。 (但其他应用程序不受影响)。但是这对于主窗体来说是没有意义的,因为当主窗体被显示时,没有“剩余”的应用程序需要禁用。事实上,如果您不打开任何其他窗体,则正常的主窗体在某种程度上已经是模态窗口了。

我认为您希望创建一个系统模态窗体,即显示时会禁用整个桌面其余部分的窗体。但这并不容易实现,因为现代版本的Microsoft Windows操作系统遵循安全原则,通常情况下,单个应用程序不能够控制整个操作系统。


从示例代码来看,似乎OP想要在应用程序级别上进行模态操作,关于这一点你已经表达得很清楚了。 - Andriy M
我们想从远程计算机检索文件,即部署一个在特定时间启动并通过FTP将文件或文件传回主机的可执行文件。在此过程中,我不希望用户与桌面交互。因此,我需要主窗体是模态的。谢谢。 - Pieter van Wyk
对于这个任务,我会创建一个无边框的最大化窗体,并从桌面的其余部分截取灰色屏幕截图,在该窗体的中心放置一些进度条或其他你想要激活的内容。但是请非常小心地考虑,以防止用户在其他应用程序之间切换。而且我要说,CTRL + ALT + DEL 总是可用的。 - user532231
1
是的,我将按CTRL + ALT + DELETE键,选择任务管理器,点击文件|运行,然后运行 pskill IrritatingPseudoKioskApp。实际上,我会在它开始尝试任何这些无聊操作之前杀死该应用程序! - David Heffernan
但你仍然可以从键盘上弹出键来 :) - user532231
甚至更好的方法是使用您自己的键盘,通过USB / COM直接以您自己的方式与应用程序通信。 - user532231

2
使用CreateDesktop()创建自己的桌面(并创建一个状态窗口在其上显示),然后使用OpenDesktop()检索用户的桌面,在文件传输开始和结束时使用SwitchDesktop()之间切换。当您的自定义桌面处于活动状态时,用户无法访问他/她的桌面(例如屏幕保护程序正是这样做的)。

1
如其他答案所提及,你想要做的是很难理解的,因为模态窗体的目的是禁用下方的所有应用程序窗体,因此应用程序窗体本身可能被认为是一个模态窗体。
虽然如果您希望使您的应用程序成为当前窗口桌面上唯一接收焦点的接收者(可能是非管理员用户桌面),您需要:
  1. 通过使您的表单全屏来隐藏任务栏
  2. 锁定尽可能多的窗口键,考虑到您的应用程序的易用性(Ctrl、Alt、F1-F12、Windows、菜单)
有了新版本的Windows,作为非特权用户,除了使用全局窗口钩子的Ctrl+Alt+Del组合外,您可以执行所有这些操作。
uses
  Windows;

var
  hKeybaordHook: HHOOK = 0;

function KeyboardHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): HRESULT; stdcall;
type
  PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
  TKBDLLHOOKSTRUCT = packed record
    vkCode: DWORD;
    scanCode: DWORD;
    flags: DWORD;
    time: DWORD;
    dwExtraInfo: DWORD;
  end;
const
  LLKHF_ALTDOWN = $20;
var
  pkbhs: PKBDLLHOOKSTRUCT;
begin
  pkbhs := PKBDLLHOOKSTRUCT(lParam);
  if nCode = HC_ACTION then
  begin
    Result := 1;
// CTRL
    if WordBool(GetAsyncKeyState(VK_CONTROL) and $8000) then Exit
// ALT
    else if LongBool(pkbhs^.flags and LLKHF_ALTDOWN) then Exit
// WIN KEYS
    else if (pkbhs^.vkCode = VK_LWIN) or (pkbhs^.vkCode = VK_RWIN) then Exit
// FUNCTION KEYS
    else if bDisableFunctionKeys and (pkbhs^.vkCode >= VK_F1) and (pkbhs^.vkCode <= VK_F24) then Exit;
{
// Disabling specific combinations
// CTRL+ESC
    else if (pkbhs^.vkCode = VK_ESCAPE) and WordBool(GetAsyncKeyState(VK_CONTROL) and $8000) then Exit
// ALT+TAB
    else if (pkbhs^.vkCode = VK_TAB) and LongBool(pkbhs^.flags and LLKHF_ALTDOWN) then Exit
// ALT+ESC
    else if (pkbhs^.vkCode = VK_ESCAPE) and LongBool(pkbhs^.flags and LLKHF_ALTDOWN) then Exit
}
  end;
  Result := CallNextHookEx(hKeybaordHook, nCode, wParam, lParam);
end;

procedure MainForm.FormShow(Sender: TObject);
const
  WH_KEYBOARD_LL = 13;
begin
  SetBounds(0, 0, Screen.Width, Screen.Height);

  if hKeybaordHook = 0 then
    hKeybaordHook := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardHook, HInstance, 0);
end;

procedure MainForm.FormHide(Sender: TObject);
begin
  if (hKeybaordHook <> 0) and UnhookWindowsHookEx(hKeybaordHook) then
    hKeybaordHook := 0;
end;

您还可以将“SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe”注册表键值设置为一些虚拟文本,以禁用任务管理器(包括Ctrl+Shift+Esc组合键)。

2
这种软件被称为恶意软件。 - David Heffernan
但是使用这种操作方式的真正应用程序被称为自助应用程序。看看最近的ATM或信息亭。 - too
我的自动取款机不运行Windows。一个真正的信息亭不会以Explorer作为其外壳运行。 - David Heffernan
我同意 Shell 不应该在任何 Kiosk 上运行,但是应用程序的 Kiosk 模式也不应永久禁用 Windows Shell。 - too
你不能仅仅从桌面模式切换到展示器模式。 - David Heffernan
显示剩余2条评论

-1

如果你想接管用户的桌面并防止他们使用计算机,你可以使用dWinLock


无论如何,直到我们得到一个64位的Delphi。 :-) - Warren P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接