SRC: Как вывести для файла контекстное меню 2
От: OlegO Россия http://www.mediachase.ru
Дата: 26.09.02 07:51
Оценка: 3 (1)
Расширенный код для статьи: Как вывести для файла контекстное меню, как в эксплорере?

Для того чтобы сделать меню, действительно как в эксплорере, т.е. с работающими пунктами 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.
Re: SRC: Как вывести для файла контекстное меню 2
От: ilya123 Россия  
Дата: 06.10.02 18:16
Оценка:
Здравствуйте 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.
Что, вообще, должно измениться-то?
Может, надо как-то систему настроить или какие-то файлы должны быть особые?
Re[2]: SRC: Как вывести для файла контекстное меню 2
От: OlegO Россия http://www.mediachase.ru
Дата: 07.10.02 09:38
Оценка:
Здравствуйте 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>Может, надо как-то систему настроить или какие-то файлы должны быть особые?


Да вроде нет.
С уважением, OlegO.
Re: SRC: Как вывести для файла контекстное меню 2 Addon
От: OlegO Россия http://www.mediachase.ru
Дата: 07.10.02 10:03
Оценка:
Ну и совсем чтобы меню было как в эксплорере, можно по анологии обработать интерфейс IContextMenu3 и "повесить" его на событие WM_MENUCHAR.
С уважением, OlegO.
Re[3]: SRC: Как вывести для файла контекстное меню 2
От: ilya123 Россия  
Дата: 07.10.02 10:21
Оценка:
Здравствуйте OlegO, Вы писали:

I>>Что, вообще, должно измениться-то?


OO>Этот код позволяет отображать расширениям Эксплорера элементы меню (стилем OwnerDraw и т.д.).


OO>Наглядный пример (должен у всех работать ), в частноти у меня после добавления этого кода стало нормально отображаться содержимое меню SendTo.


OO>В старой версии SendTo->SendTo, в новой SendTo->3 1/2 Floppy, ....


Сейчас работает!
Наверное, был какое-то глюк с системой.
Еще изменилось Open With.
Re: SRC: Как вывести для файла контекстное меню 2
От: ilya123 Россия  
Дата: 13.10.02 21:29
Оценка:
Здравствуйте OlegO, Вы писали:

OO>Расширенный код для статьи: Как вывести для файла контекстное меню, как в эксплорере?


OO>Для того чтобы сделать меню, действительно как в эксплорере, т.е. с работающими пунктами New, SendTo и т.д.


JFYI
http://www.maddogsw.com/programmers/
там лежат исходники утилиты, которая выводит контекстное меню из консоли.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.