Cara Menerapkan Antarmuka IContextMenu
IContextMenu adalah antarmuka yang paling kuat tetapi juga paling rumit untuk diterapkan. Kami sangat menyarankan Anda menerapkan kata kerja dengan menggunakan salah satu metode kata kerja statis. Untuk informasi selengkapnya, lihat Memilih Metode Menu Pintasan Statis atau Dinamis. IContextMenu memiliki tiga metode, GetCommandString, InvokeCommand, dan QueryContextMenu, yang dibahas di sini secara rinci.
- C++
- Kata Kerja Statis
- Menu Pintasan
Metode IContextMenu::GetCommandString handler digunakan untuk mengembalikan nama kanonis untuk kata kerja. Metode ini bersifat opsional. Di Windows XP dan versi Windows yang lebih lama, ketika Windows Explorer memiliki bilah Status, metode ini digunakan untuk mengambil teks bantuan yang ditampilkan di bilah Status untuk item menu.
Parameter idCmd menyimpan offset pengidentifikasi dari perintah yang sudah ditetapkan ketika IContextMenu::QueryContextMenu dipanggil. Jika string bantuan diminta, uFlags akan diset menjadi GCS_HELPTEXTW. Salin string bantuan ke pszName buffer, transmisikan ke PWSTR. String kata kerja diminta dengan mengatur uFlags ke GCS_VERBW. Salin string yang sesuai ke pszName, persis seperti string bantuan. Penanda GCS_VALIDATEA dan GCS_VALIDATEW tidak digunakan oleh pengendali menu pintasan.
Contoh berikut menunjukkan implementasi sederhana GetCommandString yang sesuai dengan contoh QueryContextMenu yang diberikan di bagian IContextMenu::QueryContextMenu Method topik ini. Karena handler hanya menambahkan satu item menu, hanya ada satu set string yang dapat dikembalikan. Metode ini menguji apakah idCmd valid dan, jika ya, mengembalikan string yang diminta.
FungsiStringCchCopy digunakan untuk menyalin string yang diminta ke pszName untuk memastikan bahwa string yang disalin tidak melebihi ukuran buffer yang ditentukan oleh cchName. Contoh ini mengimplementasikan dukungan hanya untuk nilai Unicode uFlags, karena hanya yang telah digunakan di Windows Explorer sejak 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 that is passed in
// through idCommand.
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
cchName,
L"DisplayFileName");
break;
}
}
return hr;
}
Metode ini dipanggil ketika pengguna mengklik item menu untuk memberi tahu handler untuk menjalankan perintah terkait. Parameter pici menunjuk ke struktur yang berisi informasi yang diperlukan untuk menjalankan perintah.
Meskipun pici dinyatakan dalam Shlobj.h sebagai strukturCMINVOKECOMMANDINFO, dalam praktiknya sering menunjuk ke struktur CMINVOKECOMMANDINFOEX. Struktur ini adalah versi yang diperluas dari CMINVOKECOMMANDINFO dan memiliki beberapa anggota tambahan yang memungkinkan untuk meneruskan string Unicode.
Periksa anggota cbSize dari pici untuk menentukan struktur mana yang diteruskan. Jika ini adalah strukturCMINVOKECOMMANDINFOEXdan anggota fMask memiliki set bendera CMIC_MASK_UNICODE, cast pici ke CMINVOKECOMMANDINFOEX. Ini memungkinkan aplikasi Anda untuk menggunakan informasi Unicode yang terkandung dalam lima anggota terakhir struktur.
Struktur dengan anggota lpVerb atau lpVerbW digunakan untuk mengidentifikasi perintah yang akan dijalankan. Perintah diidentifikasi dalam salah satu dari dua cara berikut:
- Berdasarkan string kata kerja dari perintah
- Dengan offset ID perintah
Untuk membedakan antara kedua kasus ini, periksa kata urutan tinggi lpVerb untuk kasus ANSI atau lpVerbW untuk kasus Unicode. Jika kata urutan tinggi bukan nol, lpVerb atau lpVerbW memegang string kata kerja. Jika kata urutan tinggi adalah nol, offset perintah berada dalam kata urutan rendah lpVerb.
Contoh berikut menunjukkan implementasi sederhana IContextMenu::InvokeCommand yang sesuai dengan IContextMenu::QueryContextMenu dan IContextMenu::GetCommandString contoh yang diberikan sebelum dan sesudah bagian ini. Pertama-tama, metode ini menentukan struktur mana yang sedang diteruskan. Kemudian menentukan apakah perintah diidentifikasi berdasarkan offset atau berdasarkan kata kerjanya. Jika lpVerb atau lpVerbW menyimpan kata kerja atau offset yang valid, metode akan menampilkan kotak pesan.
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;
}
Shell memanggil IContextMenu::QueryContextMenu untuk memungkinkan handler menu pintasan menambahkan elemen menunya ke menu. Ini memasukkan handle HMENU di dalam parameter hmenu. Parameter indexMenu diatur ke indeks yang akan digunakan untuk item menu pertama yang akan ditambahkan.
Item menu apa pun yang ditambahkan oleh handler harus memiliki pengidentifikasi yang berada di antara nilai dalam parameter idCmdFirst dan idCmdLast. Biasanya, pengidentifikasi perintah pertama diatur ke idCmdFirst, yang bertambah satu (1) untuk setiap perintah tambahan. Praktik ini membantu Anda menghindari melebihi idCmdLast dan memaksimalkan jumlah pengidentifikasi yang tersedia jika Shell memanggil lebih dari satu handler.
perintah offset untuk pengidentifikasi item merupakan selisih antara pengidentifikasi dan nilai dalam idCmdFirst. Simpan offset setiap item yang ditambahkan handler Anda ke menu pintasan, karena Shell mungkin menggunakan offset untuk mengidentifikasi item jika kemudian memanggil IContextMenu::GetCommandString atau IContextMenu::InvokeCommand.
Anda juga harus menetapkan kata kerja ke setiap perintah yang Anda tambahkan. Kata kerja adalah rangkaian karakter yang dapat digunakan alih-alih offset untuk mengidentifikasi perintah ketika InvokeCommand dipanggil. Ini juga digunakan oleh fungsi seperti ShellExecuteEx untuk menjalankan perintah menu pintasan.
Ada tiga flags yang dapat diteruskan melalui parameter uFlags yang relevan dengan penangan menu pintasan. Mereka dijelaskan dalam tabel berikut.
Bendera | Deskripsi |
---|---|
CMF_DEFAULTONLY | Pengguna telah memilih perintah default, biasanya dengan mengklik dua kali objek. IContextMenu::QueryContextMenu harus mengembalikan kontrol ke Shell tanpa memodifikasi menu. |
CMF_NODEFAULT | Tidak ada item dalam menu yang harus menjadi item default. Metode harus menambahkan perintahnya ke dalam menu. |
CMF_NORMAL | Menu pintasan akan ditampilkan secara normal. Metode harus menambahkan perintahnya ke menu. |
Gunakan InsertMenu atau InsertMenuItem untuk menambahkan item menu ke daftar. Kemudian kembalikan nilai HRESULT dengan tingkat keparahan yang diatur menjadi SEVERITY_SUCCESS. Atur nilai kode ke offset pengidentifikasi perintah terbesar yang ditetapkan, ditambah satu (1). Misalnya, asumsikan bahwa idCmdFirst diatur ke 5 dan Anda menambahkan tiga item ke menu dengan pengidentifikasi perintah 5, 7, dan 8. Nilai yang dikembalikan harus MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 + 1).
Contoh berikut menunjukkan implementasi sederhana QueryContextMenu yang menyisipkan satu perintah. Offset identifikasi untuk perintah IDM_DISPLAY, yang diatur ke nol. Variabel m_pszVerb dan m_pwszVerb adalah variabel privat yang digunakan untuk menyimpan string kata kerja independen bahasa terkait dalam format ANSI dan 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));}
Untuk tugas implementasi verba lainnya, lihat Membuat Pengelola Menu Pintasan.