2010-09-23 19 views
11

Windows Gezgini'nde, bir dosyaya sağ tıklarsanız, 'Gönder ...' ve/veya 'Winzip ile zip dosyası gibi 3. taraf eylemleri gibi yerleşik öğeler içeren bir bağlam menüsü görüntülenir. Benim sorumuz:Windows kabuk içeriği menü öğelerine nasıl erişilir?

  • Belirli bir dosya için kullanılabilir menü öğelerinin tam listesi nasıl elde edilir?
  • Her menü öğesi için altyazı nasıl alınır?
  • Belirli bir disk dosyası için belirli bir menü maddesi eylemi nasıl çağırılır?

Teşekkürler!

[DÜZENLEME]: Diğer bilgiler kesinlikle yararlı olsa da, Delphi çözümü çok takdir edilecektir!

+0

kendi ortam menü öğelerini oluşturmak veya varolan menü öğelerini manipüle etmek istiyor musunuz? – Liton

+0

@Liton, kendi kabuk içeriği menü öğelerini oluşturmama, ancak varolan menü yerleşik öğesinde veya 3. bölüm öğelerinde değişiklik yapmak. –

cevap

9

Kabuk İçeriği menüsünü elde etmek için kullanılan anahtar, IContextMenu arabirimidir.

Daha fazla bilgi için bu harika makaleyi inceleyin Shell context menu support.

GÜNCELLEME

Delphi örnekleri için size JEDI JCL dan JclShell birimi (DisplayContextMenu fonksiyonunu kontrol edin) ve Delphi örnekleri klasöründe bulunmaktadır ShellCtrls birimini görebilirsiniz.

+0

Bağlantı için teşekkürler, ben kontrol edeceğim! –

+0

Merhaba RRUZ, JCL paketinden DisplayContextMenu funcitonu tam olarak istediğimi yapıyor! Teşekkür ederim! –

7

Kısa cevap

JAM Software dan ShellBrowser Components deneyin. Bunlar, Explorer'in içerik menüsünü, TPopupMenu'dan karışık kendi komutlarınızla göstermenize izin verecek bir bileşene sahiptir.


Uzun cevap

, Tarayıcı menüsünden Alma tüm özellikleri sorgulama ve kendi menüde bunları barındırma

mümkündür, ama sen gerçekten rahat okuma/yazma düşük seviye Win32 kodu olmalıdır ve C'nin çalışma bilgisi yardımcı olacaktır. Ayrıca bazı tutacakları (aşağıda kapsanan) dikkat etmeniz gerekir. Birçok teknik ayrıntı için Raymond Chen'in How to host an IContextMenu serisini okumanızı şiddetle tavsiye ediyorum.

kolay yaklaşım IContextMenu arabirimi için sorgu, sonra hMenu, ardından Windows menüsünü göstermek atalım TrackPopupMenu kullanın, ardından sonunda InvokeCommand diyoruz.

Aşağıdaki kodun bir kısmı test edilmediğinden veya kullandığımızdan değiştirildiğinden, kendi sorumluluğunuzda ilerleyin. İşte

bir taban klasör içindeki dosyaların bir grup için, IContextMenu olsun nasıl:

function GetExplorerMenu(AHandle: HWND; const APath: string; 
    AFilenames: TStrings): IContextMenu; 
var 
    Desktop, Parent: IShellFolder; 
    FolderPidl: PItemIDList; 
    FilePidls: array of PItemIDList; 
    PathW: WideString; 
    i: Integer; 
begin 
    // Retrieve the Desktop's IShellFolder interface 
    OleCheck(SHGetDesktopFolder(Desktop)); 
    // Retrieve the parent folder's PItemIDList and then it's IShellFolder interface 
    PathW := WideString(IncludeTrailingPathDelimiter(APath)); 
    OleCheck(Desktop.ParseDisplayName(AHandle, nil, PWideChar(PathW), 
    Cardinal(nil^), FolderPidl, Cardinal(nil^))); 
    try 
    OleCheck(Desktop.BindToObject(FolderPidl, nil, IID_IShellFolder, Parent)); 
    finally 
    SHFree(FolderPidl); 
    end; 
    // Retrieve PIDLs for each file, relative the the parent folder 
    SetLength(FilePidls, AFilenames.Count); 
    try 
    FillChar(FilePidls[0], SizeOf(PItemIDList) * AFilenames.Count, 0); 
    for i := 0 to AFilenames.Count-1 do begin 
     PathW := WideString(AFilenames[i]); 
     OleCheck(Parent.ParseDisplayName(AHandle, nil, PWideChar(PathW), 
     Cardinal(nil^), FilePidls[i], Cardinal(nil^))); 
    end; 
    // Get the context menu for the files from the parent's IShellFolder 
    OleCheck(Parent.GetUIObjectOf(AHandle, AFilenames.Count, FilePidls[0], 
     IID_IContextMenu, nil, Result)); 
    finally 
    for i := 0 to Length(FilePidls) - 1 do 
     SHFree(FilePidls[i]); 
    end; 
end; 

Eğer IContextMenu.QueryContextMenu çağırmanız gerekir fiili menü öğelerini almak için. DestroyMenu kullanarak iade edilen HMENU'yu yok edebilirsiniz.

procedure InvokeCommand(const AContextMenu: IContextMenu; AVerb: PChar); 
const 
    CMIC_MASK_SHIFT_DOWN = $10000000; 
    CMIC_MASK_CONTROL_DOWN = $20000000; 
var 
    CI: TCMInvokeCommandInfoEx; 
begin 
    FillChar(CI, SizeOf(TCMInvokeCommandInfoEx), 0); 
    CI.cbSize := SizeOf(TCMInvokeCommandInfo); 
    CI.hwnd := GetOwnerHandle(Owner); 
    CI.lpVerb := AVerb; 
    CI.nShow := SW_SHOWNORMAL; 
    // Ignore return value for InvokeCommand. Some shell extensions return errors 
    // from it even if the command worked. 
    try 
    AContextMenu.InvokeCommand(PCMInvokeCommandInfo(@CI)^) 
    except on E: Exception do 
    MessageDlg(Owner, E.Message, mtError, [mbOk], 0); 
    end; 
end; 

procedure InvokeCommand(const AContextMenu: IContextMenu; ACommandID: UINT); 
begin 
    InvokeCommand(AContextMenu, MakeIntResource(Word(ACommandID))); 
end; 

Şimdi başlığını almak için GetMenuItemInfo işlevini kullanabilirsiniz, bitmap, vs, ama çok daha kolay: İşte

function GetExplorerHMenu(const AContextMenu: IContextMenu): HMENU; 
const 
    MENUID_FIRST = 1; 
    MENUID_LAST = $7FFF; 
var 
    OldMode: UINT; 
begin 
    OldMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX); 
    try 
    Result := CreatePopupMenu; 
    AContextMenu.QueryContextMenu(Result, 0, MENUID_FIRST, MENUID_LAST, CMF_NORMAL); 
    finally 
    SetErrorMode(OldMode); 
    end; 
end; 

aslında kullanıcı menüsünden seçilen ettiğini komutu çağırır nasıl Yaklaşım TrackPopupMenu'u aramak ve Windows'un açılır menüyü göstermesine izin vermek. Aslında menü öğeleri/başlıkları ayıklamak ve (biz Çubuğu 2000 kullanmak ve tam olarak bunu) kendi açılan menüden eklemek isterseniz buraya,

procedure ShowExplorerMenu(AForm: TForm; AMousePos: TPoint; 
    const APath: string; AFilenames: TStrings;); 
var 
    ShellMenu: IContextMenu; 
    Menu: HMENU; 
    MenuID: LongInt; 
begin 
    ShellMenu := GetExplorerMenu(AForm.Handle, APath, AFilenames); 
    Menu := GetExplorerHMenu(ShellMenu); 
    try 
    MenuID := TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_TOPALIGN or TPM_RETURNCMD, 
     AMousePos.X, AMousePos.Y, 0, AForm.Handle, nil); 
    InvokeCommand(ShellMenu, MenuID - MENUID_FIRST); 
    finally 
    DestroyMenu(Menu); 
    end; 
end; 

diğer büyük sorunlar şunlardır: Yani böyle bir şey olmazdı çalıştıracağınız içine:

  • menüsü "gönder" ve iletileri işlemek ve IContextMenu2/IContextMenu3 arayüzleri onları geçmek sürece on-demand inşa herhangi diğerleri çalışmaz.
  • Menü bitmapler birkaç farklı formattadır. Delphi, coaxing olmadan yüksek renkteki Vista'ları işlemez ve eskileri bir XOR kullanarak arka plan rengine karışır.
  • Bazı menü öğeleri sahiplenilmiştir, bu nedenle boya iletilerini yakalamanız ve bunları kendi tuvalinize boyamanız gerekir.
  • El ile sorgulamadığınız sürece, ip dizeleri çalışmaz.
  • IContextMenu ve HMENU'nun ömrünü yönetmeniz ve yalnızca açılır menü kapatıldıktan sonra bunları serbest bırakmanız gerekir.
+0

Merhaba Craig, Ayrıntılı teknoloji bilgisi için teşekkürler, çok yardımcı oluyorlar! Ama RRUZ'un cevabını kabul etmeliyim çünkü beni tek bir çizgi ile istediğimi yapan JCL'den DisplayContextMenu işlevine işaret etti ... –

0

Burada, "Gönder ... | Posta alıcısı" bağlamı menü öğesinin arkasındaki işletim sistemi mantığının, varsayılan posta istemcisini açmak için bir Delphi uygulamasından nasıl kullanılabileceğine dair bir exmple kullanılabilir. geçti (seçilen) dosyaları ekli:

How can I simulate ‘Send To…’ with Delphi?

İlgili konular