Entwickler-Ecke

WinForms - Taskleisteneintrag -> Menü öffnen


VampireSilence - So 18.09.11 01:54
Titel: Taskleisteneintrag -> Menü öffnen
Hallo zusammen,

ich hätte da mal wieder eine Frage, und zwar bekommt jede geöffnete Anwendung einen Eintrag in der Taskleiste (sofern ShowInTaskbar = true). Wenn ich diese jetzt mit nem Rechtsklick anklicke, öffnet sich ja ein spezielles Menü (das gleiche wie wenn man das Icon des Fensters anklickt) [Schließen, Verschieben, Größe ändern, etc...]. Wie kann ich dieses Menü gezielt aufrufen ?

mfg
- VampireSilence


storestore - So 18.09.11 11:21

Hi,
Wo klickst du genauch hin? Meinst du jetzt auf die Taskleiste? Mach doch mal bitte ein screenshot! Hab jetzt net genau verstanden was du willst!
mfg storestore


Th69 - So 18.09.11 12:15

Hallo VampireSilence,

das geht wohl nur direkt mit WinAPI-Funktionen.
Du könntest mal versuchen mittels SendMessage die Tastenkombination "Alt + Space" an das eigene Fenster zu schicken.
Um an das sog. SystemMenu programmtechnisch heranzukommen, kannst du die Funktion GetSystemMenu [http://msdn.microsoft.com/en-us/library/ms647985%28v=vs.85%29.aspx] benutzen. Die weiteren Menu-Funktionen findest du unter Menu Functions [http://msdn.microsoft.com/en-us/library/ff468865%28v=vs.85%29.aspx]
Den Aufruf der Funktionen in C# findet du per pinvoke.net [http://pinvoke.net].

Aber wozu benötigst du das?


VampireSilence - So 18.09.11 14:00

Ich benötige das, weil ich eine Form habe, deren FormBorderStyle = None ist. Und der unpraktische Nebeneffekt scheint zu sein, dass sich das SystemMenu jetzt nicht mehr öffnen lässt (oder vllt sogar nichtmal mehr existiert, wie sich gleich zeigen wird).

Habe nämlich fleißig gegoogelt und mit folgendem Code, habe ich es geschafft, das System Menu einer gewöhnlichen Form aufzurufen:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
  [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        private static extern int AppendMenu(int hMenu, int Flagsw, int IDNewItem, string lpNewItem);

        [DllImport("user32.dll")]
        static extern uint TrackPopupMenuEx(IntPtr hmenu, uint uFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool PostMessage(IntPtr hhwnd, uint msg, IntPtr wparam,

        IntPtr lparam);

        private const uint TPM_LEFTBUTTON = (uint)0x0000L;
        private const uint TPM_RIGHTBUTTON = (uint)0x0002L;

        private const uint TPM_NONOTIFY = (uint)0x0080L;
        private const uint TPM_RETURNCMD = (uint)0x0100L;

        private const uint WM_SYSCOMMAND = (uint)0x0112L;

        public static void ShowContextMenu(IntPtr hWnd)
        {
            SetForegroundWindow(hWnd);
            IntPtr wMenu = GetSystemMenu(hWnd, false);

            uint command = TrackPopupMenuEx(wMenu, TPM_LEFTBUTTON | TPM_RETURNCMD, 00, hWnd, IntPtr.Zero);

            if (command == 0)
            {
                return;
            }

            PostMessage(hWnd, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ShowContextMenu(this.Handle);
        }


So. Nur wenn ich jetzt das FormBorderStyle = None setze, funktioniert es schon wieder nicht.

Ich dachte mir also, vielleicht werden nur die Elemente gelöscht und habe daraufhin nochmal folgendermaßen probiert, Elemente hinzuzufügen, die dann ja angezeigt werden müssten:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
        private void SetupSystemMenu()
        {
            IntPtr menu = GetSystemMenu(this.Handle, false);

            AppendMenu(menu, 0xA000null);
            AppendMenu(menu, 0111"Test?");
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == 0x112)
            {
                if (m.WParam.ToInt32() == 111)
                {
                    MessageBox.Show("Test!");
                }
            }
        }


SetupSystemMenu() habe ich jetzt noch vor ShowContextMenu() in button1_Click() hinzugefügt und siehe da, bei normalen Forms funktioniert es und bei FormBorderStyle = None wieder nicht. Jetzt macht sich wieder Ratlosigkeit breit.

mfg
- VampireSilence


Th69 - So 18.09.11 15:05

Anscheinend ist wohl das System-Menu zwingend mit dem Rahmen (d.h. der Titelzeile) verbunden.

Evtl. könntest du mit einem Custom-Border tricksen, s. Custom Window Border für Forms [http://www.mycsharp.de/wbb2/thread.php?threadid=27473], d.h. den Rahmen verkleinern (WM_NCCALCSIZE).


VampireSilence - So 18.09.11 16:25

Naja die Autoren schreiben ja selbst, dass das noch nicht völlig ausgereift ist und zudem zeigt diese Methode auf verschiedenen Betriebssystemen (XP/Vista/7/8) auch sehr unterschiedliche Ergebnisse, deshalb ist das für mich leider nicht geeignet. Mal sehen, vielleicht bekomme ich es ja auch hin, das Menü einfach mit nem ContextMenu nachzubauen oder so. Mal ausprobieren.

Edit: Ok, das Menü nachzubauen war jetzt doch viel einfacher, als ich dachte. Ist zwar nicht 100% originalgetreu, aber ich denke, ich lasse es so. Das andere ist mir zu heikel, aber trotzdem danke für die Hilfe !

mfg
- VampireSilence