Получение информации о меню
Функция GetMenu возвращает дескриптор главного меню окна hwnd:
HMENU GetMenu(HWND hwnd);
Если окно не имеет меню, функция возвращает NULL. Функция GetSubMenu возвращает дескриптор временного меню, которое расположено в позиции nPos указанного меню hmenu:
HMENU GetSubMenu(HMENU hmenu, int nPos);
Причем первому временному меню в hmenu соответствует нулевое значение параметра nPos. Если функция GetSubMenu вернула значение NULL, то hmenu в позиции nPos не содержит временное меню.
Функция IsMenu возвращает ненулевое значение, если hmenu является дескриптором меню, иначе – возвращает нуль:
BOOL IsMenu(HMENU hmenu);
Функция GetMenuItemCount возвращает количество элементов в меню hmenu:
int GetMenuItemCount(HMENU hmenu);
В случае ошибки возвращаемое значение равно -1.
Задача. Окно приложения при создании должно узнать информацию о разделе меню "Файлы" приложения из листинга 4.3, сообщить о количестве элементов в этом разделе. После нажатия левой клавиши мыши окну этого приложения послать команду элемента в позиции 0 ("Открыть").
Листинг 4.4. Управление состоянием строк меню другого окна
#include <windows.h>
#include <tchar.h>
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInstance;
TCHAR szClass[] = TEXT("GetMenuInfo");
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
hInstance = hInst;
if (!RegClass(WndProc, szClass, COLOR_WINDOW)) return FALSE;
hwnd = CreateWindow(szClass, TEXT("Управление состоянием строк меню другого окна"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);
if (!hwnd) return FALSE;
while(GetMessage(&msg, 0, 0, 0))
{ TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam;
}
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASS wc;
wc.style = wc.cbClsExtra = wc.cbWndExtra = 0;
wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(brBackground +1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szName;
return (RegisterClass(&wc) != 0);
}
UINT GetMenuItem(HMENU hMenu, UINT uIns)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_ID;
GetMenuItemInfo(hMenu, uIns, 1, &mii);
return mii.wID;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMainMenu, hFiles;
static HWND hOther;
switch (msg)
{
case WM_CREATE:
{
hOther = FindWindow(TEXT("SetMenuInfo"), TEXT("Управление состоянием элементов меню"));
if (!hOther)
{ MessageBox(hwnd, TEXT("Такого окна нет"), TEXT("Сообщение"), MB_OK); return 0; }
hMainMenu = GetMenu(hOther);
if (!hMainMenu)
{ MessageBox(hwnd, TEXT("OKHo не имеет меню"), TEXT("Сообщение"), MB_OK); return 0; }
hFiles = GetSubMenu(hMainMenu, 0);
if (!hFiles)
{ MessageBox(hwnd, TEXT("HeT такого элемента меню"), TEXT("Сообщение"), MB_OK); return 0; }
int items = GetMenuItemCount(hFiles);
TCHAR str[50]={0};
_itow(items, str, 10);
_tcscat(str, TEXT(" – элементов в меню 'Файлы' другого окна"));
MessageBox(hwnd, str, TEXT("Сообщение"), MB_OK);
return 0;
}
case WM_LBUTTONDOWN:
{
UINT uCom = GetMenuItem(hFiles, 0);
if (!uCom)
MessageBox(hwnd, TEXT("Команда равна нулю"), TEXT("Сообщение"), MB_OK);
SendMessage(hOther, WM_COMMAND, uCom, 0L);
return 0;
}
case WM_DESTROY: { PostQuitMessage(0); return 0; }
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
До запуска этого приложения должно быть запущено приложение из листинга 4.3.
Рассмотрим, как работает это приложение.
Приложение основную работу выполняет при обработке сообщения WM_CREATE.
Перечислим эти действия:
1. Определяет, существует ли окно класса "SetMenuInfo" с заголовком "Управление состоянием строк меню":
hOther=FindWindow("SetMenuInfo", "Управление состоянием строк меню");
2. Запрашивает дескриптор главного меню этого окна:
hMainMenu = GetMenu(hOther);
3. Запрашивает дескриптор временного меню в позиции 0:
hFiles = GetSubMenu(hMainMenu, 0);
4. Определяет количество элементов в меню hFiles:
int items = GetMenuItemCount(hFiles);
5. Формирует и выдает сообщение об этом:
char str[50];
itoa(items, str, 10);
strcat(str, " – элементов в меню 'Файлы' другого окна");
MessageBox(hwnd, str, "Сообщение", МВ_ОК);
После нажатия левой клавиши мыши активизируется первый элемент меню:
1. Определяется значение команды элемента мещо hFiles:
UINT uCom=GetMenuItem(hFiles, 0);
Обратите внимание, что функция с именем GetMenuItem в этом приложении приведена к виду:
UINT GetMenuItem(HMENU hMenu, UINT uIns)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_ID;
GetMenuItemInfo(hMenu, uIns, 1, &mii);
return mii.wID;
}
Теперь эта функция возвращает идентификатор команды элемента в указанной позиции. Например, вызов GetMenuItem(hFiles, 0) возвращает идентификатор команды первого элемента меню hFiles.
2. Посылается сообщение WM_COMMAND с идентификатором команды uCom:
SendMessage(hOther, WM_COMMAND, uCom, 0L);
По сути, функции окна приложения из листинга 4.3 посылается сообщение WM_COMMAND с кодом wParam, младшее слово которого равно идентификатору команды CM_FILE_OPEN.
Приложение листинга 4.3 немедленно выполняет эту команду. Эта; команда поступает независимо от состояния элемента "Открыть" (он может быть и заблокирован).
Сообщение WM_COMMAND с идентификатором uCom можно посылать сколь угодно раз. Каждый раз в главное меию вставляются элементы "Правка" и "Вид". Это говорит о том, что нельзя полагаться на то, что заблокированный элемент меню не может послать команду. Перед обработкой сообщения нужно проверять состояние элемента, которое имеет право посылать это сообщение.
Сообщения от меню
Меню посылает сообщения в функцию того окна, к которому оно подключено функцией SetMenu.
Сообщение WM_INITMENU
Сообщение WM_INITMENU поступает перед отображением главного меню. Параметр wParam равен дескриптору меню. Если сообщение WM_INITMENU обрабатывают, то возвращают 0. Обработка обычно сводится к изменению состояния элементов меню.