Приложение без окон Win32 - дождитесь выхода из программы - PullRequest
4 голосов
/ 20 декабря 2010

У меня есть приложение без окон, единственной целью которого является установка 32-битного DLL-файла ловушки и ожидание выхода из родительской программы (64-битная программа).64-битная программа написана на C #, а приложение без окон написано на C ++.Первоначально у меня был этот цикл GetMessage, который удерживал программу открытой:

while(GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Я закрывал приложение C ++, используя метод Process.Kill в C #, но я обнаружил, что это не позволяет приложению C ++закрыть чисто.Кроме того, в случае сбоя приложения C # приложение C ++ останется открытым навсегда.Я сделал проверку приложения C ++, чтобы проверить, работает ли приложение C #, используя этот цикл:

while(true)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;

    Sleep(1000);
}

По какой-то причине сон вызывает проблемы.Хуки, установленные файлом DLL, - это WH_CBT и WH_KEYBOARD.Всякий раз, когда я нажимаю клавишу, когда приложение C ++ работает с этим циклом, ключи просто съедаются.Удаление Sleep заставляет его работать нормально, но, как и ожидалось, он использует 100% CPU , что мне не нужно.Я попытался полностью удалить цикл сообщений и вместо этого использовать WaitForSingleObject с бесконечным тайм-аутом в потоке, который завершится, когда isMainProgramRunning вернет false.Это в основном блокирует весь компьютер.

Я не очень понимаю, почему GetMessage, который, насколько я видел, никогда не возвращался, но приостанавливал основной поток на неопределенный срок, еще не вызывал этих проблем WaitForSingleObject вызываеткаждое приложение зависает при нажатии на него.Как я могу заставить приложение C ++ оставаться открытым до тех пор, пока приложение C # не закроется?

Редактировать:

Поскольку мне было указано, что спать в насосе сообщений плохо, позвольте мне спросить это: Есть ли способ указать время ожидания для ожидания сообщения, чтобы программа не ждала сообщения в течение неопределенного времени, а скорее подождет около 250 мс, время ожидания, позвольте мне запустить метод isMainProgramRunning, а затем подождать еще немного?

Edit2:

Я пытался использовать MsgWaitForMultipleObjects, хотя и несколько иначе, чем предложил Лео.Вот цикл, который я использовал:

while(MsgWaitForMultipleObjects (0, NULL, true, 250, QS_ALLPOSTMESSAGE) != WAIT_FAILED)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;
}

Снова у меня была та же проблема со сном.Я также попытался приостановить основной поток и заставить другой поток возобновить его.Та же проблема.Что делает GetMessage, что позволяет ему ждать, не вызывая этих проблем?Может быть, это должно быть темой другого поста, но почему, когда приложение C ++, устанавливающее хуки, спит или приостанавливается, вся обработка в хуках, похоже, также приостанавливается?

Edit3:

Вот метод DLL, который приложение C ++ вызывает для установки ловушек:

extern "C" __declspec(dllexport) void install()
{
    cbtHook = SetWindowsHookEx(WH_CBT, hookWindowEvents, hinst, NULL);

    if(cbtHook == NULL)
        MessageBox(NULL, "Unable to install CBT hook", "Error!", MB_OK);

    keyHook = SetWindowsHookEx(WH_KEYBOARD, LowLevelKeyboardProc, hinst, NULL);

    if(keyHook == NULL)
        MessageBox(NULL, "Unable to install key hook", "Error!", MB_OK);
}

Ответы [ 4 ]

4 голосов
/ 20 декабря 2010

У вас есть две отдельные проблемы:

  1. Как заставить программу C ++ без окон работать автоматически при выходе из программы C # (например, сбой).

    В программе на C ++ откройте дескриптор программы на C #. Поскольку программа C # запускает программу C ++, пусть программа C # передает свой собственный PID в качестве аргумента; затем программа C ++ может открыть дескриптор этого процесса, используя OpenProcess .

    Затем используйте MsgWaitForMultipleObjects в цикле сообщений. Если программа C # выйдет из дескриптора, который вам нужен, он будет сигнализирован и вы проснетесь. (Вы также можете использовать WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0, чтобы проверить, сигнализирует ли процесс или нет, например, чтобы проверить, почему вы проснулись, хотя результат MsgWaitForMultipleObjects также скажет вам об этом.)

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

  2. Как заставить программу C # дать команду программе C ++ на выход.

    Это может вам не понадобиться, если вы # 1 работаете, но вы можете просто заставить программу C # публиковать сообщение на C ++, если хотите.

    НЕ ИСПОЛЬЗУЙТЕ PostQuitMessage и НЕ публикуйте и не отправляйте WM_QUIT между потоками или процессами.

    Вместо этого опубликуйте другое сообщение, о котором договариваются два приложения (например, WM_APP + 1), используя PostThreadMessage .

1 голос
/ 20 декабря 2010

Вы можете создать именованное событие и использовать:

MsgWaitForMultipleObjects

в вашем цикле сообщений.

Приложение C # должно только открыть и вызвать это событие, чтобы сообщить вашему приложению о выходе.

Это своего рода минимальное межпроцессное взаимодействие.

0 голосов
/ 20 декабря 2010

GetMessage никогда не возвращается, потому что у вас нет созданного окна!

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

0 голосов
/ 20 декабря 2010

Вы должны выйти из процесса, отправив ему сообщение WM_QUIT и обработав его правильно, как указано в этой статье (Модальность) Рэймонда ЧенаНе спите внутри цикла без обработки сообщений - это неправильно.Ваше приложение должно либо обрабатывать сообщение, либо ждать новых сообщений.

...