Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Programy obsługi menu skrótów są również znane jako programy obsługi menu kontekstowego lub programy obsługi czasowników. Procedura obsługi menu skrótów jest typem procedury obsługi typów plików.
Ten temat jest zorganizowany w następujący sposób:
- O czasownikach statycznych i dynamicznych
- jak programy obsługi menu skrótów współpracują z czasownikami dynamicznymi
- unikanie kolizji z powodu niekwalifikowanych nazw czasowników
- rejestrowanie obsługi menu skrótów za pomocą czasownika dynamicznego
- implementowanie interfejsu IContextMenu
- Tematy pokrewne
Informacje o czasownikach statycznych i dynamicznych
Zdecydowanie zachęcamy do zaimplementowania menu skrótów przy użyciu jednej ze statycznych metod czasowników. Zalecamy wykonanie instrukcji podanych w sekcji "Dostosowywanie menu skrótów przy użyciu czasowników statycznych" Tworzenie procedur obsługi menu kontekstowego. Aby uzyskać dynamiczne zachowanie dla czasowników statycznych w systemie Windows 7 lub nowszym, zobacz "Getting Dynamic Behavior for Static Verbs" (Uzyskiwanie dynamicznego zachowania dla czasowników statycznych) w Tworzenie programów obsługi menu kontekstowego. Aby uzyskać szczegółowe informacje na temat implementacji czasowników statycznych i których czasowników dynamicznych można uniknąć, zobacz Wybieranie czasownika statycznego lub dynamicznego dla menu skrótów.
Jeśli musisz rozszerzyć menu skrótów dla typu pliku, rejestrując czasownik dynamiczny dla typu pliku, postępuj zgodnie z instrukcjami podanymi w dalszej części tego tematu.
Notatka
Istnieją specjalne zagadnienia dotyczące 64-bitowego systemu Windows podczas rejestrowania programów obsługi, które działają w kontekście aplikacji 32-bitowych: gdy czasowniki powłoki są wywoływane w kontekście aplikacji 32-bitowej, podsystem WOW64 przekierowuje dostęp systemu plików do niektórych ścieżek. Jeśli program obsługi .exe jest przechowywany w jednej z tych ścieżek, nie jest dostępny w tym kontekście. W związku z tym, jako rozwiązanie, zapisz .exe w ścieżce, która nie zostanie przekierowana, lub zapisz wersję tymczasową .exe, która uruchamia rzeczywistą wersję.
Jak programy obsługi menu skrótów działają z czasownikami dynamicznymi
Oprócz IUnknown, programy obsługi menu skrótów eksportują następujące dodatkowe interfejsy do obsługi komunikatów potrzebnych do zaimplementowania elementów menu tworzonych przez właściciela.
- IShellExtInit (obowiązkowe)
- IContextMenu (obowiązkowe)
- IContextMenu2 (opcjonalnie)
- IContextMenu3 (opcjonalnie)
Aby uzyskać więcej informacji na temat elementów menu rysowanych przez właściciela, zobacz sekcję Creating Owner-Drawn Menu Items (Tworzenie elementów menu Owner-Drawn) w temacie Using Menus.
Shell używa interfejsu IShellExtInit w celu zainicjowania procedury obsługi. Gdy powłoka wywołuje IShellExtInit::Initialize, przekazuje obiekt danych zawierający nazwę obiektu oraz wskaźnik do listy identyfikatorów elementów (PIDL) folderu, który zawiera plik. Parametr hkeyProgID to lokalizacja rejestru, w której zarejestrowano uchwyt menu skrótów. Metoda IShellExtInit::Initialize musi wyodrębnić nazwę pliku z obiektu danych i zapisać nazwę oraz wskaźnik folderu do listy identyfikatorów elementów (PIDL) do późniejszego użycia. Aby uzyskać więcej informacji na temat inicjowania obsługi, zobacz Implementacja IShellExtInit.
Gdy czasowniki są wyświetlane w menu skrótów, są one najpierw odnajdywane, a następnie prezentowane użytkownikowi, a na koniec wywoływane. Poniższa lista zawiera bardziej szczegółowe opisy tych trzech kroków:
- Powłoka wywołuje IContextMenu::QueryContextMenu, co zwraca zestaw czasowników, które mogą być oparte na stanie elementów lub systemu.
- System przekazuje uchwyt HMENU, za pomocą którego metoda może dodawać elementy do menu skrótów.
- Jeśli użytkownik kliknie jeden z elementów programu obsługi, powłoka uruchamia IContextMenu::InvokeCommand. Program obsługi może następnie wykonać odpowiednie polecenie.
Unikanie kolizji z powodu niekwalifikowanych nazw czasowników
Ze względu na to, że czasowniki są rejestrowane na typ, dla czasowników w różnych elementach można używać tej samej nazwy czasownika. Dzięki temu aplikacje mogą odwoływać się do typowych czasowników niezależnie od typu elementu. Chociaż ta funkcja jest przydatna, użycie niekwalifikowanych nazw może spowodować kolizje z wieloma niezależnymi dostawcami oprogramowania (ISV), które wybierają tę samą nazwę czasownika. Aby tego uniknąć, zawsze poprzedzaj czasowniki nazwą niezależnego dostawcy oprogramowania (ISV) w następujący sposób:
ISV_Name.verb
Zawsze używaj określonego identyfikatora progID aplikacji. Przyjęcie konwencji mapowania rozszerzenia nazwy pliku na ProgID dostarczony przez niezależnego dostawcę oprogramowania zapobiega potencjalnym kolizjom. Jednak ponieważ niektóre typy elementów nie używają tego mapowania, istnieje potrzeba użycia unikatowych nazw dostawcy. Podczas dodawania czasownika do istniejącego identyfikatora ProgID, który może już mieć ten czasownik zarejestrowany, musisz najpierw usunąć klucz rejestru dla starego czasownika przed dodaniem własnego czasownika. Należy to zrobić, aby uniknąć scalania informacji o czasowniku z dwóch czasowników. Niepowodzenie w tym celu powoduje nieprzewidywalne zachowanie.
Rejestrowanie procedury obsługi menu skrótów za pomocą polecenia dynamicznego
Programy obsługi menu skrótów są skojarzone z typem pliku lub folderem. W przypadku typów plików program obsługi jest rejestrowany pod poniższym podkluczem.
HKEY_CLASSES_ROOT
Program ID
shellex
ContextMenuHandlers
Aby skojarzyć obsługę menu kontekstowego z typem pliku lub folderem, najpierw utwórz podklucz w podkluczu ContextMenuHandlers. Nazwij podklucz programu obsługi i ustaw wartość domyślną podklucza na postać ciągu identyfikatora klasy programu obsługi (CLSID).
Następnie, aby skojarzyć program obsługi menu skrótów z różnymi rodzajami folderów, zarejestruj program obsługi w taki sam sposób, jak w przypadku typu pliku, ale pod podkluczem FolderType, jak pokazano w poniższym przykładzie.
HKEY_CLASSES_ROOT
FolderType
shellex
ContextMenuHandlers
Aby uzyskać więcej informacji na temat typów folderów, dla których można zarejestrować programy obsługi, zobacz Registering Shell Extension Handlers.
Jeśli typ pliku ma skojarzone menu skrótów, to dwukrotne kliknięcie obiektu zwykle uruchamia domyślne polecenie, a programu obsługi IContextMenu::QueryContextMenu metoda nie jest wywoływana. Aby określić, że metoda IContextMenu::QueryContextMenu powinna być wywoływana, gdy obiekt jest dwukrotnie kliknięty, utwórz podklucz pod CLSID programu obsługi podklucz, jak pokazano poniżej.
HKEY_CLASSES_ROOT
CLSID
{00000000-1111-2222-3333-444444444444}
shellex
MayChangeDefaultMenu
Po dwukrotnym kliknięciu obiektu skojarzonego z procedurą obsługi, wywoływana jest funkcja IContextMenu::QueryContextMenu z flagą CMF_DEFAULTONLY ustawioną w parametrze uFlags.
Programy obsługi menu skrótów powinny ustawić podklucz MayChangeDefaultMenu tylko wtedy, gdy może być konieczna zmiana domyślnego polecenia menu skrótów. Ustawienie tego podklucza wymusza załadowanie przez system biblioteki DLL programu obsługi po dwukrotnym kliknięciu skojarzonego elementu. Jeśli obsługujący nie zmienia czasownika domyślnego, nie należy ustawiać tego podklucza, ponieważ powoduje to niepotrzebne załadowanie biblioteki DLL przez system.
Poniższy przykład ilustruje wpisy rejestru, które umożliwiają obsługę menu skrótów dla typu pliku myp. Podklucz clSID programu obsługi zawiera podklucz MayChangeDefaultMenu w celu zagwarantowania, że program obsługi jest wywoływany, gdy użytkownik dwukrotnie kliknie powiązany obiekt.
HKEY_CLASSES_ROOT
.myp
(Default) = MyProgram.1
CLSID
{00000000-1111-2222-3333-444444444444}
InProcServer32
(Default) = C:\MyDir\MyCommand.dll
ThreadingModel = Apartment
shellex
MayChangeDefaultMenu
MyProgram.1
(Default) = MyProgram Application
shellex
ContextMenuHandler
MyCommand = {00000000-1111-2222-3333-444444444444}
Implementowanie interfejsu IContextMenu
IContextMenu jest najbardziej zaawansowaną, ale także najbardziej skomplikowaną metodą implementacji. Zdecydowanie zalecamy zaimplementowanie czasownika przy użyciu jednej ze statycznych metod czasownika. Aby uzyskać więcej informacji, zobacz Wybieranie czasownika statycznego lub dynamicznego dla menu skrótów. IContextMenu ma trzy metody, GetCommandString, InvokeCommandi QueryContextMenu, które zostały szczegółowo omówione tutaj.
IContextMenu::GetCommandString — Metoda
Metoda IContextMenu::GetCommandString programu obsługi jest używana do zwracania kanonicznej nazwy czasownika. Ta metoda jest opcjonalna. W systemie Windows XP i starszych wersjach systemu Windows, gdy Eksplorator Windows ma pasek stanu, ta metoda służy do pobierania tekstu pomocy wyświetlanego na pasku stanu dla elementu menu.
Parametr idCmd przechowuje przesunięcie identyfikatora polecenia zdefiniowanego podczas wywołania elementu IContextMenu::QueryContextMenu. Jeśli zażądano ciągu pomocy, uFlags zostanie ustawione na wartość GCS_HELPTEXTW. Skopiuj ciąg pomocy do buforu pszName, rzutując go na PWSTR. Ciąg czasowników jest żądany przez ustawienie uFlags na GCS_VERBW. Skopiuj odpowiedni ciąg do pszName, tak samo jak w przypadku ciągu pomocy. Flagi GCS_VALIDATEA i GCS_VALIDATEW nie są używane przez programy obsługi menu skrótów.
Poniższy przykład przedstawia prostą implementację IContextMenu::GetCommandString, która odpowiada przykładowi IContextMenu::QueryContextMenu, jak to opisano w sekcji IContextMenu::QueryContextMenu Method tego tematu. Ponieważ program obsługi dodaje tylko jeden element menu, istnieje tylko jeden zestaw ciągów, które można zwrócić. Metoda sprawdza, czy idCmd jest prawidłowa, a jeśli tak, zwraca żądany ciąg.
FunkcjastringCchCopysłuży do kopiowania żądanego ciągu do pszName, aby upewnić się, że skopiowany ciąg nie przekracza rozmiaru buforu określonego przez cchName. W tym przykładzie zaimplementowano obsługę tylko wartości Unicode uFlags, ponieważ tylko te zostały użyte w Eksploratorze Windows od systemu Windows 2000.
IFACEMETHODIMP CMenuExtension::GetCommandString(UINT idCommand,
UINT uFlags,
UINT *pReserved,
PSTR pszName,
UINT cchName)
{
HRESULT hr = E_INVALIDARG;
if (idCommand == IDM_DISPLAY)
{
switch (uFlags)
{
case GCS_HELPTEXTW:
// Only useful for pre-Vista versions of Windows that
// have a Status bar.
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
cchName,
L"Display File Name");
break;
case GCS_VERBW:
// GCS_VERBW is an optional feature that enables a caller
// to discover the canonical name for the verb passed in
// through idCommand.
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
cchName,
L"DisplayFileName");
break;
}
}
return hr;
}
IContextMenu::InvokeCommand — Metoda
Ta metoda jest wywoływana, gdy użytkownik kliknie element menu, aby poinformować program obsługi o uruchomieniu skojarzonego polecenia. Parametr pici wskazuje strukturę zawierającą wymagane informacje.
Mimo że pici jest zadeklarowany w pliku Shlobj.h jako struktura CMINVOKECOMMANDINFO, w praktyce często wskazuje na strukturę CMINVOKECOMMANDINFOEX. Ta struktura jest rozszerzoną wersją CMINVOKECOMMANDINFO i ma kilka dodatkowych członków, które umożliwiają przekazywanie ciągów Unicode.
Sprawdź cbSize członek pici, aby określić, która struktura została przekazana. Jeśli jest to struktura CMINVOKECOMMANDINFOEX i element członkowski fMask ma ustawioną flagę CMIC_MASK_UNICODE, rzutuj pici na CMINVOKECOMMANDINFOEX. Dzięki temu aplikacja może korzystać z informacji Unicode zawartych w pięciu ostatnich elementach struktury.
Składnik lpVerb lub lpVerbW jest używany do identyfikacji polecenia do wykonania. Polecenia są identyfikowane na jeden z następujących dwóch sposobów:
- Na podstawie ciągu czasownika w poleceniu
- Przesunięcie według identyfikatora polecenia
Aby rozróżnić te dwa przypadki, sprawdź najwyższy segment słowa lpVerb dla przypadku ANSI lub lpVerbW dla przypadku Unicode. Jeśli wyraz o wysokiej kolejności jest niezerowy, lpVerb lub lpVerbW przechowuje ciąg czasownika. Jeśli wyraz o wysokiej kolejności ma wartość zero, przesunięcie polecenia znajduje się w wyrazie o niskiej kolejności lpVerb.
W poniższym przykładzie pokazano prostą implementację IContextMenu::InvokeCommand, która odpowiada przykładom IContextMenu::QueryContextMenu i IContextMenu::GetCommandString podanym przed i po tej sekcji. Metoda najpierw określa, która struktura jest przekazywana. Następnie określa, czy polecenie jest identyfikowane przez przesunięcie, czy czasownik. Jeśli lpVerb lub lpVerbW przechowuje prawidłowy czasownik lub przesunięcie, metoda wyświetla komunikat.
STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
BOOL fEx = FALSE;
BOOL fUnicode = FALSE;
if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
{
fEx = TRUE;
if((lpcmi->fMask & CMIC_MASK_UNICODE))
{
fUnicode = TRUE;
}
}
if( !fUnicode && HIWORD(lpcmi->lpVerb))
{
if(StrCmpIA(lpcmi->lpVerb, m_pszVerb))
{
return E_FAIL;
}
}
else if( fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW))
{
if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb))
{
return E_FAIL;
}
}
else if(LOWORD(lpcmi->lpVerb) != IDM_DISPLAY)
{
return E_FAIL;
}
else
{
MessageBox(lpcmi->hwnd,
"The File Name",
"File Name",
MB_OK|MB_ICONINFORMATION);
}
return S_OK;
}
IContextMenu::QueryContextMenu — Metoda
Powłoka wywołuje IContextMenu::QueryContextMenu, aby włączyć procedurę obsługi menu skrótów w celu dodania elementów menu do menu. Przechodzi w dojściu HMENU w parametrze hmenu. Parametr indexMenu jest ustawiony na indeks, który ma być używany dla pierwszego elementu menu, który ma zostać dodany.
Wszystkie elementy menu dodane przez program obsługi muszą mieć identyfikatory mieszczące się w zakresie wartości parametrów idCmdFirst i idCmdLast. Zazwyczaj pierwszy identyfikator polecenia jest ustawiony na idCmdFirst, który jest zwiększany o jeden (1) dla każdego dodatkowego polecenia. Ta praktyka pomaga uniknąć przekroczenia idCmdLast i maksymalizuje liczbę dostępnych identyfikatorów, jeśli powłoka wywołuje więcej niż jedną procedurę obsługi.
Przesunięcie polecenia identyfikatora elementu jest różnicą między identyfikatorem a wartością w idCmdFirst. Zapisz przesunięcie każdego elementu, który program obsługi dodaje do menu skrótów, ponieważ powłoka może użyć go do zidentyfikowania elementu, jeśli następnie wywołuje element IContextMenu::GetCommandString lub IContextMenu::InvokeCommand.
Należy również przypisać czasownik do każdego dodanego polecenia. Czasownik to ciąg znaków, którego można użyć zamiast przesunięcia, aby zidentyfikować polecenie, gdy wywoływana jest IContextMenu::InvokeCommand. Jest on również używany przez funkcje, takie jak ShellExecuteEx do wykonywania poleceń w menu kontekstowym.
Istnieją trzy flagi, które można przekazać za pośrednictwem parametru uFlags, które są istotne dla obsługujących menu kontekstowe. Zostały one opisane w poniższej tabeli.
| Flaga | Opis |
|---|---|
| CMF_DEFAULTONLY | Użytkownik wybrał domyślne polecenie, zwykle klikając dwukrotnie obiekt. IContextMenu::QueryContextMenu powinna zwrócić kontrolkę do powłoki bez modyfikowania menu. |
| CMF_NODEFAULT | Żaden element w menu nie powinien być elementem domyślnym. Metoda powinna dodać swoje polecenia do menu. |
| CMF_NORMAL | Menu skrótów będzie wyświetlane normalnie. Metoda powinna dodać polecenia do menu. |
Użyj InsertMenu lub InsertMenuItem, aby dodać elementy menu do listy. Następnie zwróć wartość HRESULT z ważnością ustawioną na SEVERITY_SUCCESS. Ustaw wartość kodu na przesunięcie największego przypisanego identyfikatora polecenia, zwiększone o jeden (1). Załóżmy na przykład, że idCmdFirst jest ustawiona na 5 i dodajesz trzy elementy do menu z identyfikatorami poleceń 5, 7 i 8. Wartość zwracana powinna być MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1).
Poniższy przykład przedstawia prostą implementację IContextMenu::QueryContextMenu, która wstawia jedno polecenie. Offset identyfikatora polecenia to IDM_DISPLAY, który ustawiono na zero. Zmienne m_pszVerb i m_pwszVerb to zmienne prywatne używane do przechowywania skojarzonego ciągu czasownika niezależnego od języka zarówno w formatach ANSI, jak i Unicode.
#define IDM_DISPLAY 0
STDMETHODIMP CMenuExtension::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
HRESULT hr;
if(!(CMF_DEFAULTONLY & uFlags))
{
InsertMenu(hMenu,
indexMenu,
MF_STRING | MF_BYPOSITION,
idCmdFirst + IDM_DISPLAY,
"&Display File Name");
hr = StringCbCopyA(m_pszVerb, sizeof(m_pszVerb), "display");
hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"display");
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_DISPLAY + 1));
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
}
Aby zapoznać się z innymi zadaniami implementacji czasowników, zobacz Tworzenie procedur obsługi menu kontekstowego.
Tematy pokrewne
-
menu skrótów (kontekstowych) i programy obsługi menu skrótów
-
wybieranie czasownika statycznego lub dynamicznego dla menu skrótów
-
najlepsze rozwiązania dotyczące programów obsługi menu skrótów i zleceń wielokrotnego wyboru