![]() |
Explorer-Kontextmenüpunkt unsichtbar ausführen
Ich möchte gerne einen Menüpunkt aus dem Kontextmenü des Windows Explorers ausführen.
Nach einigem Hin und Her bin ich bei ![]() Was mir noch fehlt: Mit dem Code kann ich das gewünschte Kontextmenü anzeigen und manuell auf den Menüpunkt klicken, aber eigentlich möchte ich das ja gar nicht anzeigen. Das gefundene Menü soll unsichtbar bleiben. Stattdessen möchte ich dessen Items durchiterieren und die Aktion eines bestimmten Items ausführen. Nach einigen Tests bin ich irgendwie ratlos, wie das gehen könnte. Kann mir dabei bitte jemand weiterhelfen?
Delphi-Quellcode:
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComObj, ShlObj, ActiveX; type TForm1 = class(TForm) Button1: TButton; procedure WndProc(var Message: TMessage); override; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; aContextMenu: IContextMenu; aContextMenu2: IContextMenu2; implementation {$R *.dfm} procedure TForm1.WndProc(var Message: TMessage); begin case Message.Msg of WM_INITMENUPOPUP, WM_DRAWITEM, WM_MENUCHAR, WM_MEASUREITEM: if Assigned(aContextMenu2) then begin If (aContextMenu2.HandleMenuMsg(Message.Msg, Message.wParam, Message.lParam) <> NOERROR) then inherited WndProc(Message) else Message.Result := 0; end else inherited WndProc(Message); else inherited WndProc(Message); end; end; function SlashDirName(ADir: String): String; var s: String; bRootDir: Boolean; begin if ADir<>'' then begin s := ADir; bRootDir := ((Length(s)=3) and (s[2]=':')) or (s='\'); if not bRootDir then if s[Length(s)]<>'\' then s:=s+'\'; Result := s; end; end; function SHGetIDListFromPath(Path: TFileName; var ShellFolder: IShellFolder): PItemIDList; var TempPath, NextDir: TFileName; SlashPos: Integer; Folder, subFolder: IShellFolder; PIDL, PIDLbase: PItemIDList; ParseStruct: TStrRet; ParseNAme: String; EList: IEnumIDList; DidGet: Cardinal; ScanParam: Integer; begin SHGetDesktopFolder(Folder); SHGetSpecialFolderLocation(0, CSIDL_DRIVES, PIDLbase); OLECheck(Folder.BindToObject(PIDLbase, nil, IID_IShellFolder, Pointer(SubFolder))); TempPath := Path; NextDir:=''; while Length(TempPath)>0 do begin SlashPos := Pos('\', TempPath); if SlashPos > 0 then begin if Pos(':', TempPath) > 0 then NextDir := Copy(TempPath, 1, 3) else NextDir := SlashDirName(NextDir) + Copy(TempPath, 1, SlashPos-1); TempPath := Copy(TempPath, SlashPos+1, Length(TempPath)); end else begin if NextDir='' then NextDir:=TempPath else NextDir := SlashDirName(NextDir)+TempPath; TempPath := ''; end; PIDL := PidlBase; ScanParam := SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN; if (NextDir=Path) and (not DirectoryExists(Path)) then ScanParam := ScanParam or SHCONTF_NONFOLDERS; if S_OK=SubFolder.EnumObjects(0, ScanParam, EList) then begin while S_OK=EList.Next(1, pidl, DidGet) do begin OLECheck(SubFolder.GetDisplayNameOf(PIDL, SHGDN_FORPARSING, ParseStruct)); case ParseStruct.uType of STRRET_CSTR: ParseName :=ParseStruct.cStr; STRRET_WSTR: ParseName :=WideCharToString(ParseStruct.pOleStr); STRRET_OFFSET: Parsename :=PChar(DWORD(Pidl)+ParseStruct.uOffset); end; if UpperCase(Parsename)=UpperCase(NextDir) then Break; end end else begin Folder := nil; Result := nil; Exit; end; if DidGet=0 then begin Folder := nil; Result := nil; Exit; end; PIDLBase := PIDL; Folder := subFolder; if not FileExists(NextDir) then OLECheck(Folder.BindToObject(Pidl, nil, IID_IShellFolder, Pointer(SubFolder))); end; ShellFolder := Folder; if ShellFolder = nil then Result := nil else Result := PIDL; end; procedure ContextMenuForFile(FileName: TFileName; X, Y: Integer; Handle: HWND); var aPrgOut: Pointer; aPopup: HMENU; aCmd: Integer; aCmdInfo: TCMInvokeCommandInfo; PIDL: PItemIDList; ShellFolder: IShellFolder; begin PIDL := SHGetIDListFromPath(FileName, ShellFolder); if not Assigned(PIDL) then Exit; aPrgOut := nil; OLECheck(ShellFolder.GetUIObjectOf(0, 1, PIDL, IID_IContextMenu, aPrgOut, Pointer(aContextMenu))); // Ab hier wird das Kontextmenü zusammengebaut und angezeigt // Stattdessen: // 1. Menüpunkte iterieren und gewünschten Eintrag erkennen (Text? ID?) // 2. Dessen Aktion ausführen aPopup := CreatePopUpMenu; if aPopup=0 then Exit; try OLECheck(aContextMenu.QueryContextMenu(aPopup, 0, 1, $7FFF, CMF_EXPLORE or CMF_CANRENAME)); OLECheck(aContextMenu.QueryInterface(IID_IContextMenu2, aContextMenu2)); //To handle submenus. try aCmd := Integer(TrackPopupMenu(aPopup, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, X, Y, 0, Handle, nil)); if aCmd<>0 then begin FillChar(aCmdInfo, Sizeof(aCmdInfo), 0); with aCmdInfo do begin cbSize := SizeOf(TCMInvokeCommandInfo); lpVerb := PAnsiChar(MakeIntResource(aCmd-1)); nShow := SW_SHOWNORMAL; end; try aContextMenu.InvokeCommand(aCmdInfo); except end; end; finally aContextMenu2 := nil; end; finally DestroyMenu(aPopup); end; end; procedure TForm1.Button1Click(Sender: TObject); begin ContextMenuForFile('C:\', 100, 100, Application.Handle); end; procedure TForm1.FormCreate(Sender: TObject); begin aContextMenu2 := nil; end; end. |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Oder mit anderen Worten gesagt:
Du möchtest gar nicht das Kontext-Menü, sondern nur den Inhalt (also die Aktionen) und dir daraus eine aussuchen und ausführen, so als ob diese über das Kontextmenü ausgelöst worden wäre. So in etwa richtig? |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Korrekt!
Aber um an diese Aktionen zu kommen, brauche ich ja erst das Kontextmenü, oder? Zumindest war das mein Gedankengang... |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Die Informationen, wie und wo was warum angezeigt/aufgerufen wird liegt zum einen Teil in der Registry.
Was für einen Menü-Eintrag - was für einen Aktion - soll denn ausgeführt werden? Meistens gibt es einen ganz anderen Weg dahin. |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Hm, ich glaube, das würde hier zu weit weg von dem eigentlichen Wunsch wegführen. Das, was ich hier anfrage bzw. vorhabe, ist bereits mein letzter Stohhalm. Der normale API-Weg funktioniert in einer bestimmten Konstellation nur fehlerhaft. Über das Kontextmenü des Explorers geht es allerdings. Das Problem ist hier bereits durch mehrere Hände gegangen und es gibt dazu auch Diskussionen bei MSDN, die zu keiner Lösung führen.
Es wird also definitiv nur über einen Workaround führen und mit dem hier beschriebenen Weg, sehe ich die Möglichkeit für einen solchen Workaround. Edit: Wenn es dich wirklich interessiert, beschreibe ich Dir das Problem gerne per PM bzw. sende Links dazu. Ich befürchte einfach, wenn ich das hier beschreibe, geht die eigentliche Frage komplett unter. ;) |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Was soll der Code denn eigentlich machen? Ich werde aus der riesen Prozedur nicht so ganz schlau? Und ich kann mir nicht vorstellen, dass das nur über das Kontext Menü des Explorers gescheit funktionieren soll.
|
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Zitat:
|
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Da ich mit der Materie nicht so vertraut bin, habe ich mal bei MSDN nachgeschaut:
Zitat:
Gruß K-H |
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Zitat:
|
AW: Explorer-Kontextmenüpunkt unsichtbar ausführen
Zitat:
Nach
Delphi-Quellcode:
ist das Kontextmenü in aContextMenu drin. Aber nun muss ich da noch irgendie durchiterieren und den gewünschten Eintrag finden (anhand vom Text oder irgendeiner ID). Danach kann ich das ausführen.
OLECheck(ShellFolder.GetUIObjectOf(0, 1, PIDL, IID_IContextMenu, aPrgOut, Pointer(aContextMenu)));
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:12 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz