Вызов функции c ++ перед выходом из системы - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь выполнить функцию при выходе пользователя из системы, но программа закрывается перед вызовом функции, есть ли способ подождать, пока функция завершит выполнение функции?

#include "stdafx.h"
#include <windows.h>
#include <fstream>  
using namespace std;
bool done = false;

void createFile() {
    ofstream outfile("test.txt");
    outfile << "test" << std::endl;
    outfile.close();
}

BOOL WINAPI consoleHandler(DWORD signal) {
    switch (signal)
    {
    case CTRL_LOGOFF_EVENT:
        printf("Logoff");
        done = true;
        Sleep(20000); // force exit after 20 seconds
        return TRUE;
    case CTRL_C_EVENT:
        printf("Ctrl+c");
        done = true;
        Sleep(20000); // force exit after 20 seconds
        return TRUE;

    case CTRL_CLOSE_EVENT:
        printf("close");
        done = true;
        Sleep(20000); // force exit after 20 seconds
        return TRUE;

    default:
        // Pass signal on to the next handler
        return FALSE;
    }
}


int main()
{
    if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
        printf("\nERROR: Could not set control handler");
        return 1;
    }

    printf("Runing");
    while (!done) {
        printf(".");
        Sleep(1000);
    }
    createFile(); //Dont called on user logout but called on close and ctrl+c
    printf("\nEnding\n");
    Sleep(1000);
    return 0;
}

Вкл. CTRL_C_EVENT и CTRL_CLOSE_EVENT

Файл test.txt создан, но в

CTRL_LOGOFF_EVENT

Программа закрывается мгновенно, без вызова функции.

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Во-первых, позвольте мне извиниться: я не отвечу на конкретное «CTRL_LOGOFF_EVENT», на которое вы ссылаетесь, но на общую функцию, которую вы пытаетесь выполнить: «выполнить функцию при выходе пользователя из системы».

Общий способ сделать:

Насколько я знаю, нет никакого общего способа сделать.

Вы можете попробовать различные решения:

  • ловит события как вы
  • используя try catch / finally
  • порождает таймеры окон и реагирует на него
  • порождает потоки, которые будут ждать окончания основного потока

Но (насколько я знаю) у всех них есть слабость в способе закрытия или в другом.

Например, недавно мне пришлось бороться с плохо закодированным dll, который я должен был использовать. Эта DLL вызывала «выход (0)». Я не нашел элегантного способа изящно справиться с этим поведением.

Мне пришлось запустить его в отдельном процессе (не в потоке), который я отслеживал из своего основного процесса. Это много работы для реализации и поддержания для простого результата.

Другой подход:

В зависимости от того, что вы пытаетесь сделать, хорошей практикой может быть постепенное выполнение «последней» операции с использованием формата, позволяющего восстановить частично записанные файлы.

Это то, что я обычно делаю, но это всегда зависит от того, чего вы пытаетесь достичь.

Например, если вы пытаетесь очистить свое рабочее пространство, вы можете:

  • сделать это при запуске, если это не было сделано в предыдущем запуске
  • работа во временных папках

В другом случае, если у вас очень длинный процесс и вы хотите сгенерировать сводный файл, вы можете:

  • время от времени генерирует частичный сводный файл
  • при создании нового файла вы перемещаете предыдущий

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

0 голосов
/ 30 апреля 2018

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

Прежде всего, так как вы не получаете CTRL_LOGOFF_EVENT, вы можете обратиться к этому документу (https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler). Критический раздел:

If a console application loads the gdi32.dll or user32.dll library, the 
HandlerRoutine function that you specify when you call SetConsoleCtrlHandler 
does not get called for the CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT events. The 
operating system recognizes processes that load gdi32.dll or user32.dll as Windows 
applications rather than console applications. This behavior also occurs for 
console applications that do not call functions in gdi32.dll or user32.dll 
directly, but do call functions such as Shell functions that do in turn call 
functions in gdi32.dll or user32.dll.

To receive events when a user signs out or the device shuts down in these 
circumstances, create a hidden window in your console application, and then handle 
the WM_QUERYENDSESSION and WM_ENDSESSION window messages that the hidden window 
receives. You can create a hidden window by calling the CreateWindowEx method with 
the dwExStyle parameter set to 0.

Возможно, вы также захотите прочитать (https://msdn.microsoft.com/en-us/library/windows/desktop/aa376890(v=vs.85).aspx).

Теперь, что я ранее предлагал, это использовать SetWindowsHookEx, который должен работать, когда все сообщения Windows проходят через него (это то, что Spy использует для просмотра очередей сообщений (https://blogs.msdn.microsoft.com/vcblog/2007/01/16/spy-internals/)). 20 лет назад, вы могли бы сделать что-то подобное для определенных сообщений, которые не были переданы в ваше окно - как в вашем случае, когда сообщение Windows обрабатывается в потоке текущего окна. Вы можете столкнуться со старым кодом, который это делает, или могут возникнуть ситуации, когда вам все еще нужно это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...