2011-02-01 4 views
3

Я пишу небольшое приложение-утилиту для управления громкостью системы с помощью горячих клавиш для моего GF, чей ноутбук почему-то лишен таких функциональных клавиш. Я мгновенно взломал код, и у меня есть основная функциональность, работающая отлично; однако, поскольку я не создаю никаких окон (просто цикл сообщений обрабатывает сообщение WM_HOTKEY), я не могу закончить приложение более элегантно, чем просто безмерно прекратить процесс (также, когда система выключается, это показывает «должен ли я ждать завершения процесса или убить его сейчас» с некоторым количеством мусора в том месте, где обычно находится заголовок окна).Изящно закрывающее окно без окон в WinAPI

Есть ли способ сделать это, что не связано с созданием поддельного окна только для перехвата сообщений WM_CLOSE?

Вот код (я ушел из функций управления смесителем намеренно, они не имеют отношения к вопросу):

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { 
    MSG msg; 
    int step; 
    MixerInfo_t mi; 
    HANDLE mutex; 

    mutex = CreateMutex(NULL, TRUE, "volhotkey"); 
    if (mutex == NULL) 
     return 1; 
    if (GetLastError() == ERROR_ALREADY_EXISTS) 
     return 0; 

    RegisterHotKey(NULL, 1, MOD_ALT | MOD_CONTROL, VK_F5); 
    RegisterHotKey(NULL, 2, MOD_ALT | MOD_CONTROL, VK_F6); 
    RegisterHotKey(NULL, 3, MOD_ALT | MOD_CONTROL, VK_F7); 

    mi = GetMixerControls(); 
    step = (mi.maxVolume - mi.minVolume)/20; 

    while (GetMessage(&msg, NULL, 0, 0)) { 
     switch (msg.message) { 
      case WM_HOTKEY: 
       switch (msg.wParam) { 
        case 1: 
         AdjustVolume(&mi, -step); 
         break; 
        case 2: 
         AdjustVolume(&mi, step); 
         break; 
        case 3: 
         SetMute(&mi, !IsMuted(&mi)); 
         break; 
       } 
       MessageBeep(MB_ICONASTERISK); 
       break; 
      case WM_DESTROY: 
       PostQuitMessage(0); 
       break; 
      default: 
       break; 
     } 
    } 

    UnregisterHotKey(NULL, 1); 
    UnregisterHotKey(NULL, 2); 

    return msg.wParam; 
} 

Заранее спасибо!

О, и для записи WM_DESTROY также не отправляется.

+0

Вы проверили сайт поддержки вашего ноутбука, чтобы убедиться, что они уже предоставляют такую ​​утилиту? – Ferruccio

+0

У меня есть, и они этого не делают. Это HP nx6110, и у него даже нет кнопок для него, как я уже сказал в вопросе. – IneQuation

ответ

4

Вы можете использовать функцию SetConsoleCtrlHandler() для прослушивания события выключения.

SetConsoleCtrlHandler(ShutdownHandler, TRUE); 

Вы обработчик будет выглядеть примерно так:

BOOL WINAPI ShutdownHandler(DWORD dwCtrlType) 
{ 
    if(dwCtrlType == CTRL_SHUTDOWN_EVENT || dwCtrlType == CTRL_LOGOFF_EVENT) 
    { 
     ExitProcess(0); 
     return TRUE; // just to keep the compiler happy 
    } 

    return FALSE; 
} 

Несмотря на название, SetConsoleCtrlHandler() работает независимо от того, является ли приложение является консольным приложением.

+1

Спасибо, мужик, это именно то, что я искал! :) Плюс, вы, наверное, единственный человек, который на самом деле внимательно прочитал вопрос. – IneQuation

+0

Добро пожаловать. Рад, что смог помочь. –

0

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

Или есть еще одна горячая клавиша, которая показывает небольшое окно с настройками?

+0

Приложение не будет расти, это всего лишь маленькое частное приложение, и я спросил конкретно о решении без окон. – IneQuation

1

Обратите внимание на вызов API ExitProcess для изящного завершения процесса. Чтобы обнаружить выключение Windows, включите в обработку сообщений WM_ENDSESSION. Если ваше приложение более сложное, чем опубликованное, вы также можете просмотреть функцию ExitThread.

+0

Спасибо, что привлекли это сообщение к моему вниманию, оно пригодится! – IneQuation

1

Вы не создали ни одного окна, даже скрытого, поэтому нет способа получить цикл для выхода, отправив сообщение в окно. Также причина, по которой WM_DESTROY никогда не срабатывает.

Все, что осталось, это PostThreadMessage() для отправки WM_QUIT. Вы должны были бы найти идентификатор потока каким-то образом. Использование Shell_NotifyIcon() было бы разумным.

+0

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

+0

Эмм, не поддельный, не настоящий. Просто не видно.Также весьма полезно обнаружить, что Windows выключается, поэтому вы можете завершить приложение без остановки или выстрела в голову Windows. Если вы просто не хотите использовать окно, используйте именованный канал. –

Смежные вопросы