Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как получить хэндл контекстного меню?  (Прочитано 15029 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« : 19-04-2006 18:39 » 

Ситуация:
Есть некое оконное приложение, в котором, в частности, пользователь имеет возможность осуществлять выбор чего-либо через контекстное меню. Есть другое приложение, которое владеет информацией касательно хэндлов окон первого.
Задача заключается в обнаружении и получении доступа к контекстному меню первого приложения из второго (считаем, что второе приложение работает "в фоне" и оно будет иметь достаточно времени, чтобы засечь меню).

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

Если способ обнаружить контекстное меню есть, но не работает через границу процесса - не беда, уже есть один хук, который вешается вторым процессом на поток первого.
Записан
Серж
Гость
« Ответ #1 : 20-04-2006 07:03 » 

Получить доступ к меню можно с помощью вызова функций GetMenu или
GetSubmenu, если хэндлы окон-владельцев известны и затем выдать сообщения WM_INITMENU или WM_INITMENUPOPUP, а затем WM_COMMAND. Ну а если нужно перехватить меню в процессе всплывания, тогда действовать так, как сам и описываешь.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #2 : 20-04-2006 21:52 » 

Серж, Не получится так перехватить меню через функцию GetMenu. Эта функция выдаст хэндл меню закрепленное за окном. В головном окне это строка меню. В дочерних окнах ставят как правило NULL. Контекстное меню как правило вызывается по правому шелчку мыши. И оно никак не регистрируется относительно окна. Вызов производится через функцию TrackPopupMenu.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Серж
Гость
« Ответ #3 : 21-04-2006 09:19 » 

Finch, по-моему, меню всегда приписывается какому-нибудь окну.
Это делается либо в CreateWindow, либо в SetMenu. И владелец меню должен быть явно указан в функции TrackPopupMenu. Если меню не приписано никакому окну, оно просто не будет отображаться, так как некому обрабатывать сообщения.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #4 : 21-04-2006 12:11 » 

В функции TrackPopupMenu один из параметров хэндл окна, которое будет получать сообшение об иницилизации контекстного меню и о выборе подпункта. Пока я не иницилизирую данной функцией меню, я не обязан приписывать его своему окну. Чуть попозже набрасаю пример работы Улыбаюсь .
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 21-04-2006 14:20 » 

Вот обешанный пример. Программа сделана на WinAPI
Код:
//---------------------------------------------------------------------------
#include <windows.h>
#include <windowsx.h>
//---------------------------------------------------------------------------

static HWND MainWindow;
char szAppName[] = "LibraryApp";
char szTitle[] = "Library Sample Application";
HMENU menu=NULL;                                                     //Хэндл контекстной менюшки
HBRUSH brush[2];
int setBrush=0;


bool Register(HINSTANCE);
HWND Create(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void OnDestroy(HWND hwnd);

//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE hInst,
               HINSTANCE hPrevInst,
               LPSTR CmdParam,
               int nCmdShow)
{
   MSG Msg;
   brush[0]=CreateSolidBrush(RGB(0,0,0));
   brush[1]=CreateSolidBrush(RGB(255,255,192));

   if (!Register(hInst))
       return false;
   MainWindow=Create(hInst,nCmdShow);
   if (MainWindow==0)
       return false;

   while (GetMessage(&Msg,NULL,0,0))
      {
       TranslateMessage(&Msg);
       DispatchMessage(&Msg);
      }
   DeleteObject(brush[0]);
   DeleteObject(brush[1]);
   return Msg.wParam;
}
//---------------------------------------------------------------------------
bool Register(HINSTANCE hInst)
{
   WNDCLASS wc;

   wc.style         = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc   = (WNDPROC) WndProc;
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 0;
   wc.hInstance     = hInst;
   wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = brush[setBrush];
   //Меню не связано с окном при регистрации
   wc.lpszMenuName  = NULL;                                                         
   wc.lpszClassName = szAppName;

   return (RegisterClass(&wc) !=0);

}

HWND Create(HINSTANCE hInst, int nCmdShow)
{
   // Также при создании окна
   HWND hWindow = CreateWindow(szAppName, szTitle,
                               WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               NULL, NULL, hInst, NULL);
   if (hWindow != NULL)
       {
        ShowWindow(hWindow, nCmdShow);
        UpdateWindow(hWindow);
       }
   return hWindow;
}

#define ID_CLOSE 100
#define ID_CHANGE 101
//Создаем контекстное меню
void InitMenu(void)
{
if (menu == NULL)
{
menu=CreatePopupMenu();
AppendMenu(menu, MF_STRING, ID_CHANGE, "Change Color");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, ID_CLOSE, "Exit");

}
}

//Вызываем его при нажатии правой кнопки мыши
void OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
InitMenu();
POINT po;
po.x=x;
po.y=y;
ClientToScreen(hwnd, &po);
TrackPopupMenu(menu,TPM_RIGHTBUTTON, po.x, po.y, 0, hwnd, NULL);
}

void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case ID_CLOSE:
PostMessage(hwnd, WM_CLOSE, 0,0);
break;
case ID_CHANGE:
setBrush=1-setBrush;
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG) brush[setBrush]);
InvalidateRect(hwnd,NULL, true);
break;
};
}



LRESULT CALLBACK WndProc(HWND hWindow, UINT Message,
                         WPARAM wParam, LPARAM lParam)
{
   switch(Message)
      {
       HANDLE_MSG(hWindow, WM_DESTROY, OnDestroy);
   HANDLE_MSG(hWindow, WM_RBUTTONDOWN, OnRButtonDown);
   HANDLE_MSG(hWindow, WM_COMMAND, OnCommand);
       default:
          return DefWindowProc(hWindow, Message, wParam, lParam);
      }
}


void OnDestroy(HWND hwnd)
{
if (menu != NULL) DestroyMenu(menu);
menu=NULL;
PostQuitMessage(0);
}

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

Так что, кроме хука, я не вижу способа ловить отрисовку контекстного меню из чужого окна.
« Последнее редактирование: 21-04-2006 14:27 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Серж
Гость
« Ответ #6 : 21-04-2006 14:46 » 

Finch, согласен, я уже и сам проверил, что до вызова TrackPopupMenu,
можно окно-приемник сообщений не определять.
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 21-04-2006 21:11 » 

Ну что ж, и на том спасибо - по крайней мере, остановлюсь на уже выбранном варианте, не ломая голову в поисках других (уже достаточно поломал, MSDN и инет прилично полопатил - сработало какое-то "не может быть, должен же быть способ!").
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines