Расширенный код для статьи:
Как вывести для файла контекстное меню, как в эксплорере?
Для того чтобы сделать меню, действительно как в эксплорере, т.е. с работающими пунктами New, SendTo и т.д.
#include <shlobj.h>
#include <atlbase.h>
...
void ShowContextMenu2(HWND hWnd, LPCTSTR pszPath, int x, int y,IContextMenu2** ppContextMenu2)
{
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);
if(ppContextMenu2)
{
pContextMenu->QueryInterface(IID_IContextMenu2,(LPVOID*)ppContextMenu2);
}
// Создаём меню
HMENU hPopupMenu = CreatePopupMenu();
// Заполняем меню
pContextMenu->QueryContextMenu(hPopupMenu, 0, 1, 0x7FFF, CMF_EXPLORE|CMF_CANRENAME);
// Отображаем меню
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);
// Освобождаем все полученные интерфейсы
if(ppContextMenu2&&*ppContextMenu2)
{
(*ppContextMenu2)->Release;
*ppContextMenu2 = NULL;
}
pDesktopFolder->Release();
pFolder->Release();
pContextMenu->Release();
pMalloc->Release();
return;
}
К окну hWnd надо привязать, интерфейс IContextMenu2 *m_pContextMenu2 и в обработчик WindowProc для hWnd, добавил такой код:
(Пример для MFC, для Win32API я думаю код понятен)
LRESULT CMyView::WindowProc(UINT message,WPARAM wParam,LPARAM lParam)
{
if(m_pContextMenu2)
if(message==WM_INITMENUPOPUP||message==WM_DRAWITEM||message==WM_MENUCHAR||message==WM_MEASUREITEM)
{
return m_pContextMenu2->HandleMenuMsg(message, wParam, lParam);
}
return CView::WindowProc(message,wParam,lParam);
}
Использование (Посмотрите как преобразилось меню ):
Win32API:
...
IContextMenu2 *m_pContextMenu2;
...
case WM_CONTEXTMENU:
ShowContextMenu2(hWnd, "C:\\command.com", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),&m_pContextMenu2);
MFC:
...
IContextMenu2 *m_pContextMenu2;
...
void CMyView::OnContextMenu(CWnd* pWnd, CPoint point)
{
ShowContextMenu2(pWnd->GetSafeHwnd(), "C:\\command.com", point.x, point.y, &m_pContextMenu2);
}
Здравствуйте OlegO, Вы писали:
OO>Расширенный код для статьи: Как вывести для файла контекстное меню, как в эксплорере?
OO>LRESULT CMyView::WindowProc(UINT message,WPARAM wParam,LPARAM lParam)
OO>{
OO> if(m_pContextMenu2)
OO> if(message==WM_INITMENUPOPUP||message==WM_DRAWITEM||message==WM_MENUCHAR||message==WM_MEASUREITEM)
OO> {
OO> return m_pContextMenu2->HandleMenuMsg(message, wParam, lParam);
OO> }
OO>
OO> return CView::WindowProc(message,wParam,lParam);
OO>}
OO>[/ccode]
OO>Использование (Посмотрите как преобразилось меню ):
У меня почему-то ничего не изменилось.
Код обработчика вызывается только один раз для message==WM_INITMENUPOPUP и m_pContextMenu2->HandleMenuMsg возвращает E_NOTIMPL.
Система WinXP, IE 6.0.
Что, вообще, должно измениться-то?
Может, надо как-то систему настроить или какие-то файлы должны быть особые?
Здравствуйте ilya123, Вы писали:
I>У меня почему-то ничего не изменилось.
I>Код обработчика вызывается только один раз для message==WM_INITMENUPOPUP и m_pContextMenu2->HandleMenuMsg возвращает E_NOTIMPL.
I>Система WinXP, IE 6.0.
Проверял на WinXP, W2K, W98, NT4 c IE (5.0 — 6.0)
I>Что, вообще, должно измениться-то?
Этот код позволяет отображать расширениям Эксплорера элементы меню (стилем OwnerDraw и т.д.).
Наглядный пример (должен у всех работать
), в частноти у меня после добавления этого кода стало нормально отображаться содержимое меню
SendTo.
В старой версии
SendTo->SendTo, в новой
SendTo->3 1/2 Floppy, ....
I>Может, надо как-то систему настроить или какие-то файлы должны быть особые?
Да вроде нет.
Ну и совсем чтобы меню было как в эксплорере, можно по анологии обработать интерфейс
IContextMenu3 и "повесить" его на событие WM_MENUCHAR.
Здравствуйте OlegO, Вы писали:
I>>Что, вообще, должно измениться-то?
OO>Этот код позволяет отображать расширениям Эксплорера элементы меню (стилем OwnerDraw и т.д.).
OO>Наглядный пример (должен у всех работать ), в частноти у меня после добавления этого кода стало нормально отображаться содержимое меню SendTo.
OO>В старой версии SendTo->SendTo, в новой SendTo->3 1/2 Floppy, ....
Сейчас работает!
Наверное, был какое-то глюк с системой.
Еще изменилось
Open With.
Здравствуйте OlegO, Вы писали:
OO>Расширенный код для статьи: Как вывести для файла контекстное меню, как в эксплорере?
OO>Для того чтобы сделать меню, действительно как в эксплорере, т.е. с работающими пунктами New, SendTo и т.д.
JFYI
http://www.maddogsw.com/programmers/
там лежат исходники утилиты, которая выводит контекстное меню из консоли.