Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Aufruf des Systemmenü eines Fensters verhindern (https://www.delphipraxis.net/191766-aufruf-des-systemmenue-eines-fensters-verhindern.html)

TUX_der_Pinguin 17. Feb 2017 08:40

Aufruf des Systemmenü eines Fensters verhindern
 
Hi,

ich versuche gerade einen Weg zu finden wie ich verhindern kann das das Systemmenü eines Fensters aufgerufen werden kann. Ohne in der Option 'BorderIcons' das Menü zu deaktivieren, dann verschwindet das "Rote X" und BorderStyle bsToolWindow ist auch keine Option. Mein erster weg war einfach im OnCreate() von TForm die Einträge aus dem Menü zu löschen was auch funktioniert und das Menü scheint auch weg zu sein. Mir ist dann aber aufgefallen das man das Menü trotzdem noch mit der Tastenkombination ALT + Leertaste aufrufen kann, es ist zwar nicht sichtbar aber der Fokus liegt dann trotzdem im Menü und nicht mehr auf der Form selbst. Das möchte ich gerne unterbinden.

Bei meiner Recherche bin ich auf zwei Windows Botschaften gestoßen WM_INITMENU und WM_INITMENUPOPUP jedoch finde ich keine wirkliche Lösung wie ich diese Botschaften abfangen und quasi verwerfen kann so das das Systemmenü einfach nicht aufgerufen wird.

Ich habe es mal mit WndProc versucht und ja die Botschaften werden abgefangen, aber wie verwerfe ich diese nun?

Delphi-Quellcode:
.
.
.
 private
    procedure WndProc(var msg: TMessage); override;


procedure TForm1.WndProc(var msg: TMessage);
begin

  if (msg.Msg = WM_INITMENU) or (msg.Msg = WM_INITMENUPOPUP) then
  begin
    ShowMessage('Bla Bla Mr. Freeman');
  end
  else
    inherited;

end;

TUX_der_Pinguin 17. Feb 2017 11:11

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Für den Fall das es noch jemanden interessiert, ich habe inzwischen eine Akzeptable Lösung gefunden. Das Menü erscheint nicht mehr beim drücken der Tastenkombination ALT + Leertaste und der Focus hängt auch nicht mehr im unsichtbaren Menü fest.

Delphi-Quellcode:
private
  procedure WMInitMenuPopup(var Msg: TWMInitMenuPopup); message WM_INITMENUPOPUP;

procedure TForm1.WMInitMenuPopup(var Msg: TWMInitMenuPopup);
begin
  inherited;
  if Msg.SystemMenu then
  begin
    //Beendet das Menü sofort wieder
    EndMenu;

    //Einträge können gelöscht werden, da aber eh nicht sichtbar also auch nicht nötig.
    //Außerdem sorgt dafür das löschen des "Schließen" Eintrags dafür das das "Rote X" deaktiviert wird und gräulich dargestellt wird
    DeleteMenu(msg.MenuPopUp, SC_MOVE, MF_BYCOMMAND);
    DeleteMenu(msg.MenuPopUp, SC_CLOSE, MF_BYCOMMAND);
  end;{if}

end;

Der schöne Günther 17. Feb 2017 11:22

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Ich kenne mich mit den Windows-Messages nicht so aus, aber weshalb in jedem Fall das
Delphi-Quellcode:
inherited
? Würde man das eben gerade nicht den Standard-Handler ranlassen wollen und einfach nur das LRESULT der Message auf Null sezten?

Ich rede nur vor so mich hin, ausprobiert habe ich nichts...

TUX_der_Pinguin 17. Feb 2017 11:29

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1361935)
Ich kenne mich mit den Windows-Messages nicht so aus, aber weshalb in jedem Fall das
Delphi-Quellcode:
inherited
? Würde man das eben gerade nicht den Standard-Handler ranlassen wollen und einfach nur das LRESULT der Message auf Null sezten?

Ich rede nur vor so mich hin, ausprobiert habe ich nichts...

Wenn ich dich jetzt richtig verstehe, du meinst das Ergebnis einfach auf Null setzten und nichts weiteres. Das klappt nicht, das Systemmenu wird trotzdem angezeigt.

Delphi-Quellcode:
procedure TfrmDlgIdent.WMInitMenuPopup(var Msg: TWMInitMenuPopup);
begin
  Msg.Result := 0;
end;

EWeiss 17. Feb 2017 12:35

AW: Aufruf des Systemmenü eines Fensters verhindern
 
1. GetSystemMenu
2. GetMenuItemCount
3. RemoveMenu

gruss

TUX_der_Pinguin 17. Feb 2017 12:48

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361939)
1. GetSystemMenu
2. GetMenuItemCount
3. RemoveMenu

gruss

Und das hilft mir jetzt wie weiter?

Wenn ich die Eintrage aus dem Systemmenü lösche ist es trotzdem noch da, zwar unsichtbar, aber durch drücken der Tastenkombination ALT+Leertaste bekommt das Menü trotzdem den Focus und das will ich grade nicht.

EWeiss 17. Feb 2017 13:04

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von TUX_der_Pinguin (Beitrag 1361946)
Zitat:

Zitat von EWeiss (Beitrag 1361939)
1. GetSystemMenu
2. GetMenuItemCount
3. RemoveMenu

gruss

Und das hilft mir jetzt wie weiter?

Wenn ich die Eintrage aus dem Systemmenü lösche ist es trotzdem noch da, zwar unsichtbar, aber durch drücken der Tastenkombination ALT+Leertaste bekommt das Menü trotzdem den Focus und das will ich grade nicht.

Sehr viel wenn man sich einfach mal der MSLibrary bedient.

Bei mir geht kein Menu mehr auf auch nicht mit ALT-SPACE
Dir sollte aber eins klar sein das durch die Manipulation und des kompletten entfernen des System Menüs
der X-Button deaktiviert und das Window sich nicht mehr verschieben lässt.

Also man sollte schon wissen was man da tut.

gruss

TUX_der_Pinguin 17. Feb 2017 13:08

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361948)
Zitat:

Zitat von TUX_der_Pinguin (Beitrag 1361946)
Zitat:

Zitat von EWeiss (Beitrag 1361939)
1. GetSystemMenu
2. GetMenuItemCount
3. RemoveMenu

gruss

Und das hilft mir jetzt wie weiter?

Wenn ich die Eintrage aus dem Systemmenü lösche ist es trotzdem noch da, zwar unsichtbar, aber durch drücken der Tastenkombination ALT+Leertaste bekommt das Menü trotzdem den Focus und das will ich grade nicht.

Sehr viel wenn man sich einfach mal der MSLibrary bedient.

Bei mir geht kein Menu mehr auf auch nicht mit ALT-SPACE
Dir sollte aber eins klar sein das durch die Manipulation und des kompletten entfernen des System Menüs
der X-Button deaktiviert und das Window sich nicht mehr verschieben lässt.

Also man sollte schon wissen was man da tut.

gruss

Es geht ja auch kein Menü auf, wenn man alle Einträge löscht, aber trotzdem ist es noch da bzw. erhält den Focus. Wenn man TFrom.KeyPreview := True einstellt und im TFrom.KeyDown die Esc-Taste abfrage reagiert das Ereignis erst wenn man die Taste zweimal drückt, da beim ersten drücken das Menü geschlossen wird, welches unsichtbar ist und beim zweiten wird dann das Ereignis ausgelöst.
Ja ich weiß das der X-Button deaktiviert wird das ist aber nicht wichtig und verschieben soll sowieso nicht gemacht werden. Die Anwendung soll nur über die Tastatur zu bedienen sein.

EWeiss 17. Feb 2017 13:13

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Na gut dann bitte..

Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
var
  Menu: HMENU;
  MenuItems: Integer;
  i: Integer;
begin

  Menu := GetSystemMenu(Handle, false);
  if Menu <> 0 then
  begin
    MenuItems := GetMenuItemCount(Menu);
    if MenuItems <> 0 Then
      for i := MenuItems - 1 DownTo 0 do
        RemoveMenu(Menu, i, MF_BYPOSITION);
  end;
end;
Wenn du das Window trotzden verschieben möchtest dann ändere einfach die
DownTo 0 zu 2

Dann geht zwar das Menu wieder auf aber nur mit zwei Einträgen.
Wiederherstellen / Verschieben.

Nebenbei ich musste auch des Öfteren MS in Anspruch nehmen ;)
Man bekommt nicht überall alles umsonst und muss es sich erarbeiten.
Aber sei's drum.

gruss

TUX_der_Pinguin 17. Feb 2017 13:20

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361951)
Na gut dann bitte..

Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
var
  Menu: HMENU;
  MenuItems: Integer;
  i: Integer;
begin

  Menu := GetSystemMenu(Handle, false);
  if Menu <> 0 then
  begin
    MenuItems := GetMenuItemCount(Menu);
    if MenuItems <> 0 Then
      for i := MenuItems - 1 DownTo 0 do
        RemoveMenu(Menu, i, MF_BYPOSITION);
  end;
end;
Wenn du das Window trotzden verschieben möchtest dann ändere einfach die
DownTo 0 zu 2

Dann geht zwar das Menu wieder auf aber nur mit zwei Einträgen.
Wiederherstellen / Verschieben.

Nebenbei ich musste auch des Öfteren MS in Anspruch nehmen ;)
Man bekommt nicht überall alles umsonst und muss es sich erarbeiten.
Aber sei's drum.

gruss


Ist das Menü weg: JA
Bekommt das UNSICHTBARE Menü immer noch den Focus: JA
Muss ich immer noch ZWEIMAL die ESC-Taste drücken um das Formular zu schließen: JA
Ist es das was ich will: NEIN

Es tut mir leid das das vielleicht etwas harsch wirkt, aber das ist doch genau das wo von ich die ganze Zeit spreche das es zwar Funktioniert aber nicht so wie ich das will. Vielleicht reden wir auch an einander vorbei.

EWeiss 17. Feb 2017 13:21

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Bekommt das UNSICHTBARE Menü immer noch den Focus: JA
Quatsch.

Zitat:

Muss ich immer noch ZWEIMAL die ESC-Taste drücken um das Formular zu schließen: JA
Ich kann es selbst mit 100 ESC Klicks nicht schießen.
Wie denn auch wenn es nicht mehr existiert.
Also auch Quatsch.

Das Menu ist nicht mehr da wie denn auch.
Drück doch einfach mein dein besagtes ALT-SPACE

Aber natürlich hänge ich das Projekt auch noch an. (Weil ich dazu blöd genug bin)
Du bist ab sofort auf meiner Ignorier liste.

gruss

TUX_der_Pinguin 17. Feb 2017 13:33

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361956)
Das Menu ist nicht mehr da wie denn auch.
Drück doch einfach mein dein besagtes ALT-SPACE

gruss

Ja ich drücke ALT-Space, dann drücke ich ESC um mein Formular zu schließen und es passiert nichts weil DAS SYSTEMMENÜ DEN FOCUS HAT UND SICH DURCH DRÜCKEN DER ESC-TASTE SCHLIESST, drücke ich dann ein zweites mal ESC wird endlich das KeyDown Ereignis des Formulars ausgelöst und das Formular schließt sich.

Die Anwendung soll nur über die Tastatur zu bedienen sein und wenn der Anwender ausversehen in dem unsichtbaren Menü hängt und dann das Fenster schließen will und beim drücken der ESC-Taste nichts passiert finde ich das unsauber das er dann noch mal drücken muss.

EWeiss 17. Feb 2017 13:36

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Ach lade dir mein Teil doch einfach und versuche dieses durch ESC zu schließen.
Sag bescheid wenn du es geschlossen hast.

Zitat:

in dem unsichtbaren Menü hängt
Wo ist das Problem dann entferne einfach den WindowStyle WS_SYSMENU nach dem du alle Items gelöscht hast.
Danach ist das Menu garantiert nicht mehr vorhanden.

gruss

TUX_der_Pinguin 17. Feb 2017 13:42

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361959)
Ach lade dir mein Teil doch einfach und versuche dieses durch ESC zu schließen.
Sag bescheid wenn du es geschlossen hast.

gruss

Das schließen wird ja auch über das OnKeyDown Event des Formulars gelöst, wie bereits beschrieben, dazu muss noch KeyPreview des Formulars aktiv sein. Rufe ich die Anwendung auf ohne irgendwas zu machen und drücke die ESC-Taste beendet sich die Anwendung sofort und umgehend. Drücke ich nach dem Start jedoch ALT+Leertaste und dann die ESC-Taste passiert nichts, erst beim erneuten drücken der ESC-Taste. Warum weil das Systemmenü obwohl nicht sichtbar doch den Focus oder sonst was bekommen hat. Du darfst das gerne selbst testen.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin

  Close;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_ESCAPE then
  begin
    Close;
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  Menu: HMENU;
  MenuItems: Integer;
  i: Integer;
begin

  Menu := GetSystemMenu(Handle, false);
  if Menu <> 0 then
  begin
    MenuItems := GetMenuItemCount(Menu);
    if MenuItems <> 0 Then
      for i := MenuItems - 1 DownTo 0 do
        RemoveMenu(Menu, i, MF_BYPOSITION);
  end;
end;

end.

EWeiss 17. Feb 2017 13:46

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Du darfst das gerne selbst testen.
Ich habe es mit meinem Projekt getestet ;)

Da kann ich drücken wie blöde da schießt sich nichts mit ESC.
Aber gut hab meinen Beitrag über dir editiert.

gruss

EWeiss 17. Feb 2017 13:54

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Warum weil das Systemmenü obwohl nicht sichtbar doch den Focus oder sonst was bekommen hat. Du darfst das gerne selbst testen.
Was nicht existiert kann keinen Focus bekommen.

So es gibt kein SysMenu mehr überprüfe das einfach anhand der GWL_STYLE
Weder Unsichtbar noch sonst was.
Du kannst aber das Window nun trotzdem verschieben.

Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
var
  Menu: HMENU;
  MenuItems: Integer;
  i: Integer;
  Style: DWord;
begin

  Menu := GetSystemMenu(Handle, false);
  if Menu <> 0 then
  begin
    MenuItems := GetMenuItemCount(Menu);
    if MenuItems <> 0 Then
      for i := MenuItems - 1 DownTo 0 do
        RemoveMenu(Menu, i, MF_BYPOSITION);
  end;

  Style := GetWindowLong(Handle, GWL_STYLE);
  Style := Style and not WS_SYSMENU;
  SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, Style)
    or WS_BORDER or WS_SIZEBOX or WS_DLGFRAME or WS_OVERLAPPED);
end;
Entferne den Button auf der Form addiere dein ominöses
Delphi-Quellcode:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_ESCAPE then
   begin
     Close;
   end;
end;
Klick einmal die ESC Taste dann beendet sich die Anwendung sofort.

TUX_der_Pinguin 17. Feb 2017 14:12

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361963)
So es gibt kein SysMenu mehr überprüfe das einfach anhand der GWL_STYLE
Weder Unsichtbar noch sonst was.
Du kannst aber das Window nun trotzdem verschieben.

Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
var
  Menu: HMENU;
  MenuItems: Integer;
  i: Integer;
  Style: DWord;
begin

  Menu := GetSystemMenu(Handle, false);
  if Menu <> 0 then
  begin
    MenuItems := GetMenuItemCount(Menu);
    if MenuItems <> 0 Then
      for i := MenuItems - 1 DownTo 0 do
        RemoveMenu(Menu, i, MF_BYPOSITION);
  end;

  Style := GetWindowLong(Handle, GWL_STYLE);
  Style := Style and not WS_SYSMENU;
  SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, Style)
    or WS_BORDER or WS_SIZEBOX or WS_DLGFRAME or WS_OVERLAPPED);
end;

Danke für den Tipp aber leider kommt das auf das selbe raus wenn ich in der Option BorderIcons das Systemmenü abschalten, es verschwindet der X-Button, den ich aus Design Gründen ganz gerne behalten würde. Alles nicht so das ware, es läuft wohl auf einen Kompromiss hinaus.

Wobei meine erste Lösung zumindest die ALT+Leertaste Problematik behebt, danach war mir auf gefallen das schon das alleinige drücken von ALT das Menü aufruft, auch wenn es nicht sichtbar ist.

Delphi-Quellcode:
private
  procedure WMInitMenuPopup(var Msg: TWMInitMenuPopup); message WM_INITMENUPOPUP;

procedure TForm1.WMInitMenuPopup(var Msg: TWMInitMenuPopup);
begin
  inherited;
  if Msg.SystemMenu then
  begin
    //Beendet das Menü sofort wieder
    EndMenu;

    //Einträge können gelöscht werden, da aber eh nicht sichtbar also auch nicht nötig.
    //Außerdem sorgt dafür das löschen des "Schließen" Eintrags dafür das das "Rote X" deaktiviert wird und gräulich dargestellt wird
    DeleteMenu(msg.MenuPopUp, SC_MOVE, MF_BYCOMMAND);
    DeleteMenu(msg.MenuPopUp, SC_CLOSE, MF_BYCOMMAND);
  end;{if}

end;

EWeiss 17. Feb 2017 14:26

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Alles nicht so das ware, es läuft wohl auf einen Kompromiss hinaus.
Abgesehen davon das nun der X-Button nicht mehr sichtbar ist läuft alles so wie gewünscht.

1.
Ich starte die Anwendung.
Drücke ALT-SPACE nichts passiert.
Drücke einmalig den ESC Key die Anwendung beendet.

2.
Ich starte die Anwendung.
Drücke einmalig den ESC Key die Anwendung beendet.

OK das war's für mich. :)

gruss

TUX_der_Pinguin 17. Feb 2017 14:28

AW: Aufruf des Systemmenü eines Fensters verhindern
 
Zitat:

Zitat von EWeiss (Beitrag 1361966)
Abgesehen davon das nun der X-Button nicht mehr sichtbar ist läuft alles so wie gewünscht.

1.
Ich starte die Anwendung.
Drücke ALT-SPACE nichts passiert.
Drücke einmalig den ESC Key die Anwendung beendet.

2.
Ich starte die Anwendung.
Drücke einmalig den ESC Key die Anwendung beendet.

OK das war's für mich. :)

gruss

Das wäre mir schon wichtig das der X-Button sichtbar wäre, aber danke dir trotzdem.

TUX_der_Pinguin 17. Feb 2017 16:01

AW: Aufruf des Systemmenü eines Fensters verhindern
 
So ich habe es jetzt scheinbar endlich geschafft ob die Lösung jetzt allem Standhält muss sich noch herausstellen.

Delphi-Quellcode:
private
  procedure WMInitMenu(var Msg: TWMInitMenu); message WM_INITMENU;

procedure TForm1.WMInitMenu(var Msg: TWMInitMenu);
begin
  //Behandlung abbrechen
  abort;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:56 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz