Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Hook WM_CLOSE


Автор: ApolloKiD 9.5.2012, 17:14
Доброго времени суток всем!

Встала передо мной задача хукнуть WM_CLOSE.
Есть программа которая при нажатии на крести [x] сразу закрываеться даже не спрашивает мол "Вы действительно хотите закрыть окно, Да или нет".
Следственно исходников программы у меня тоже нету, есть только ДЛЛ которую я подключаю к этой программе.
Хук я оуществил, при нажатии на крестик выскакивает сообщение "Вы действительно хотите закрыть окно, Да или нет", но окно закрываеться даже если нажимаю "нет".
Может кто-то подсказать что я не так делаю, и что надо сделать чтобы при нажатии на кнопку "Нет" окно не закрывалось.

Вот код:
Код

HHOOK currentHook;
LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp)
{
   CWPSTRUCT cwp = *(CWPSTRUCT *)lp;
   switch(cwp.message)
   {
   case WM_CLOSE:
        if (MessageBox(cwp.hwnd, "Вы действительно хотите закрыть окно?", "Close", MB_YESNO | MB_APPLMODAL) == IDYES)
        {
            DestroyWindow(cwp.hwnd);
        }
       break;
   default:
       return FALSE;
   }
   return CallNextHookEx(currentHook, nCode, wp, lp);
}


extern "C"
{
    __declspec(dllexport) BOOL __stdcall WINAPI DllMain (HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
    {
        switch (dwReason)
        {
        case DLL_PROCESS_ATTACH:
            currentHook = SetWindowsHookExA(WH_CALLWNDPROC, HookProc, 0, GetCurrentThreadId());
            break;
         case DLL_PROCESS_DETACH:
                        UnHookWindowsHookExA(currentHook);
            break;
        }
        return TRUE;
    }
}


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

Автор: feodorv 9.5.2012, 20:55
Цитата(ApolloKiD @  9.5.2012,  18:14 Найти цитируемый пост)
но окно закрываеться даже если нажимаю "нет".

Видимо, сообщение WM_CLOSE всё равно доходит до оконной процедуры  smile С хуком или без)))

Автор: ApolloKiD 9.5.2012, 20:58
А можно как-то сделать чтобы не доходило при нажатии кнопки "нет" ?

Автор: feodorv 9.5.2012, 21:03
Цитата(ApolloKiD @  9.5.2012,  18:14 Найти цитируемый пост)
что надо сделать

Думаю, поставить WH_GETMESSAGE хук, и при получении WM_CLOSE и отрицательного результата от MessageBox модифицировать msg так, что оно больше не было WM_CLOSE...

Автор: ApolloKiD 9.5.2012, 21:11
А можно примером показать ? =)

Автор: GremlinProg 10.5.2012, 07:32
может проще так:
Цитата(ApolloKiD @ 9.5.2012,  19:14)
Доброго времени суток всем!
   case WM_CLOSE:
        if (MessageBox(cwp.hwnd, "Вы действительно хотите закрыть окно?", "Close", MB_YESNO | MB_APPLMODAL) == IDYES)
        {
            DestroyWindow(cwp.hwnd);
            break;
        }
        break;
        return 0;
   default:
       return FALSE;
   }
   return CallNextHookEx(currentHook, nCode, wp, lp);


Автор: feodorv 10.5.2012, 09:53
Цитата(GremlinProg @  10.5.2012,  08:32 Найти цитируемый пост)
        return 0;
   default:
       return FALSE;

А чем return 0; от return FALSE; отличается?

Цитата

WH_CALLWNDPROCRET - Installs a hook procedure that monitors messages after they have been processed by the destination window procedure.  

Полагаю, что оконная процедура уже обработала WM_CLOSE.

Автор: GremlinProg 10.5.2012, 09:58
Цитата(feodorv @  10.5.2012,  11:53 Найти цитируемый пост)
А чем return 0; от return FALSE отличается?

ни чем не отличается

Автор: feodorv 10.5.2012, 10:01
Тогда чем это поможет?

Цитата(feodorv @  10.5.2012,  10:53 Найти цитируемый пост)

WH_CALLWNDPROCRET - Installs a hook procedure that monitors messages after they have been processed by the destination window procedure.  

Полагаю, что оконная процедура уже обработала WM_CLOSE.


Автор: GremlinProg 10.5.2012, 10:15
Цитата(feodorv @ 10.5.2012,  12:01)
Тогда чем это поможет?

Цитата(feodorv @  10.5.2012,  10:53 Найти цитируемый пост)

WH_CALLWNDPROCRET - Installs a hook procedure that monitors messages after they have been processed by the destination window procedure.  

Полагаю, что оконная процедура уже обработала WM_CLOSE.

а при чем тут WH_CALLWNDPROCRET?

Добавлено через 4 минуты и 56 секунд
Цитата(ApolloKiD @  9.5.2012,  19:14 Найти цитируемый пост)
ледственно исходников программы у меня тоже нету, есть только ДЛЛ которую я подключаю к этой программе.

в таком случае хук - мера лишняя,
подойдет сабклассинг главного окна из DLL

Автор: feodorv 10.5.2012, 10:31
Цитата(GremlinProg @  10.5.2012,  11:15 Найти цитируемый пост)
а при чем тут WH_CALLWNDPROCRET? 

Прошу прощения, не туда посмотрел)))

Цитата

WH_CALLWNDPROC - Installs a hook procedure that monitors messages before the system sends them to the destination window procedure.


То есть хук вызывается до оконной процедуры. 
Но даже так в доке написано:
Цитата

After the hook procedure returns control to the system, the message is passed to the window procedure. 

То есть WM_CLOSE всё равно уходит в оконную процедуру.


А вот на что влияет возвращаемое из хука значение - вопрос интересный.
В любом случае попробовать стоит (хотя возвращаемое значение 0 - стандартное, и вряд ли на что-то влияет). Только
Цитата(ApolloKiD @  9.5.2012,  18:14 Найти цитируемый пост)
   default:
       return FALSE;

я бы делать не стал...

Добавлено через 9 минут
Цитата(GremlinProg @  10.5.2012,  11:15 Найти цитируемый пост)
подойдет сабклассинг главного окна из DLL

 smile 

Гм. Если есть HWND главного окна...

Автор: feodorv 10.5.2012, 11:10
Цитата(ApolloKiD @  9.5.2012,  22:11 Найти цитируемый пост)
А можно примером показать ? =) 

Что-то вроде такого:
Код

LRESULT CALLBACK GetMsgHook( int nCode, WPARAM wParam, LPARAM lParam)
{
  if( nCode == HC_ACTION )
  {
    MSG *msg = (MSG *) lParam;
    if( msg->message == WM_CLOSE )
      if( MessageBox( msg->hwnd, "Вы действительно хотите закрыть окно?", "Close", MB_YESNO | MB_APPLMODAL) != IDYES )
         msg->message = WM_NULL;
  }
  return CallNextHookEx( currentHook, nCode, wParam, lParam);
}

Автор: ApolloKiD 11.5.2012, 15:43
Извиняюсь за опоздание..

Цитата(GremlinProg @  10.5.2012,  10:15 Найти цитируемый пост)
в таком случае хук - мера лишняя,
подойдет сабклассинг главного окна из DLL 


можно пример или ссылку где бы почитать о сабклассинге?

Цитата(feodorv @  10.5.2012,  11:10 Найти цитируемый пост)
Что-то вроде такого:


пробывал ваш метод, вообще 0 реакции..

Автор: feodorv 11.5.2012, 22:54
Цитата(ApolloKiD @  11.5.2012,  16:43 Найти цитируемый пост)
пробывал ваш метод, вообще 0 реакции.. 

Здесь нужен глобальный хук (не локальный) и знание хендла окна. Но если хендл известен, то лучше реализовать сабклассинг.

Если хендл окна неизвестен, без хука не обойтись. Выше я писал о необходимости понять, на что влияет возвращаемое из хука значение. Соответственно, можно подобрать подходящий хук. Я подобрал:
Код

#include <windows.h>

static HHOOK currentHook;

LRESULT CALLBACK CBTHook( int nCode, WPARAM wParam, LPARAM lParam)
{
  LRESULT rv = CallNextHookEx( currentHook, nCode, wParam, lParam);
  if( nCode == HCBT_SYSCOMMAND && wParam == SC_CLOSE )
    if( MessageBox( NULL, "Вы действительно хотите закрыть окно?", "Close", MB_YESNO | MB_APPLMODAL) != IDYES )
       return TRUE;
  return rv;
}

__declspec(dllexport) BOOL WINAPI DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
{
  switch (dwReason)
  {
    case DLL_PROCESS_ATTACH:
      currentHook = SetWindowsHookEx( WH_CBT, CBTHook, 0, GetCurrentThreadId());
      break;
    case DLL_PROCESS_DETACH:
      UnhookWindowsHookEx( currentHook );
      break;
  }
  return TRUE;
}


Обо всех хуках неплохо написано http://www.rsdn.ru/article/baseserv/winhooks.xml. Может, реализуете как-нибудь иначе (трудно сказать, все ли варианты закрытия окна охватывает приведённое решение).

Автор: ApolloKiD 11.5.2012, 23:24
Спасибо большое, всё работает =)

Автор: feodorv 12.5.2012, 07:38
Цитата(ApolloKiD @  12.5.2012,  00:24 Найти цитируемый пост)
всё работает =) 

Работать то работает, но, может не так, как планировалось. Например, если главное окно в результате действий пользователя порождает ещё окна, то их закрытие нажатием на крестик приведёт к ненужному срабатыванию ловушки...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)