|
Registriert seit: 23. Dez 2003 Ort: Bad Waldsee 112 Beiträge Delphi 5 Professional |
#11
Das eine Problem ist noch nicht gelöst. So lange keine eigenen Menüeinträge hinzugefügt werden oder das Menü mit der Maus bedient wird, funktioniert es zumindest mit Windows 98.
Ich habe folgendes geschrieben:
Delphi-Quellcode:
Das Menü braucht nicht extra aufgerufen werden. Wenn der Benutzer die rechte Maustaste drückt wird das Menü angezeigt.
…
type TShellMenuKind = (smkOnlyHandler, smkComplete, smkDefaultOnly, smkNoDefault); type TForm1 = class(TForm) … public { Public-Deklarationen } procedure WndProc(var Message: TMessage); override; … implementation uses ShellApi, ShlObj, ComObj, FileCtrl, ActiveX, CommCtrl; {$R *.DFM} var mContextMenu: IContextMenu; mContextMenu2: IContextMenu2; iHandlerIndex, iHandlerCount: Integer; CanDraw, ValidCmdArea: Boolean; function SHGetIDListFromPath(FileName: TFileName; var ShellFolder: IShellFolder): PItemIDList; var sParseName: String; mTempPath, mNextDir: TFileName; iScanParam: Integer; iDidGet: Cardinal; mFolder, mSubFolder: IShellFolder; mPIDL, mPIDLbase: PItemIDList; mParseStruct: TStrRet; mEList: IEnumIDList; procedure GetDirs(var TempPath, NextDir: TFileName); var iSlashPos: Integer; function SlashDirName(ADir: String): String; var S: String; RootDir: Boolean; begin if ADir <> '' then begin S := ADir; RootDir := ((Length(S)=3) and (S[2]=':')) or (S='\'); if not RootDir then if S[Length(S)] <> '\' then S := S + '\'; Result := S; end; end; begin iSlashPos := Pos('\', TempPath); if iSlashPos > 0 then begin if Pos(':', TempPath) > 0 then NextDir := Copy(TempPath, 1, 3) else NextDir := SlashDirName(NextDir) + Copy(TempPath, 1, iSlashPos - 1); TempPath := Copy(TempPath, iSlashPos + 1, Length(TempPath)); end else begin if NextDir = '' then NextDir := TempPath else NextDir := SlashDirName(NextDir) + TempPath; TempPath := ''; end; end; begin SHGetDesktopFolder(mFolder); SHGetSpecialFolderLocation(0, CSIDL_DRIVES, mPIDLbase); OLECheck(mFolder.BindToObject(mPIDLbase, nil, IID_IShellFolder, Pointer(mSubFolder))); mTempPath := FileName; mNextDir := ''; while Length(mTempPath) > 0 do begin GetDirs(mTempPath,mNextDir); mPIDL := mPidlBase; iScanParam := SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN; if (mNextDir = FileName) and (not DirectoryExists(FileName)) then iScanParam := iScanParam or SHCONTF_NONFOLDERS; if S_OK = mSubFolder.EnumObjects(0, iScanParam, mEList) then while S_OK = mEList.Next(1, mPIDL, iDidGet) do begin OLECheck(mSubFolder.GetDisplayNameOf(mPIDL, SHGDN_FORPARSING, mParseStruct)); case mParseStruct.uType of STRRET_CSTR: sParseName := mParseStruct.cStr; STRRET_WSTR: sParseName := WideCharToString(mParseStruct.pOleStr); STRRET_OFFSET: sParseName := PChar(DWORD(mPIDL) + mParseStruct.uOffset); end; if UpperCase(sParseName) = UpperCase(mNextDir) then Break; end else begin mFolder := nil; Result := nil; Exit; end; if iDidGet = 0 then begin mFolder := nil; Result := nil; Exit; end; mPIDLBase := mPIDL; mFolder := mSubFolder; if not FileExists(mNextDir) then OLECheck(mFolder.BindToObject(mPIDL, nil, IID_IShellFolder, Pointer(mSubFolder))); end; ShellFolder := mFolder; if ShellFolder = nil then Result := nil else Result := mPIDL; end; procedure ContextMenuForFile(FileName: TFileName; HandlerIndex, X, Y: Integer; Handle: HWND; PopupMenu: TPopupMenu; MenuType: TShellMenuKind); var mPopup: HMENU; iCmd, iID, iRes, iCmdLast: Integer; iFlags: Cardinal; mCmdInfo: TCMInvokeCommandInfo; mPIDL: PItemIDList; mShellFolder: IShellFolder; aMenuBitmaps: array of TBitmap; function ExecMenuItemAction(Cmd: Integer; var ID: Integer; Item: TMenuItem): Boolean; var ix: Integer; begin Result := false; ix := 0; while ix < Item.Count do begin Application.ProcessMessages; if Cmd = ID then begin Item[ix].Click; Result := true; Exit; end; if Item.Items[ix].Count > 0 then ExecMenuItemAction(Cmd,ID,Item.Items[ix]); Inc(ID); Inc(ix); end; end; function AddVCLMenuItems(APIMenu: HMENU; var ID: Integer; Item: TMenuItem; CanAddLine: Boolean; ArrayPos: Integer): Integer; var ix: Integer; SubMenu: HMenu; mBitmap: TBitmap; function GetItemFlags(Item: TMenuItem): Cardinal; begin Result := MF_STRING; if Item.Checked then Result := Result or MF_CHECKED; if not Item.Enabled then Result := Result or MF_GRAYED; if Item.Caption = cLineCaption then Result := Result or MF_SEPARATOR; end; procedure AddMenuBitmap(MnuID: Integer; MnuItm: TMenuItem); begin SetLength(aMenuBitmaps,ArrayPos + 1); aMenuBitmaps[ArrayPos] := TBitmap.Create; aMenuBitmaps[ArrayPos].Width := 14; aMenuBitmaps[ArrayPos].Height := 14; if (Assigned(MnuItm.Bitmap)) and (not MnuItm.Bitmap.Empty) then begin aMenuBitmaps[ArrayPos].Canvas.StretchDraw(Rect(0,0,16,16),MnuItm.Bitmap); aMenuBitmaps[ArrayPos].TransparentColor := MnuItm.Bitmap.Canvas.Pixels[0,0]; aMenuBitmaps[ArrayPos].Transparent := true; end else if (MnuItm.ImageIndex > -1) and (Assigned(PopupMenu.Images)) then begin mBitmap := TBitmap.Create; try PopupMenu.Images.GetBitmap(MnuItm.ImageIndex,mBitmap); aMenuBitmaps[ArrayPos].Canvas.StretchDraw(Rect(0,0,13,13),mBitmap); finally mBitmap.Free; end; end; SetMenuItemBitmaps(APIMenu,MnuID,MF_BYCOMMAND,aMenuBitmaps[ArrayPos].Handle,aMenuBitmaps[ArrayPos].Handle); Inc(ArrayPos); end; begin Result := 0; if CanAddLine then AppendMenu(APIMenu,MF_SEPARATOR,0,nil); ix := 0; while ix < Item.Count do begin Inc(Result); Application.ProcessMessages; if Item.Items[ix].Visible then begin // Item hinzufügen if Item.Items[ix].Count > 0 then begin // Untermenü erstellen, falls nötig SubMenu := CreatePopupMenu; Inc(Result,AddVCLMenuItems(SubMenu,ID,Item.Items[ix],false,ArrayPos)); AppendMenu(APIMenu,GetItemFlags(Item.Items[ix]) or MF_POPUP,SubMenu,PChar(Item.Items[ix].Caption)); // Check und RadioItem hinzufügen if Item.Items[ix].Default then SetMenuDefaultItem(APIMenu,ID,0); if (Item.Items[ix].Checked) and (Item.Items[ix].RadioItem) then CheckMenuRadioItem(APIMenu,ID,ID,ID,MF_BYCOMMAND); // Bitmap hinzufügen if ((Assigned(Item.Items[ix].Bitmap)) and (not Item.Items[ix].Bitmap.Empty)) or ((Assigned(PopupMenu.Images)) and (Item.Items[ix].ImageIndex > -1)) and (not Item.Items[ix].Checked) then AddMenuBitmap(ID,Item.Items[ix]); Inc(ID); end else begin // Menüeintrag hinzufügen AppendMenu(APIMenu,GetItemFlags(Item.Items[ix]),ID,PChar(Item.Items[ix].Caption)); // Check und RadioItem hinzufügen if Item.Items[ix].Default then SetMenuDefaultItem(APIMenu,ID,0); if (Item.Items[ix].Checked) and (Item.Items[ix].RadioItem) then CheckMenuRadioItem(APIMenu,ID,ID,ID,MF_BYCOMMAND); // Bitmap hinzufügen if ((Assigned(Item.Items[ix].Bitmap)) and (not Item.Items[ix].Bitmap.Empty)) or ((Assigned(PopupMenu.Images)) and (Item.Items[ix].ImageIndex > -1)) and (not Item.Items[ix].Checked) then AddMenuBitmap(ID,Item.Items[ix]); end; end; Inc(ID); Inc(ix); end; end; begin mPIDL := SHGetIDListFromPath(FileName, mShellFolder); if not Assigned(mPIDL) then Exit; OLECheck(mShellFolder.GetUIObjectOf(Handle, 1, mPIDL, IID_IContextMenu, nil, Pointer(mContextMenu))); mPopup := CreatePopUpMenu; if mPopup = 0 then Exit; try // VCL Menüeinträge iID := 1; iRes := AddVCLMenuItems(mPopup,iID,PopupMenu.Items,true,0); iHandlerCount := GetMenuItemCount(mPopup); // Einfügeposition korrigieren // Wichtig! Da sonst die "Senden an" Menüeinträge in das falsche // Untermenü gezeichnet werden! if (HandlerIndex > PopupMenu.Items.Count) then HandlerIndex := PopupMenu.Items.Count; if (PopupMenu.Items.Count > 0) and (HandlerIndex < PopupMenu.Items.Count) then if PopupMenu.Items[HandlerIndex].Count > 0 then while (HandlerIndex < PopupMenu.Items.Count) and (PopupMenu.Items[HandlerIndex].Count > 0) do Inc(HandlerIndex); // Handler hinzufügen iCmdLast := 0; iFlags := CMF_NORMAL; case MenuType of smkOnlyHandler: begin iCmdLast := 0; iFlags := CMF_NORMAL; end; smkComplete: begin iCmdLast := $7FFF; iFlags := CMF_NORMAL; end; smkDefaultOnly: begin iCmdLast := $7FFF; iFlags := CMF_DEFAULTONLY; end; smkNoDefault: begin iCmdLast := $7FFF; iFlags := CMF_NODEFAULT; end; end; OLECheck(mContextMenu.QueryContextMenu(mPopup, HandlerIndex + 1, HandlerIndex + 1, iCmdLast, iFlags)); OLECheck(mContextMenu.QueryInterface(IID_IContextMenu2, mContextMenu2)); try iHandlerCount := GetMenuItemCount(mPopup) - iHandlerCount + 1; if PopupMenu.Items.Count > 0 then iHandlerIndex := HandlerIndex else iHandlerIndex := 0; iCmd := Integer(TrackPopupMenuEx(mPopup, TPM_LEFTALIGN or TPM_RIGHTBUTTON or TPM_HORIZONTAL or TPM_VERTICAL or TPM_RETURNCMD, X, Y, Handle, nil)); if not (iCmd in [0..iRes]) then Dec(iCmd,HandlerIndex); // "OnClick" Ereignisse ausführen if (MenuType <> smkOnlyHandler) and (iCmd = 1) and (PopupMenu.Items.Count > 0) then PopupMenu.Items[0].Click else if iCmd <> 0 then begin if (ValidCmdArea) or (MenuType = smkDefaultOnly) or (MenuType = smkNoDefault) or (PopupMenu.Items.Count = 0) then begin // OnClick des Shell Menus FillChar(mCmdInfo, SizeOf(mCmdInfo), 0); with mCmdInfo do begin cbSize := SizeOf(TCMInvokeCommandInfo); lpVerb := MakeIntResource(iCmd - 1); nShow := SW_SHOWNORMAL; end; try if not Succeeded(mContextMenu.InvokeCommand(mCmdInfo)) then begin // Wenn die Ausführung fehlgeschlagen ist iID := 1; ExecMenuItemAction(iCmd,iID,PopupMenu.Items); end; except // nichts tun end; end else begin // VCL OnClick ausführen iID := 1; ExecMenuItemAction(iCmd,iID,PopupMenu.Items); end; end; finally mContextMenu := nil; mContextMenu2 := nil; end; finally DestroyMenu(mPopup); end; end; // Wenn der Benutzer mit der rechten Maustaste klickt Menü anzeigen procedure TForm1.PopupMenu1Popup(Sender: TObject); begin DestroyMenu((Sender as TPopupMenu).Handle); ContextMenuForFile('C:\Eigene Dateien\_Test\Test.txt',3,Mouse.CursorPos.x, Mouse.CursorPos.y,Handle,(Sender as TPopupMenu),smkComplete); end; procedure TForm1.WndProc(var Message: TMessage); var iMenuPos: Integer; begin case Message.Msg of WM_MENUSELECT: begin // Prüfen, ob das Owner Draw Shell Popup Menü (mPopupMenu2) gezeichnet werden kann iMenuPos := Integer(MenuItemFromPoint(Handle,HMENU(Message.LParam),TPoint(Mouse.CursorPos))); if GetSubMenu(HMENU(Message.LParam),iMenuPos) > 0 then CanDraw := iMenuPos in [(iHandlerIndex)..(iHandlerIndex + iHandlerCount)]; ValidCmdArea := CanDraw; inherited WndProc(Message); end; WM_INITMENUPOPUP, WM_DRAWITEM, WM_MENUCHAR, WM_MEASUREITEM: begin // Owner Draw Shell Popup Menü zeichnen if (Assigned(mContextMenu2)) and (CanDraw) then begin If (mContextMenu2.HandleMenuMsg(Message.Msg, Message.wParam, Message.lParam) <> NOERROR) then inherited WndProc(Message) else Message.Result := 0; end else inherited WndProc(Message); end; else inherited WndProc(Message); end; end; procedure TForm1.FormCreate(Sender: TObject); begin mContextMenu2 := nil; end; Allerdings muss folgende Ereignisbehandlungsroutine für „OnPopup“ (bei TPopupMenu) oder „OnBeforePopup“ (bei TFJFPopupMenu) geschrieben werden:
Delphi-Quellcode:
Der letzte Parameter von „ContextMenuForFile“ gibt an, welcher Teil des Shell Menüs angezeigt werden soll.
procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin DestroyMenu((Sender as TPopupMenu).Handle); ContextMenuForFile('C:\Eigene Dateien\_Test\Test.txt',3,Mouse.CursorPos.x, Mouse.CursorPos.y,Handle,(Sender as TPopupMenu),smkOnlyHandler); end; Zugegeben es ist etwas viel geworden, aber wenigstens funktioniert es einigermaßen. Der nächste Schritt ist die Erstellung einer Komponente. Allerdings muss die Komponente „WndProc“ von „TForm“ überschreiben, damit diese funktioniert. Ich habe schon einiges probiert. Mit „TApplication.OnMessage“ funktioniert es nicht und mit einem Hook stürzt Windows ab! Vielleicht hat jemand eine Idee. PS: Bitte lasst mich nicht wieder hängen. Auch wenn Ihr keine Lösung wisst bitte meldet euch, dann weiß ich wenigstens, dass dieses Thema von jemandem gelesen wird. |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |