Страница 1 из 1

Завершение работы ПК после копирования

Добавлено: Ср май 13, 2026 12:43
Orion9
Автоматическое выключение ПК после завершения копирования или перемещения файлов. Скрипт написан на языке плагина Autorun.
Установка Autorun
Для работы рекомендуется установить последнюю версию плагина. На данный момент это 2.2.21.3 (15.10.2025)

Инструкция по установке плагина
https://total.darkhost.ru/wiki/doku.php?id=ru:autorun

Особенности последней версии. Для версии 2.2.21.3 нет полного архива с дополнительными модулями (субплагинами) и файлами справки, установку придется проводить в два этапа. Сначала нужно установить версию 2.2.21 от 28.09.2025
https://total.darkhost.ru/files/autorun ... 1_beta.zip
Поверх неё накатить последний модуль от 15.10.2025
https://total.darkhost.ru/files/temp/au ... 251015.zip
Интерфейс для задания параметров отсутствует. Операция активируется нажатимем Ctrl+Alt+O или Alt+Win+O во время копирования или перемещения файлов (далее просто копирования), окно ТС при этом становится прозрачным. По завершении копирования сохраяется возможность отменить действие в течении 25 секунд. Действие также можно отменить в любой момент копирования повторным нажатием Ctrl+Alt+O или Alt+Win+O.

Операция копирования может быть прервана окном диалога (запрос на перезапись, ошибка копирования и т.д.). В этом случае скрипт ждет 300 секунд перед тем, как выключить ПК. Значение можно изменить в переменной wait_seconds. Некоторая дополнительная информация отображается в заголовке окна копирования. В корне ТС сохраняется лог выключения Shutdown.log — должны быть права на запись в эту папку или путь к файлу лога придется изменить.
Shutdown.aucfg

Код: Выделить всё

Pragma IncludeOnce

RegisterCommand 81010 "WinShutdown"

# Ctrl+Alt+O
SetHotkeyAction /K:C /K:A /H:O /DM "RunThread" "CopyMonitor"

# Alt+Win+O
SetHotkeyAction /K:A /K:W /H:O /DM "RunThread" "CopyMonitor"

Global h_WinShutdown
Global g_WinShutdown, g_Shutdown = 0
Global g_LogShutdown = COMMANDER_PATH & "\Shutdown.log"
Global o_WinShutdown = Callback("WinShutdownProc", "hwnd;uint;wparam;lparam")

Func WinShutdownProc(hWnd, uMsg, wParam, lParam)
    Static WM_CLOSE = 0x0010
    If uMsg = WM_CLOSE Then
       If DllCall("DestroyWindow", "handle", hWnd) Then 
          g_Shutdown = 0
       EndIf   
       Return 0
    EndIf
    Return DllCall("CallWindowProcW", "ptr", g_WinShutdown, _
                                      "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func WinShutdown()
    Local hIco
    Local nTimeOut = 25    # время на отмену операции
        
    # окно уже существует
    If h_WinShutdown > 0 Then
       If WinGetState(1, h_WinShutdown) Then
          SendMessage(h_WinShutdown, 0x0010, 0, 0)
          Return
       EndIf   
       h_WinShutdown = 0
    Endif
    
    # дескриптор монитора окна ТС
    Local hMon = DllCall("MonitorFromWindow", "hwnd", AUTORUN_TCHANDLE, "dword", 2)
    
    # информация о масштабировании экрана
    Local nMonScale = 0, nTextScale
    DllCall("Shcore.dll\GetScaleFactorForMonitor", "hwnd", hMon, "dword*", @nMonScale)
    If nMonScale < 100 Then nMonScale = 100
    
    # информация о размере текста
    RegRead nTextScale "HKCU\Software\Microsoft\Accessibility" "TextScaleFactor" 100
    nTextScale = Round(nTextScale/100,2)
    Local nWidth = Round(3*nMonScale*nTextScale,0)
    
    # создание окна прогресс-бара
    h_WinShutdown = DllCall("CreateWindowExW", _
                            "dword", 0, _
                            "wstr", "msctls_progress32", _
                            "wstr", "", _
                            "dword", 0x00C80000, _
                            "int", 200, "int", 100, "int", Round(Scale(300)*nTextScale,0), "int", Scale(50), _
                            "handle", , _
                            "handle", 0, "handle", 0, "ptr", 0, _
                            "handle")
    # не удалось создать окно                            
    If h_WinShutdown = 0 Then Return 0
    
    # поверх всех окон
    WinSetState(30, h_WinShutdown)
    
    # WinAlign(h_WinShutdown, 0, DllCall("GetDesktopWindow"), 0, 100, -100)    
    # выравнивание по центру рабочего стола    
    WinAlign(h_WinShutdown, 0, DllCall("GetDesktopWindow"))
    
    # перемещение окна вверх на 50 пикселей    
    WinSetPos("", -Scale(50), "", "", 1, h_WinShutdown)
    
    # перемещение окна вправо на 50 пикселей
    # WinSetPos(Scale(50), "", "", "", 1, h_WinShutdown)
    
    # отображение окна    
    WinSetState(5, h_WinShutdown)

    # установка оконной процедуры
    g_WinShutdown = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                            "hwnd", h_WinShutdown, _
                            "int", -4, _
                            "long_ptr", o_WinShutdown.Ptr, "ptr")
                            
    Static PBM_SETPOS      =  1026, _
           PBM_SETRANGE    =  1025, _
           PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80

    # установка иконки ТС
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(h_WinShutdown, WM_SETICON, 0, hIco)       
                   
    g_Shutdown = 1
    
    # стиль и позиция прогресс-бара
    WinSetStyle(PBS_MARQUEE, 4, h_WinShutdown) 
    SendMessage(h_WinShutdown, PBM_SETPOS, 0, 0)
    
    # время на отмену
    For i = 1 to nTimeOut
        SendMessage(h_WinShutdown, PBM_SETPOS, Round(i/nTimeOut*100,0), 0) 
        WinSetText("Выключение через " & nTimeOut-i & " сек.", h_WinShutdown)
        Sleep(900)
        If g_Shutdown = 0 Then Break
    Next 
       
    If g_Shutdown = 0 Then    
       FileAppend(g_LogShutdown, StrFormat("%s %s Выключение отменено", Date(), Time()))     
       MsgBox("Выключение ПК отменено", "", 48)
    Else       
       If DllCall("DestroyWindow", "handle", h_WinShutdown) Then h_WinShutdown = 0
       FileAppend(g_LogShutdown, StrFormat("%s %s Выключение ПК...", Date(), Time()))            
       # MsgBox("Выключение ПК", "Тест", 64)
       ShellExec("shutdown", "/s /t 0 /f")    # /f принудительное закрытие приложений
    EndIf   
EndFunc

Global g_CopyMonitor = false, g_CopyWndOwner = false, g_DialogWnd = ""

Func CopyMonitor()
    Local bWmi = true            # показывать байты в заголовке
    Local bTransCopyWin = true   # прозрачность окна копирования
    Local wait_seconds = 300     # время ожидания при появлении окна диалога 
    
    Static hCopyWnd = 0
    
    # монитор уже запущен - остановить
    If g_CopyMonitor Then 
       g_CopyMonitor = false
       Return
    EndIf
    
    # поиск окна копирования
    hCopyWnd = WinFind(0, "TDLG2FILEACTIONMIN")
    If hCopyWnd = 0 Then
       ShowHint("Копирование не запущено", 0, 0, 1000, 1)
       WinAlign(LAST_HINT_WINDOW)
       Return
    EndIf
    
    # текущее состояние монитора    
    g_CopyMonitor = true
    
    # установка прозрачности окна ТС
    WinSetStyle(0x80000, 3)
    DllCall("SetLayeredWindowAttributes", "hwnd", AUTORUN_TCHANDLE, _ 
                                          "ptr", 0, "byte", 192, "dword", 2)
                                          
    # опциональная прозрачность окна копирования                                       
    If bTransCopyWin Then                                      
       WinSetStyle(0x80000, 3, hCopyWnd)
       DllCall("SetLayeredWindowAttributes", "hwnd", hCopyWnd, _ 
                                             "ptr", 0, "byte", 192, "dword", 2)
    EndIf
    
    # поиск и блокировка кнопки "В фоне"
    Local b = WinFind(hCopyWnd, _
                     (AUTORUN_TCARCH = 32 ? "TButton" : "Button"), (AUTORUN_TCARCH = 32 ? 2 : 1))
    WinSetState(21, b)
    
    # параметры подсказки                                      
    SetHintParam("ShowHint", "Font", 15, "Arial")
    SetHintParam("ShowHint", "BackColor", 0xFF0000)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    
    ShowHint("Монитор выключения запущен, ожидание завершения копирования", 0, 0, 1000, 1)
    
    # сброс параметров подсказки                                          
    SetHintParam("ShowHint", "Reload")
    
    # центрирование подсказки
    WinAlign(LAST_HINT_WINDOW)
    Local wmi, wmq, txt = WinGetText(hCopyWnd)
    
    # wmi запрос к процессу ТС
    wmq = "SELECT IOWriteBytesPersec FROM Win32_PerfRawData_PerfProc_Process WHERE IDProcess=" & AUTORUN_TCPID
    
    # функция обратного вызова 
    Local ewp = Callback("IsCopyWndOwner", "hwnd;lparam")
    
    Local hang = 0    
    # цикл ожидания периодический поиск окна копирования
    While hCopyWnd <> 0
        g_CopyWndOwner = false
        # проверить статус владельца окна копирования
        DllCall("EnumWindows", "ptr", ewp.Ptr, "lparam", hCopyWnd)        
        # записано байт процессом опционально
        If bWmi Then wmi = SizeFormat(GetWMIValue("IOWriteBytesPersec", wmq), 1, "G", 2)
        WinSetText("Shutdown " & (Not g_CopyWndOwner ? "mode" : "paused for " & hang & " сек.") _
                               & (Not bWmi ? "" : ": " & wmi), hCopyWnd)
        hang = (g_CopyWndOwner ? hang + 1 : 0)
        If hang > wait_seconds Then Break   
        For i = 1 To 10
            If Not g_CopyMonitor Then Break
            Sleep(100)
        Next        
        If Not g_CopyMonitor Then Break
        hCopyWnd = WinFind(0, "TDLG2FILEACTIONMIN")
    Wend
    
    Free(ewp)
    WinSetText(txt, hCopyWnd)
    
    # разблокирование кнопки "В фоне"    
    WinSetState(20, b)
    
    # цикл не был прерван повторным нажатием Ctrl+Alt+O
    If g_CopyMonitor Then
       g_CopyMonitor = false
       ShutdownLog(hang)
       WinShutdown()
    Else
       SetHintParam("ShowHint", "Font", 15, "Arial")
       SetHintParam("ShowHint", "BackColor", 0xFF0000)
       SetHintParam("ShowHint", "Text", 0xFFFFFF)    
       ShowHint("Монитор выключения остановлен", 0, 0, 1000, 1)
       SetHintParam("ShowHint", "Reload") 
       WinAlign(LAST_HINT_WINDOW)
    EndIf
    
    # отключение прозрачности 
    WinSetStyle(0x80000, 5)
    If bTransCopyWin Then WinSetStyle(0x80000, 5, hCopyWnd)        
EndFunc 

Func IsCopyWndOwner(wnd, lparam)
    If Not WinGetState(2, wnd) Then Return 1
    Local h = DllCall("GetWindow", "hwnd", wnd, "uint", 4, "hwnd")
    If h = lparam Then
       g_CopyWndOwner = true
       g_DialogWnd = WinGetClass(wnd) & " - " & WinGetText(wnd)
       Return 0
    EndIf
    Return 1
EndFunc

Func ShutdownLog(CopyHang)
    Local sLog
    Local status = "копирование " & (CopyHang = 0 ? "завершено" :"прервано")
    sLog &= auCRLF & auCRLF
    sLog &= StrFormat("%s %s Окно выключения ПК\r\n", Date(), Time())
    sLog &= StrFormat("%s %s Статус: %s\r\n", Date(), Time(), status)
    If CopyHang > 0 Then sLog &= StrFormat("%s %s Диалог: %s\r\n", Date(), Time(), g_DialogWnd)
    FileAppend(g_LogShutdown, sLog) 
EndFunc

Func GetDPI()
    Local DC = DllCall("GetDC", "int", 0)
    Local lpy = DllCall("GetDeviceCaps", "handle", DC, "int", 88) # LOGPIXELSX
    DllCall("ReleaseDC", "int", 0, "handle", DC)
    Return lpy
EndFunc

Func Scale(nValue)
    Static dpi = GetDPI()
    Return DllCall("MulDiv", "int", nValue, "int", dpi, "int", 96)
EndFunc
Модуль подключается к autorun.cfg стандартно

Код: Выделить всё

Pragma Include %COMMANDER_PATH%\Ini\Autorun\Shutdown.aucfg
Пример файла конфигурации чистого плагина
autorun.cfg

Код: Выделить всё

Pragma AutorunBlockUnload

LoadLibrary Plugins\Autorun_Tweaks.dll
LoadLibrary Plugins\Autorun_Sysinfo.dll
LoadLibrary Plugins\Autorun_Runtime.dll
LoadLibrary Plugins\Autorun_Process.dll

Pragma Include %COMMANDER_PATH%\wdx\Autorun\Shutdown.aucfg

Pragma AutorunFinalizeSection