Istnieje obejście, ale jest bardzo, bardzo brudny: Użyj klasy cracker, aby uzyskać dostęp do prywatnego członek FHandle TPopupMenu.Items Właściwość elementu menu.
Klasa cracker polega na reprodukowaniu układu prywatnego magazynu klasy docelowej do prywatnego członka zainteresowania i włącznie z nim za pomocą rzutowania typu na "nałożenie" tego typu na instancję typu docelowego w kontekście, w którym następnie umożliwia dostęp do pamięci wewnętrznej celu.
W tym przypadku obiekt docelowy jest przedmioty własnością TPopupMenu który jest instancją TMenuItem. TMenuItem wywodzi TComponent więc klasy cracker, aby zapewnić dostęp do FHandle dla TMenuItem jest:
type
// Here be dragons...
TMenuItemCracker = class(TComponent)
private
FCaption: string;
FChecked: Boolean;
FEnabled: Boolean;
FDefault: Boolean;
FAutoHotkeys: TMenuItemAutoFlag;
FAutoLineReduction: TMenuItemAutoFlag;
FRadioItem: Boolean;
FVisible: Boolean;
FGroupIndex: Byte;
FImageIndex: TImageIndex;
FActionLink: TMenuActionLink;
FBreak: TMenuBreak;
FBitmap: TBitmap;
FCommand: Word;
FHelpContext: THelpContext;
FHint: string;
FItems: TList;
FShortCut: TShortCut;
FParent: TMenuItem;
FMerged: TMenuItem;
FMergedWith: TMenuItem;
FMenu: TMenu;
FStreamedRebuild: Boolean;
FImageChangeLink: TChangeLink;
FSubMenuImages: TCustomImageList;
FOnChange: TMenuChangeEvent;
FOnClick: TNotifyEvent;
FOnDrawItem: TMenuDrawItemEvent;
FOnAdvancedDrawItem: TAdvancedMenuDrawItemEvent;
FOnMeasureItem: TMenuMeasureItemEvent;
FAutoCheck: Boolean;
FHandle: TMenuHandle;
end;
UWAGA: Ponieważ technika ta polega na dokładnej reprodukcji pamięci wewnętrznej układ docelowej klasy, deklaracja crackera może wymagać wprowadzenia odmiany $ IFDEF w celu uwzględnienia zmian w tym w Ternal układ między różnymi wersjami Delphi. Deklaracja powyżej jest poprawna dla Delphi XE4 i powinna być sprawdzona względem źródła TMenuItem dla poprawności w.r.t innych wersji Delphi.
Z tą klasą krakersów możemy dostarczyć program narzędziowy do podsumowania nieprzyjemnych sztuczek, które będziemy wykonywać przy użyciu dostępu, który zapewnia.W takim przypadku możemy normalnie usuwać elementy menu, ale także wywoływać: DestroyMenu() sami używając obsady crack, aby nadpisać zmienną składową FHandle z 0, ponieważ jest ona teraz nieważna i musi wynosić 0, aby wymusić TPopupMenu odtworzyć menu gdy obok potrzebne:
procedure ResetPopupMenu(const aMenu: TPopupMenu);
begin
aMenu.Items.Clear;
// Here be dragons...
DestroyMenu(aMenu.Items.Handle);
TMenuItemCracker(aMenu.Items).FHandle := 0;
end;
w kodzie przykładowym po prostu zastąpić wywołanie PopupMenu1.Items.Clear w Button2Click obsługi z wezwaniem do ResetPopupMenu (PopupMenu1).
Nie trzeba dodawać, że jest to w najwyższym stopniu niebezpieczne. Niezależnie od zwykłego obłędu włamywania się do prywatnego przechowywania klasy, w tym konkretnym przypadku nie jest brane pod uwagę rozłączanie połączonych menu.
Ale zapytałeś, czy istnieje obejście, a tutaj jest co najmniej jeden. :)
Niezależnie od tego, czy uważasz to za mniej lub bardziej praktyczne, czy po prostu pożądane, niż po prostu zniszczenie i odtworzenie TPopupMenu należy do Ciebie. Łamanie klas jest techniką, która może być przydatna, aby wydostać cię z zakleszczenia, które w innym przypadku byłoby niemożliwe do rozwiązania, ale zdecydowanie powinno być uznane za "ostateczność"!
Mogę to zduplikować tylko za pomocą wywołań api, CreatePopupMenu, InsertMenu, TrackPopupMenu, DeleteMenu itd. Nie ma "skurczu", o ile uchwyt jest ważny. Jako takie, moim zdaniem, jedynym rozwiązaniem jest uwolnienie menu podręcznego i odtworzenie go w czasie wykonywania, to jedyny sposób wywołania "DestroyMenu". –
@hikari: Dzięki za edycję.Pytanie jest o wiele bardziej przydatne przy dostępnym kodzie, szczególnie dla przyszłych czytelników, którzy mogą znaleźć to w wyszukiwaniu. –