Задача
Необходимо иметь возможность завершить сеанс другого пользователя заблокировавшего экран, чтобы войти под своим, при условии что:
— экран блокируется автоматически по истечении некоторого времени
— вы не администратор системы
— нет возможности использовать «быстрое переключение пользователей»
— нельзя использовать автоматическое завершение сеанса по времени
А так же желательно:
— избежать появления чёрного консольного окошка в реализации
Решение
Не буду утомлять вас рассказами о том какие решения были испробованы и сколько костылей пришлось поломать, но решение таки было найдено. В решении таких задач лучше всего обходиться скриптами, но не всегда это удаётся, как и не удалось на этот раз. Дело в том, что для решения обозначенной задачи необходимо было запускать скрипт как заставку, но скрипт на заставку поставить нельзя. Для решения этой проблемы воспользуемся небольшим кодом на C, который, в свою очередь, запускает скрипт на vbs.
winexec.cpp
#include "stdio.h" #include "shlwapi.h" void RemoveNewLine (char* str) { char* pos = strrchr(str,'\n'); if (pos) *pos = '\0'; } int main(int argc, char *argv[]) { // Get command line argument if (argc < 2) return 0; if (stricmp(argv[1],"/s")) return 0; // Init vars char config_file[MAX_PATH] = ""; char command[MAX_PATH] = ""; char args[MAX_PATH] = ""; // Get own path and set config_file GetModuleFileName (NULL,config_file,MAX_PATH); PathRemoveExtension (config_file); strcat (config_file,".cfg"); // Read config file FILE* file = fopen (config_file,"r") ; if (file == NULL) { MessageBox (NULL,"Error opening config file",NULL,0); return 1; } fgets (command,MAX_PATH,file); RemoveNewLine (command); fgets (args,MAX_PATH,file); RemoveNewLine (args); // Run process PROCESS_INFORMATION processInformation; STARTUPINFO startupInfo; memset ( &processInformation,0,sizeof (processInformation) ); memset ( &startupInfo,0,sizeof (startupInfo) ); if ( !CreateProcess (command,args,NULL,NULL,0,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInformation) ) { MessageBox (NULL,"ERROR: Create Process failed!",NULL,0); return 1; } // Wait until child process exits. WaitForSingleObject (processInformation.hProcess,INFINITE); // Close process and thread handles. CloseHandle (processInformation.hProcess); CloseHandle (processInformation.hThread); }
winexec.cfg
c:\windows\system32\cscript.exe
cscript.exe c:\windows\winexec.vbs
winexec.vbs
'Create common objects Set WshShell = CreateObject("WScript.Shell") Set WshNetwork = CreateObject("WScript.NetWork") 'Set common variables username = WshNetwork.UserName title = "Завершение сеанса пользователя" & " " & username text = "Желаете выйти из системы?" 'Run logout dialog Button = WshShell.Popup(text,,title,36) 'Check answer If Button <> 6 Then Wscript.Quit 'Force logoff if "Yes" WshShell.Run "shutdown.exe -l",,true
Как это использовать
— Собираем код C в запускаемый файл winexec.scr используя mingw
Ubuntu:
i586-mingw32msvc-gcc -mwindows -s winexec.cpp -o winexec.scr -lshlwapi
Archlinux: i486-mingw32-gcc -mwindows -s winexec.cpp -o winexec.scr -lshlwapi
— Помещаем winexec.scr, winexec.cfg и winexec.vbs в директорию %WINDIR%
— Настраиваем заставку (используя групповые политики — gpedit.msc — можно настроить заставку для всех пользователей системы единым образом)
Как это работает
— По таймауту блокируется экран и запускается winexec.scr, который считывает winexec.cfg (winexec.cfg содержит параметры запуска vbs скрипта)
— Следом запускается vbs-скрипт с вопросом «завершить сеанс?». Нажатие кнопки «Нет» приведёт к появлению окна блокировки, в котором можно ввести пароль. Нажадие «Да» завершит сеанс и позволит войти под другим пользователем.
— Несмотря на то, что из vbs-скрипта запускается консольная команда shutdown, чёрного окна cmd не появляется (это достигается параметром CREATE_NO_WINDOW при создании процесса в коде C)
Комментарии
— winexec.scr можно использовать не только для запуска logout-скрипта, но и для любой другой программы (или скрипта), которую вы хотите запускать вместо экранной заставки