Menyesuaikan Menu Pintasan Menggunakan Kata Kerja Dinamis

Penangan menu pintasan juga dikenal sebagai penangan menu konteks atau penangan kata kerja. Penangan menu pintasan adalah jenis penangan tipe file.

Topik ini diatur sebagai berikut:

Tentang Kata Kerja Statis dan Dinamis

Kami sangat mendorong Anda untuk menerapkan menu pintasan menggunakan salah satu metode kata kerja statis. Kami menyarankan agar Anda mengikuti instruksi yang disediakan di bagian "Menyesuaikan Menu Pintasan menggunakan Kata Kerja Statis" dari Membuat Penangan Menu Konteks. Untuk mendapatkan perilaku dinamis untuk kata kerja statis di Windows 7 dan yang lebih baru, lihat "Mendapatkan Perilaku Dinamis untuk Kata Kerja Statis" di Membuat Penangan Menu Konteks. Untuk detail tentang implementasi kata kerja statis, dan kata kerja dinamis mana yang harus dihindari, lihat Memilih Kata Kerja Statis atau Dinamis untuk Menu Pintasan Anda.

Jika Anda harus memperluas menu pintasan untuk jenis file dengan mendaftarkan kata kerja dinamis untuk jenis file, maka ikuti instruksi yang diberikan nanti dalam topik ini.

Catatan

Ada pertimbangan khusus untuk Windows 64-bit saat mendaftarkan handler yang berfungsi dalam konteks aplikasi 32-bit: ketika kata kerja Shell dipanggil dalam konteks aplikasi 32-bit, subsistem WOW64 mengalihkan akses sistem file ke beberapa jalur. Jika handler .exe Anda disimpan di salah satu jalur tersebut, itu tidak dapat diakses dalam konteks ini. Oleh karena itu, sebagai pekerjaan, simpan .exe Anda di jalur yang tidak dialihkan, atau simpan versi stub dari .exe Anda yang meluncurkan versi nyata.

 

Cara Kerja Penangan Menu Pintasan dengan Kata Kerja Dinamis

Selain IUnknown, penangan menu pintasan mengekspor antarmuka tambahan berikut untuk menangani pesan yang diperlukan untuk menerapkan item menu yang digambar pemilik:

Untuk informasi selengkapnya tentang item menu yang digambar pemilik, lihat bagian Membuat Item Menu Gambar Pemilik di Menggunakan Menu.

Shell menggunakan antarmuka IShellExtInit untuk menginisialisasi handler. Saat Shell memanggil IShellExtInit::Initialize, Shell meneruskan objek data dengan nama objek dan penunjuk ke daftar pengidentifikasi item (PIDL) folder yang berisi file. Parameter hkeyProgID adalah lokasi registri tempat handel menu pintasan terdaftar. Metode IShellExtInit::Initialize harus mengekstrak nama file dari objek data dan menyimpan nama dan penunjuk folder ke daftar pengidentifikasi item (PIDL) untuk digunakan nanti. Untuk informasi selengkapnya tentang inisialisasi handler, lihat Menerapkan IShellExtInit.

Ketika kata kerja disajikan di menu pintasan, mereka pertama kali ditemukan, kemudian disajikan kepada pengguna, dan akhirnya dipanggil. Daftar berikut ini menjelaskan tiga langkah ini secara lebih rinci:

  1. Shell memanggil IContextMenu::QueryContextMenu, yang mengembalikan sekumpulan kata kerja yang dapat didasarkan pada status item atau sistem.
  2. Sistem melewati handel HMENU yang dapat digunakan metode untuk menambahkan item ke menu pintasan.
  3. Jika pengguna mengklik salah satu item handler, Shell memanggil IContextMenu::InvokeCommand. Handler kemudian dapat menjalankan perintah yang sesuai.

Menghindari Tabrakan Karena Nama Kata Kerja yang Tidak Memenuhi Syarat

Karena kata kerja terdaftar per jenis, nama kata kerja yang sama dapat digunakan untuk kata kerja pada item yang berbeda. Melakukannya memungkinkan aplikasi untuk merujuk ke kata kerja umum yang independen dari jenis item. Meskipun fungsionalitas ini berguna, penggunaan nama yang tidak memenuhi syarat dapat mengakibatkan tabrakan dengan beberapa vendor perangkat lunak independen (ISV) yang memilih nama kata kerja yang sama. Untuk menghindari hal ini, selalu awali kata kerja dengan nama ISV sebagai berikut:

ISV_Name.verb

Selalu gunakan ProgID khusus aplikasi. Mengadopsi konvensi pemetaan ekstensi nama file ke ISV yang disediakan ProgID menghindari potensi tabrakan. Namun, karena beberapa jenis item tidak menggunakan pemetaan ini, perlu adanya nama unik vendor. Saat menambahkan kata kerja ke ProgID yang ada yang mungkin sudah memiliki kata kerja yang terdaftar, Anda harus terlebih dahulu menghapus kunci registri untuk kata kerja lama sebelum menambahkan kata kerja Anda sendiri. Anda harus melakukannya untuk menghindari penggabungan informasi kata kerja dari dua kata kerja. Kegagalan untuk melakukannya menghasilkan perilaku yang tidak dapat diprediksi.

Mendaftarkan Penangan Menu Pintasan dengan Kata Kerja Dinamis

Penangan menu pintasan dikaitkan dengan tipe file atau folder. Untuk jenis file, handler didaftarkan di bawah subkunji berikut.

HKEY_CLASSES_ROOT
   Program ID
      shellex
         ContextMenuHandlers

Untuk mengaitkan handler menu pintasan dengan jenis file atau folder, pertama-tama buat subkunci di bawah subkunci ContextMenuHandlers . Beri nama subkunci untuk handler, dan atur nilai default subkunci ke bentuk string GUID pengidentifikasi kelas handler (CLSID).

Kemudian untuk mengaitkan handler menu pintasan dengan berbagai jenis folder, daftarkan handler dengan cara yang sama seperti yang Anda lakukan untuk jenis file, tetapi di bawah subkunjuk FolderType seperti yang ditunjukkan dalam contoh berikut.

HKEY_CLASSES_ROOT
   FolderType
      shellex
         ContextMenuHandlers

Untuk informasi selengkapnya tentang jenis folder mana yang dapat Anda daftarkan handlernya, lihat Mendaftarkan Penangan Ekstensi Shell.

Jika jenis file memiliki menu pintasan yang terkait dengannya, maka mengklik dua kali objek biasanya meluncurkan perintah default, dan metode IContextMenu::QueryContextMenu handler tidak dipanggil. Untuk menentukan bahwa metode IContextMenu::QueryContextMenu handler harus dipanggil saat objek diklik dua kali, buat subkunci di bawah subkunci CLSID handler seperti yang ditunjukkan di sini.

HKEY_CLASSES_ROOT
   CLSID
      {00000000-1111-2222-3333-444444444444}
         shellex
            MayChangeDefaultMenu

Ketika objek yang terkait dengan handler diklik dua kali, IContextMenu::QueryContextMenu dipanggil dengan bendera CMF_DEFAULTONLY yang diatur dalam parameter uFlags.

Penangan menu pintasan harus mengatur subkunci MayChangeDefaultMenu hanya jika mereka mungkin perlu mengubah kata kerja default menu pintasan. Mengatur subkuntah ini memaksa sistem memuat DLL handler ketika item terkait diklik dua kali. Jika handler Anda tidak mengubah kata kerja default, Anda tidak boleh mengatur subkuntah ini karena melakukannya menyebabkan sistem memuat DLL Anda tidak perlu.

Contoh berikut mengilustrasikan entri registri yang mengaktifkan penangan menu pintasan untuk jenis file .myp. Subkunci CLSID handler menyertakan subkunci MayChangeDefaultMenu untuk menjamin bahwa handler dipanggil ketika pengguna mengklik dua kali objek terkait.

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}

Menerapkan Antarmuka IContextMenu

IContextMenu adalah metode yang paling kuat tetapi juga yang paling rumit untuk diterapkan. Kami sangat menyarankan Anda menerapkan kata kerja dengan menggunakan salah satu metode kata kerja statis. Untuk informasi selengkapnya, lihat Memilih Kata Kerja Statis atau Dinamis untuk Menu Pintasan Anda. IContextMenu memiliki tiga metode, GetCommandString, InvokeCommand, dan QueryContextMenu, yang dibahas di sini secara rinci.

IContextMenu::GetCommandString Method

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 ditentukan ketika IContextMenu::QueryContextMenu dipanggil. Jika string bantuan diminta, uFlags akan diatur ke GCS_HELPTEXTW. Salin string bantuan ke buffer pszName , transmisikan ke PWSTR. String kata kerja diminta dengan mengatur uFlags ke GCS_VERBW. Salin string yang sesuai ke pszName, sama seperti string bantuan. Bendera GCS_VALIDATEA dan GCS_VALIDATEW tidak digunakan oleh penangan menu pintasan.

Contoh berikut menunjukkan implementasi sederhana IContextMenu::GetCommandString yang sesuai dengan contoh IContextMenu::QueryContextMenu yang diberikan di bagian Metode IContextMenu::QueryContextMenu dari topik ini. Karena handler hanya menambahkan satu item menu, hanya ada satu set string yang dapat dikembalikan. Metode menguji apakah idCmd valid dan, jika ya, mengembalikan string yang diminta.

Fungsi StringCchCopy digunakan untuk menyalin string yang diminta ke pszName untuk memastikan bahwa string yang disalin tidak melebihi ukuran buffer yang ditentukan oleh cchName. Contoh ini hanya menerapkan dukungan 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 passed in
                // through idCommand.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"DisplayFileName");
                break; 
        }
    }
    return hr;
}

IContextMenu::InvokeCommand Method

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.

Meskipun pici dinyatakan dalam Shlobj.h sebagai struktur CMINVOKECOMMANDINFO, 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 pici cbSize untuk menentukan struktur mana yang diteruskan. Jika itu adalah struktur CMINVOKECOMMANDINFOEX dan 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.

Anggota lpVerb atau lpVerbW struktur digunakan untuk mengidentifikasi perintah yang akan dijalankan. Perintah diidentifikasi dalam salah satu dari dua cara berikut:

  • Menurut string kata kerja perintah
  • Dengan offset pengidentifikasi 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 menyimpan 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 contoh IContextMenu::QueryContextMenu dan IContextMenu::GetCommandString yang diberikan sebelum dan sesudah bagian ini. Metode ini pertama-tama menentukan struktur mana yang sedang diteruskan. Kemudian menentukan apakah perintah diidentifikasi oleh offset atau 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;
}

Metode IContextMenu::QueryContextMenu

Shell memanggil IContextMenu::QueryContextMenu untuk mengaktifkan handler menu pintasan untuk menambahkan item menunya ke menu. Ini melewati handel HMENU dalam parameter hmenu . Parameter indexMenu diatur ke indeks yang akan digunakan untuk item menu pertama yang akan ditambahkan.

Setiap item menu 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.

Offset perintah pengidentifikasi item adalah perbedaan antara pengidentifikasi dan nilai di idCmdFirst. Simpan offset setiap item yang ditambahkan handler Anda ke menu pintasan karena Shell mungkin menggunakannya 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 string yang dapat digunakan alih-alih offset untuk mengidentifikasi perintah ketika IContextMenu::InvokeCommand dipanggil. Ini juga digunakan oleh fungsi seperti ShellExecuteEx untuk menjalankan perintah menu pintasan.

Ada tiga bendera yang dapat diteruskan melalui parameter uFlags yang relevan dengan penangan menu pintasan. File tersebut 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 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 ke 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 - 5 + 1).

Contoh berikut menunjukkan implementasi sederhana IContextMenu::QueryContextMenu yang menyisipkan satu perintah. Offset pengidentifikasi 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 kata kerja lainnya, lihat Membuat Penangan Menu Konteks.

Menu Pintasan (Konteks) dan Penangan Menu Pintasan

Kata kerja dan Asosiasi File

Memilih Kata Kerja Statis atau Dinamis untuk Menu Pintasan Anda

Praktik Terbaik untuk Penangan Menu Pintasan dan Beberapa Kata Kerja Pilihan

Membuat Penangan Menu Pintasan

Referensi Menu Pintasan