Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
09-06-2009 13:57
Если создать новый десктоп, то никуда юзер с него не переключится. Можете попробовать:
procedure TForm1.FormDestroy(Sender: TObject);
begin
CloseDesk(OldD);
CloseDesk(NewD);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
OldD := OpenDesk(cOldDesktopName);
NewD := OpenDesk(cNewDesktopName);
if NewD = 0 then
NewD := CreateDesk(cNewDesktopName);
CurrentD := GetDeskName(GetCurrentDesk);
if CurrentD = cOldDesktopName then
bSwitchToOldD.Enabled := False
else
bSwitchToNewD.Enabled := False;
end;
procedure TForm1.bSwitchToOldDClick(Sender: TObject);
begin
SetLastError(0);
if SwitchDesk(OldD) then
Close
else
Label4.Caption := 'Cannt switch to ' + IntToStr(OldD) + #13#10 +
SysErrorMessage(GetLastError);
end;
procedure TForm1.bSwitchToNewDClick(Sender: TObject);
begin
StartOnDesk(paramstr(0), '', cNewDesktopName);
SwitchDesk(NewD);
end;
И юнит обертка над системными функциями:
unit DesktopUtils;
interface
uses
Windows, SysUtils;
function CreateDesk(Name: string): HDESK;
function OpenDesk(Name: string): HDESK;
function SwitchDesk(Desk: HDESK): Boolean;
function CloseDesk(Desk: HDESK): Boolean;
function GetCurrentDesk: HDESK;
function GetDeskName(Desk: HDESK): string;
function StartOnDesk(ApplicationName, CommandLine, DeskName: string): Boolean;
implementation
function CreateDesk(Name: string): HDESK;
var
sa:_SECURITY_ATTRIBUTES;
begin
FillChar(sa, SizeOf(sa), 0);
sa.nLength:= sizeof(sa);
sa.lpSecurityDescriptor:= Nil;
sa.bInheritHandle:= True;
Result := CreateDesktop(PChar(Name), Nil, Nil, 0, GENERIC_ALL, @sa);
end;
function OpenDesk(Name: string): HDESK;
begin
Result := OpenDesktop(PChar(Name), 0, True, GENERIC_ALL);
end;
function SwitchDesk(Desk: HDESK): Boolean;
begin
Result := SwitchDesktop(Desk);
end;
function CloseDesk(Desk: HDESK): Boolean;
begin
Result := CloseDesktop(Desk);
end;
function GetCurrentDesk: HDESK;
var
thr: Integer;
begin
thr := GetCurrentThreadId;
Result := GetThreadDesktop(thr);
end;
function GetDeskName(Desk: HDESK): string;
var
buf: PChar;
needed: Cardinal;
begin
buf := AllocMem(1024);
if not GetUserObjectInformation(Desk, UOI_NAME, buf, 1024, needed) then
begin
FreeMem(buf);
buf := AllocMem(needed);
GetUserObjectInformation(Desk, UOI_NAME, buf, needed, needed);
end;
Result := buf;
FreeMem(buf);
end;
function StartOnDesk(ApplicationName, CommandLine, DeskName: string): Boolean;
var
sa:_SECURITY_ATTRIBUTES;
sti:STARTUPINFO;
pri:_PROCESS_INFORMATION;
begin
FillChar(sa, SizeOf(sa), 0);
sa.nLength:= sizeof(sa);
sa.bInheritHandle:= true;
Смысл в том, что как только поток создает первое окно, он намертво приклеивается к текущему десктопу. А поскольку VCL штука однопоточная, то на втором десктопе приходится запускать вторую копию своего приложения. Остальное думаю несложно найти в справке.
Блин, все же не все работает. Если форма показывает другую форму (модально) или выводить сообщение (например ShowMessage), то можно легко переключиться на любое другое приложение.
:(
Увы, но если уровень владения компьютером пользователя выше уровня администратора, то защита по определению ненадежна.
Нет цели создать абсолютно надежную монопольную программу... Как оказывается много пользователей (учителей) используя эту функцию тестирую учеников (не профи и не админов) могут упростить себе жизнь.
Т.е. тут частный случай - пользователи и одни и другие не профи и не админы.
>>> Увы, но это реалии многих средних учебных заведений
Увы, но если уровень владения компьютером пользователя выше уровня администратора, то защита по определению ненадежна. Какую бы замечательную программы Вы ни написали. Абсолютно надежным будет только вариант написания собственной ОС, заточенной под Вашу конкретную задачу. Все остальное можно будет обойти, если не предусмотреть защиты на уровне ОС.
2 Geo
Многие пользователи на такое не способны (и человека который бы это сделал нет). Поставить птичку "монопольный режим" при проверке еще смогут, а выполнить какие-либо администраторские функции нет. Увы, но это реалии многих средних учебных заведений.
В упор не пойму, зачем пытаться подменять в своей программе административные механизмы, которые уже реализованы в Windows. Причем гарантированно получится хуже и менее надежно.
Пусть администратор заведет дополнительного пользователя, которому будет запрещено все, кроме запуска Вашей программы. И нет никаких проблем. И не надо думать как заткнуть вмсе дыры, потому что проверяемый гарантированно не сможет ничего больше запустить, даже если свернет Вашу программу.
Зачем все эти фокусы? Если нужно запретить доступ к рабочему столу, то достаточно написать свой шелл и подменить им стандартный. Тогда при запуске винды в качестве рабочего стола будет ваша программа.
Программа должна включать монопольный режим при необходимости (во время работы) и выключать его, а не всегда.
Прекратите писать вирусы!!!
Это смотря для чего вам это нужно.
Программа для обучения и контроля знаний.
Другие уже готовые, где это реализовано не предлагать.
Многие пользователи программы хотят иметь такую возможность, например чтобы для перевода чисел из одной системы счисления в другую без калькулятора или чтобы не открыли excel и не проверяли какая формула будет ... и т.д. (много было пожеланий).
type
TForm1 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure WMShowWindow(var Msg: TWMShowWindow); message WM_ShowWindow;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//Этот обработчик и избавит тебя от WIN+D
procedure TForm1.WMShowWindow(var Msg: TWMShowWindow);
begin
if not Msg.Show then
Msg.Result := 0
else
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
HTaskbar: HWND;
OldVal: LongInt;
begin
try
HTaskBar := FindWindow('Shell_TrayWnd', nil);
SystemParametersInfo(97, Word(True), @OldVal, 0);
EnableWindow(HTaskBar, False);
ShowWindow(HTaskbar, SW_HIDE);
finally
with Form1 do
begin
BorderStyle := bsNone;
FormStyle := fsStayOnTop;
Left := 0;
Top := 0;
Height := Screen.Height;
Width := Screen.Width;
end;
end
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
HTaskbar: HWND;
OldVal: LongInt;
begin
HTaskBar := FindWindow('Shell_TrayWnd', nil);
SystemParametersInfo(97, Word(False), @OldVal, 0);
EnableWindow(HTaskBar, True);
ShowWindow(HTaskbar, SW_SHOW);
end;
+ таймер проверки состояния...
Зачем все эти фокусы? Если нужно запретить доступ к рабочему столу, то достаточно написать свой шелл и подменить им стандартный. Тогда при запуске винды в качестве рабочего стола будет ваша программа.
>>> От ярлыка "Показать рабочий стол" ничто не спасет
Это который "Свернуть все окна"? Вот тут про это ещё много было: »вопрос КС №42112«
А вообще верное замечание: не дело это.
P.S. To fox: а не достаточно из BorderIcons всё убрать?
В ObjectInspector ставим WindowState:= wsMaximized;
TfmMain = class(TForm)
...
private
{ Private declarations }
protected
procedure WMSysCommand(var Message:TWMSysCommand);message WM_SYSCOMMAND;
public
{ Public declarations }
end;
procedure TfmMain.WMSysCommand(var Message:TWMSysCommand);
begin
if ((Message.CmdType and $FFF0) = SC_RESTORE) or
((Message.CmdType and $FFF0) = SC_MOVE) or
((Message.CmdType and $FFF0) = SC_MINIMIZE) then Message.Msg:=0
else inherited;
end;
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.