Как проверить в C++, активна ли система?

Я пишу код, который нужно запускать только тогда, когда на ПК нет человеческой деятельности, например, когда работает заставка. Любые предложения о том, как сделать это в C++ под Windows?

@talnicolas, просто чтобы использовать неиспользованные ресурсы, сколько раз люди оставляют компьютер включенным, но они находятся в другом месте?

6 ответов

Ты можешь использовать GetLastInputInfo проверить, как долго пользователь простаивал (не двигался вокруг мыши и не набирал что-то на клавиатуре) и SystemParametersInfo проверить, активна ли заставка.

пример

#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>

// do something after 10 minutes of user inactivity
static const unsigned int idle_milliseconds = 60*10*1000;
// wait at least an hour between two runs
static const unsigned int interval = 60*60*1000;

int main() {
    LASTINPUTINFO last_input;
    BOOL screensaver_active;

    // main loop to check if user has been idle long enough
    for (;;) {
        if ( !GetLastInputInfo(&last_input)
          || !SystemParametersInfo(SPI_GETSCREENSAVERACTIVE, 0,  
                                   &screensaver_active, 0))
        {
            std::cerr << "WinAPI failed!" << std::endl;
            return ERROR_FAILURE;
        }

        if (last_input.dwTime < idle_milliseconds && !screensaver_active) {
            // user hasn't been idle for long enough
            // AND no screensaver is running
            Sleep(1000);
            continue;
        }

        // user has been idle at least 10 minutes
        do_something();
        // done. Wait before doing the next loop.
        Sleep(interval);
    }
}

Обратите внимание, что я написал этот код на компьютере с Linux, поэтому я не смог его протестировать.

Это лишь незначительное обновление для ответа Niklas B. Ответ, протестированный в Windows 8.1 и Windows 10.

Описание изменений выглядит следующим образом:

  • LASTINPUTINFO имеет cbSize инициализируется

  • вместо проверки SPI_GETSCREENSAVERACTIVE, SPI_GETSCREENSAVERRUNNING проверено

  • idle_time рассчитывается и сравнивается с idle_milliseconds

  • пользователь уведомляется только об изменении, проверка выполняется каждые ~500 мс

  • Поскольку Windows может инициировать событие с идентификатором 4803 сразу после 4802, можно определить, что заставка все еще включена у пользователя idle_timeпосмотри проблему у меня была

Кроме того, это работает, только если таймер заставки меньше таймера выключения экрана!

#define start

#include <windows.h>
#include <iostream>

// do something after 10 minutes of user inactivity
static const unsigned int idle_milliseconds = 60*10*1000;

int main() {
    LASTINPUTINFO last_input;
    // without setting cbSize GetLastError() returns the parameter is incorrect
    last_input.cbSize = sizeof(last_input);  
    BOOL screensaver_running;

    DWORD idle_time;
    bool screensaverOn = false;

    // main loop to check if user has been idle long enough
    for (;;) {
        if ( !GetLastInputInfo( &last_input )
          || !SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,  
                               &screensaver_running, 0 ) )
        {
            std::cerr << "WinAPI failed!" << std::endl;
            return ERROR_FAILURE;
        }

        // calculate idle time
        idle_time = GetTickCount() - last_input.dwTime;

        if ( idle_time > this->user_idle_time && TRUE == screensaver_running )
        {
            if ( !screensaverOn )
            {
                // screensaver is running
                screensaverOn = true;
                notify( true );
            }
        }
        else if ( idle_time < this->user_idle_time && screensaverOn )
        {
            // screensaver is not running
            screensaverOn = false;
            notify( false );
        }
        // wait 500ms before next loop
        Sleep( 500 );
    }
}

Использовать SystemParametersInfo(...)

   private const int SPI_GETSCREENSAVERACTIVE = 16;
   SystemParametersInfo( SPI_GETSCREENSAVERACTIVE, 0, 
         ref isActive, 0 );
      return isActive;

Ссылка: http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx

Может у кого-то тут путаница с plii.dwTime

plii.dwTime дает временную метку даты последнего ввода, он не дает время между текущим и последним вводом

для этого вы должны добавить его к GetTickCount() :

      LASTINPUTINFO plii;
plii.cbSize = sizeof(LASTINPUTINFO);
plii.dwTime = 0;

if (GetLastInputInfo(&plii) != 0)
{
    cout << "Last activity  : " <<  GetTickCount() - plii.dwTime << " (ms)" << endl;
}
else {
    cout << "GetLastInputInfo ERROR" << endl;
}

Неспособность обнаруживать вводимые пользователем данные в сервисе обусловлена ​​дизайном.

Это означает, что у службы, помимо прочего, нет прямого способа узнать, когда произошел последний ввод пользователя, и это причина, по которой GetLastInputInfo не возвращает ничего полезного при вызове из службы.

По-видимому, идея заключалась в том, чтобы усложнить жизнь бешеным хакерам, пытающимся написать регистраторы ключей и другие неприятные фрагменты кода. Конечно, вы можете легко обойти это ограничение, если пользовательский процесс будет передавать эту информацию в вашу службу.
Я не думаю, что этот тривиальный обходной путь недоступен среднему бешеному хакеру, я скорее представляю себе парней, которые наслаждаются такими довольно бессмысленными упражнениями по свертке кода.

Если ваш сервис выполняет запрошенные пользователем вычисления, вам, скорее всего, в любом случае потребуется пользовательский процесс для взаимодействия с ним. Но если вы хотите опросить любую индикацию активности пользователя, вам придется оставить этот пользовательский процесс запущенным. Демон-пользователь сохранил жизнь, чтобы скормить вашему настоящему демону незначительную часть информации. Поговорим об эффективном использовании ресурсов...

Кстати, мониторинг активации экранной заставки довольно ненадежен. Экран можно настроить на отключение до появления заставки. Компьютер также может перейти в спящий режим до того, как ваш код запустится. Так что будьте внимательнее при проверке условий.

Кроме того, вы можете посмотреть счетчики производительности.
Они могут предоставить вам массу информации о загрузке процессора, использовании диска и т. Д.
Вы можете относительно легко определить период низкой активности процессора и / или диска, отслеживая их.

Интерфейс - ужасный беспорядок, и, очевидно, есть еще другие препятствия для безопасности, которые нужно преодолеть. Я не совсем уверен, какие учетные записи служб - если таковые имеются - могут получить к ним доступ или могут ли они это делать по умолчанию при типичной установке Windows.

Вы также можете активировать свой код, когда никто не вошел в систему. Очевидно, нет очевидного способа обнаружить это, но это выполнимо изнутри службы.

Проверьте этот ответ, который выглядит аналогично.

Однако нужно точно определить, было ли "неактивное" средство. Это меняет сферу вашего вопроса.

Также проверьте этот код

hdesk = OpenDesktop(TEXT("Screen-saver"),
                    0,
                    FALSE,
                    DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hdesk)
{
   EnumDesktopWindows (hdesk, (WNDENUMPROC)KillScreenSaverFunc, 0);
   CloseDesktop (hdesk);
}

// ----------------------------------------------------------------

BOOL CALLBACK KillScreenSaverFunc (HWND hwnd, LPARAM lParam)
{
   PostMessage(hwnd, WM_CLOSE, 0, 0);
   return TRUE;
}

отсюда

Другие вопросы по тегам