Сообщений 10 Оценка 111 Оценить |
Для отображения контекстного меню, связанного с объектами пространства имён оболочки Windows, эксплорер использует интерфейс IContextMenu соответствующего объекта. Мы тоже можем воспользоваться этим интерфейсом в нашей программе. Последовательность шагов при этом будет следующей:
Основную сложность на самом деле представляет первый этап. Получить указатель на IContextMenu мы можем только, имея указатель на интерфейс IShellFolder для объекта оболочки Windows, содержащего требуемый файл или каталог, но Windows не предоставляет простого способа получить этот указатель. Соответствующая процедура подробно описана в статье "Как получить IShellFolder для заданного файла или каталога?", поэтому здесь я просто воспользуюсь алгоритмом, описанным в этой статье.
Функция, отображающая контекстное меню, может выглядеть примерно так (её можно использовать как в программе на "чистом" API, так и на MFC).
#include <shlobj.h> #include <atlbase.h> ... void ShowContextMenu(HWND hWnd, LPCTSTR pszPath, int x, int y) { USES_CONVERSION; // Строим полное имя файла/каталога TCHAR tchFullPath[MAX_PATH]; GetFullPathName(pszPath, sizeof(tchFullPath)/sizeof(TCHAR), tchFullPath, NULL); // Получаем интерфейс IShellFolder рабочего стола IShellFolder *pDesktopFolder; SHGetDesktopFolder(&pDesktopFolder); // Преобразуем заданный путь в LPITEMIDLIST LPITEMIDLIST pidl; pDesktopFolder->ParseDisplayName(hWnd, NULL, T2OLE(tchFullPath), NULL, &pidl, NULL); // Ищем последний идентификатор в полученном списке pidl LPITEMIDLIST pLastId = pidl; USHORT temp; while(1) { int offset = pLastId->mkid.cb; temp = *(USHORT*)((BYTE*)pLastId + offset); if(temp == 0) break; pLastId = (LPITEMIDLIST)((BYTE*)pLastId + offset); } // Получаем интерфейс IShellFolder родительского объекта для заданного файла/каталога // Примечание: родительский каталог идентифицируется списком pidl за вычетом последнего // элемента, поэтому мы временно зануляем pLastId->mkid.cb, отрезая его от списка temp = pLastId->mkid.cb; pLastId->mkid.cb = 0; IShellFolder *pFolder; pDesktopFolder->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder); // Получаем интерфейс IContextMenu для заданного файла/каталога // Примечание: относительно родительского объекта заданный файл/каталог идентифицируется // единственным элементом pLastId pLastId->mkid.cb = temp; IContextMenu *pContextMenu; pFolder->GetUIObjectOf( hWnd, 1, (LPCITEMIDLIST *)&pLastId, IID_IContextMenu, NULL, (void**)&pContextMenu); // Создаём меню HMENU hPopupMenu = CreatePopupMenu(); // Заполняем меню pContextMenu->QueryContextMenu(hPopupMenu, 0, 1, 0x7FFF, 0); // Отображаем меню UINT nCmd = TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, x, y, 0, hWnd, 0); // Выполняем команду (если она была выбрана) if(nCmd) { CMINVOKECOMMANDINFO ici; ZeroMemory(&ici, sizeof(CMINVOKECOMMANDINFO)); ici.cbSize = sizeof(CMINVOKECOMMANDINFO); ici.hwnd = hWnd; ici.lpVerb = MAKEINTRESOURCE(nCmd-1); ici.nShow = SW_SHOWNORMAL; pContextMenu->InvokeCommand(&ici); } // Получаем интерфейс IMalloc IMalloc *pMalloc; SHGetMalloc(&pMalloc); // Освобождаем память, выделенную для pidl pMalloc->Free(pidl); // Освобождаем все полученные интерфейсы pDesktopFolder->Release(); pFolder->Release(); pContextMenu->Release(); pMalloc->Release(); return; } |
Для преобразования строк из TCHAR в OLECHAR я воспользовался макросами из библиотеки ATL. Обратите внимание, что функция TrackPopupMenu вызывается с флагом TPM_RETURNCMD. Этот флаг сообщает функции, что она не должна посылать программе сообщение WM_COMMAND, а вместо этого должна вернуть идентификатор выбранной команды в вызывающую программу.
Функцию ShowContextMenu можно вызывать, например, из обработчика WM_CONTEXTMENU. Делается это так:
#include <windowsx.h> ... case WM_CONTEXTMENU: ShowContextMenu(hWnd, "C:\\command.com", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); |
В MFC обработчик выглядит аналогично:
void CMyView::OnContextMenu(CWnd* pWnd, CPoint point) { ShowContextMenu(pWnd->m_hWnd, "C:\\command.com", point.x, point.y); } |
Сообщений 10 Оценка 111 Оценить |