[Tutorial]Dialog in den Tray minimieren + menü

05/03/2009 15:37 Adroxxx#1
[Tutorial]Dialog in den Tray minimieren + menü
Ist ja schon etwas länger her, seitdem ich ein Tutorial geposted habe. Ich sage euch mal die Wahrheit, ich hatte keine Lust :P
Aber jetzt hat mich gerad wieder das Fieber gepackt und ich schreibe eins.


In diesem Tutorial werde ich euch zeigen, wie ihr euren Dialog in den Tray minimieren könnt und bei Rechtsklick ein Menü aufrufen könnt. Besonders bei Bot programmierern ist diese Technik beliebt. Und sie ist eigentlich recht Simpel.




#Inhalt:
[-]Voraussetzungen & Programme
[-]Dialog erstellen
[-]Funktion in der Header Datei
[-]Funktionen im Quelltext
[-]Menü erstellen
[-]Menü einbinden
[-]Nachwort




[-]Voraussetzungen & Programme

Voraussetzungen:
  • Kenntnisse im Umgang mit Visual Studio

Programme:
  • Visual Studio 2005 oder höher (keine Express Version)

An dieser Stelle sage ich es nochmal. Ich benutzte keine Express Version. Die Express Version ist zwar auch schön und gut wenn man Programmieren will, aber Programmiere hier mit MFC ( Microsoft Foundation Class) und die Express hat kein MFC. Ihr müsst euch also die Vollversion besorgen.



[-]Dialog erstellen

So, als Erstes erstellen wir eine neue Dialoganwendung, oder öffnen eine bestehende.
Wie das geht sollte ja nun nicht mehr das Problem sein. ;) Ich nenne mein Projekt: DialogTray

[Only registered and activated users can see links. Click Here To Register...]

Dann stellen wir aud Dialogbasierend und machen die ActiveX Steuerelemente weg. Außerdem solltet ihr auch die Minimieren-Schaltfläche aktivieren.
[Only registered and activated users can see links. Click Here To Register...]


[-]Funktion in der Header Datei

So nun gehen wir in die CDialogTrayDlg.h (Die Header datei für den Hauptdialog)

[Only registered and activated users can see links. Click Here To Register...]

Nun haben wir dort unter Protected: folgendes stehen:

PHP Code:
protected:
    
HICON m_hIcon;

    
// Generierte Funktionen für die Meldungstabellen
    
virtual BOOL OnInitDialog();
    
afx_msg void OnSysCommand(UINT nIDLPARAM lParam);
    
afx_msg void OnPaint();
    
afx_msg HCURSOR OnQueryDragIcon();
    
DECLARE_MESSAGE_MAP() 
Nun deklarieren wir unsere Funktion z.B. nach afx_msg void OnPaint();
Wir fügen also folgendes hinzu:

PHP Code:
LRESULT OnTrayNotification(WPARAM wParamLPARAM lParam); 


[-]Funktionen im Quelltext

So nun müssen wir unsere Funktionen hinzufügen. Auch wenn es etwas kompliziert aussieht, ist es das nicht.

Wir gehen in die DialogTrayDlg.cpp und fügen nach den Includes folgendes ein:

PHP Code:
#define WM_NOTIFICATION (WM_APP+100) 
Dann scrollen wir etwas weiter runter.
Irgendwann sollen wir folgendes sehen:

PHP Code:
BEGIN_MESSAGE_MAP(CDialogTrayDlgCDialog)
    
ON_WM_SYSCOMMAND()
    
ON_WM_PAINT()
    
ON_WM_QUERYDRAGICON()
    
//}}AFX_MSG_MAP
END_MESSAGE_MAP() 
(Das sollte eigentlich direkt über der Funktion OnIntitDialog sein. Also leicht zu finden)

Nach dem ON_WM_SYSCOMMAND() fügen wir folgendes ein:
PHP Code:
   ON_MESSAGE(WM_NOTIFICATIONOnTrayNotification
So nun scrollen wir noch ein Stück nach unten, bis wir folgende Funktion sehen:

PHP Code:
void CDialogTrayDlg::OnSysCommand(UINT nIDLPARAM lParam)
{
    if ((
nID 0xFFF0) == IDM_ABOUTBOX)
    {
        
CAboutDlg dlgAbout;
        
dlgAbout.DoModal();
    }
    else
    {
        
CDialog::OnSysCommand(nIDlParam);
    }

Und in die ELSE Anweisung schreiben wir folgendes:

PHP Code:
switch( nID){
         case 
SC_MINIMIZE:   {
                           
ShowWindow(SW_HIDE);
                           
NOTIFYICONDATA tnd;
                           
ZeroMemory(&tndsizeof (NOTIFYICONDATA));
                           
tnd.cbSize sizeof (NOTIFYICONDATA);
                           
tnd.hWnd m_hWnd;
                           
tnd.uID 1;
                           
tnd.uFlags NIF_MESSAGE|NIF_ICON|NIF_TIP;
                           
tnd.uCallbackMessage WM_NOTIFICATION;
                           
tnd.hIcon = (HICONLoadImage(AfxGetApp()->m_hInstanceMAKEINTRESOURCE(IDR_MAINFRAME),IMAGE_ICON16,16,LR_SHARED|LR_DEFAULTCOLOR);
                           
wcscpytnd.szTip_T("Mein Dialog"));
                           
Shell_NotifyIcon(NIM_ADD,&tnd);
                        }break;

         default:         
CDialog::OnSysCommand(nIDlParam); } 
So und wir scollen wieder etwas weiter runter. Nach der folgenden Funktion:
PHP Code:
HCURSOR CDialogTrayDlg::OnQueryDragIcon()
{
    return 
static_cast<HCURSOR>(m_hIcon);

Fügen wir unsere Funktion ein, die wir auch in der Header deklariert haben.

PHP Code:
LRESULT CDialogTrayDlg::OnTrayNotification(WPARAM wpLPARAM lp)
{
    switch (
lp){
      case 
WM_LBUTTONUP:   ShowWindow(SW_SHOW);
                     
NOTIFYICONDATA iconData;
                     
iconData.cbSize sizeof(NOTIFYICONDATA);
                     
iconData.hWnd this->GetSafeHwnd();
                     
iconData.uID 1;
                     return 
Shell_NotifyIcon(NIM_DELETE,&iconData);
    }
   return 
0;

Und ihr seid Fertig. Kompeliert das Projekt und wenn der Dialog offen ist, minimiert ihn. Dann sollte nur das das Icon im Tray zu sehen sein. Wenn ihr nun einen Linksklick da drauf macht, kommt der Dialog wieder hoch.


[-]Menü erstellen

So, natürlich wäre es super, wenn man den Bot , Hack oder jedes andere Programm was ihr habt, und es im Tray minimiert habt, von dort aus auch steuern könntet.

Also erstellen wir uns ein Menü. Wir gehen in die Ressourcenansicht und machen dort einen Rechtsklick und gehen auf "Ressource hinzufügen".
[Only registered and activated users can see links. Click Here To Register...]

Und dort wählen wir Menü und klicken auf Neu.

[Only registered and activated users can see links. Click Here To Register...]

Dann klicken wir auf unser Menü und dort wo "Hier eingeben" steht geben wir unsere Menüpunkte ein. Das erste ist wie man es von Menüs kennt, die Überschrift. Die datrunter die Menüeinträge für Funktionen.

[Only registered and activated users can see links. Click Here To Register...]




[-]Menü einbinden

Jetzt müssen wir unser Menü noch einbinden.
Dafür gehen wir wieder in unsere DialogTrayDlg.h

Nach den ganzen Protected sachen, schreiben wir :
PHP Code:
public:
CMenu m_TrayMenu
Damit haben wir nun ein CMenu Objekt angelegt. Und können von überall aus darauf zugreifen.

[Only registered and activated users can see links. Click Here To Register...]

Dann gehen wir in die DialogTrayDlg.cpp und scrollen runter zu unserer

LRESULT CDialogTrayDlg::OnTrayNotification(WPARAM wp, LPARAM lp) Funktion.

Wir erinnern uns:

PHP Code:
LRESULT CDialogTrayDlg::OnTrayNotification(WPARAM wpLPARAM lp)
{
    switch (
lp){
      case 
WM_LBUTTONUP:   ShowWindow(SW_SHOW);
                     
NOTIFYICONDATA iconData;
                     
iconData.cbSize sizeof(NOTIFYICONDATA);
                     
iconData.hWnd this->GetSafeHwnd();
                     
iconData.uID 1;
                     return 
Shell_NotifyIcon(NIM_DELETE,&iconData);
    }
   return 
0;

Nun fügen wir ein case WM_RBUTTONUP hinzu. Damit wenn wir einen Rechtsklick auf das TrayIcon machen, das Menü geladen wird.

Das sieht dann so aus:

PHP Code:
case WM_RBUTTONUPCPoint pt;    
    
GetCursorPos(&pt);
    
m_TrayMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,pt.x,pt.y,this); 
So jetzt scrollen wir noch etwas hoch. Bis wir die CDialogTrayDlg::OnInitDialog() Funktion finden.

Über dem return TRUE; sollte
// TODO: Hier zusätzliche Initialisierung einfügen

Da drunter schreiben wir:
PHP Code:
m_TrayMenu.LoadMenu(IDR_MENU1); 
Somit läd das Objekt immer unser erstelltes Menü. IDR_MENU1 ist die ID. Die kann natürlich anders sein, wenn ihr die verändert habt.
[Only registered and activated users can see links. Click Here To Register...]


Jetzt seid ihr fertig. Wenn ihr alles richtig gemacht habt, sollte wenn man auf die Minimieren Schaltfläche klickt, der Dialog in den Tray gehen. Bei Rechtsklick das Menü anzeigen und bei Linksklick wieder Maximiert werden.



[-]Nachwort

So ich hoffe es hat euch gefallen. Auch wenn es etwas kompliziert scheint, ist es doch recht einfach. Jetzt könnt ihr eure Hacks, Bots oder auch andere Programme in den Tray minimieren und von dort aus über ein Menü steuern!

Viel Spaß damit.
05/03/2009 16:11 RDTSC#2
Ich bin zwar nicht so dicke mit der Begrifflichkeit, aber sollte es nicht eher als "Howto" bezeichnet werden?
Im Grunde erklärst du ja recht wenig, sondern vielmehr gibst du Anweisungen, wodurch man ein Ergebnis erzielt, den Weg dahin aber nicht zwangsläufig versteht.
Abgesehen davon sieht der Aufbau und das Drumherum sehr schick aus.

Allerdings scheint es halt auch nach viel Aufwand für Pille-Palle zu sein, da man sich für Tray Icons nur ein wenig in die leicht herauszufindenen WinAPI Funktionen einlesen muss (hauptsächlich nur, um die richtigen Parameter zu pushen ;-)

Ist natürlich nur positive Kritik....
Ach, und wäre das Tutorial mit einer Nachrichtenschleife, die man selber abfängt, und ohne OOP nicht wesentlich hilfreicher? Wer benutzt schon MFC :P
05/03/2009 16:36 Adroxxx#3
Quote:
Originally Posted by RDTSC View Post
Ich bin zwar nicht so dicke mit der Begrifflichkeit, aber sollte es nicht eher als "Howto" bezeichnet werden?
Im Grunde erklärst du ja recht wenig, sondern vielmehr gibst du Anweisungen, wodurch man ein Ergebnis erzielt, den Weg dahin aber nicht zwangsläufig versteht.
Abgesehen davon sieht der Aufbau und das Drumherum sehr schick aus.
Naja Tutorial, heißt ja auch mehr oder weniger Anleitung. Frei übersetzt.
Für mich ist eigentlich HowTo auch nichts anderes als Tutorial.
Aber du hast schon recht, hier erkläre ich jetzt recht wenig. Das hat aber auch den Grund, weil wenn ich echt alles Erklären würde, was etwas macht usw. wäre das Tutorial Länger als alle meine vorherigen zusammen. Weil ich dann auf alles mögliche eingehen müsste. Weil wenn ich schon was erkläre dann richtig xD Und das wäre mir jetzt auch zu aufwendig xD

Bei einigen Sachen kann man sich das natürlich denken, was es macht. Wie z.B.
PHP Code:
wcscpytnd.szTip_T("Mein Dialog")); 
Da sieht man szTip und da wird ein String reinkopiert. Also kann man sich denken dass, das für den TrayTip ist.

Aber die Frage ist muss ich unbedingt wissen was genau
PHP Code:
tnd.uCallbackMessage WM_NOTIFICATION
macht?

Ich glaube besonders bei diesem Beispiel reicht es wenn man weiß, das man das braucht. Besonders das Minimieren in den Tray ist eine recht geradlinige Sache. Sprich man kann bzw braucht da nicht viel Modifizieren. Programm wird ausgeblendet, Icon im Tray, Bei Klick Programm eingeblendet. Ist ein fester Ablauf, daum braucht man imo nicht genau wissen wie dies zu stande kommt. Wer daran Interessiert ist, kann sich ja in der MSDN schlau darüber machen.

Quote:
Originally Posted by RDTSC View Post
Allerdings scheint es halt auch nach viel Aufwand für Pille-Palle zu sein, da man sich für Tray Icons nur ein wenig in die leicht herauszufindenen WinAPI Funktionen einlesen muss (hauptsächlich nur, um die richtigen Parameter zu pushen ;-)
Eigentlich kann ich nicht bestätigen das es "viel" Aufwand ist. Sieht vielleich etwas viel aus, aber eigentlich ist es ja nur die OnTrayNotification Funktion und die case im OnSysCommand.

Quote:
Originally Posted by RDTSC View Post
Ist natürlich nur positive Kritik....
Ach, und wäre das Tutorial mit einer Nachrichtenschleife, die man selber abfängt, und ohne OOP nicht wesentlich hilfreicher? Wer benutzt schon MFC :P
Ich benutzte MFC :P Das Problem bei besonders C++ Tutorials die mit GUI sind, die Übertragbarkeit auf andere Systeme / Libs usw.
Weil ich glaube kaum, das es viele Leute gibt, die ihre GUIs wenn sie unter C++ in Windows Programmieren per Hand, per API aufbauen. Das ist zu viel Arbeit.
Aber es gibt halt welche die vielleicht GTK, QT, oder auch andere GUIs benutzten. Für welche soll ich jetzt das Tutorial schreiben? Ich kann es zwar in pure c++ mit API schreiben, aber wenn jemand irgendeine Lib benutzt, wo es einfacher geht, wieso soll er sich dann die Arbeit machen und das mit API machen?

Deswegen habe ich für mich entschieden das ich meine Tutorials in denen es auch um Programmierung geht, in MFC mache. Der Grund ist einfach der das ich schon länger mit MFC programmiere. Auch bei meinen anderen Tutorials wie "Dialogfarbe ändern" oder das "General Gamehacking" Tutorial benutzte ich MFC. Und auch in folgenden werde ich MFC benutzten.
MFC ist zwar manchmal recht nervig, ist aber bei vielen sachen recht bequem. :P

Ich finde halt, man muss sich schon für eins entscheiden um wirklich spezifische Tutorials zu schreiben. Ich will z.B. bald ein's machen wie man Tabs bzw TabControl unter MFC benutzt. Damit man Tabs in seinem Dialog hat. Das kann ich halt nur Spezifisch machen. Unter GTK geht das wahrscheinlich anders, vll auch einfacher. Wobei ich muss zugeben, bei der Tabs geschichte, bin ich am mogeln, weil ich dort eine externe klasse benutzte, weil die mfc interne geschichte, etwas aufwendig ist.
05/03/2009 18:02 Gianotti#4
great tut^^

PS: bist du anwednungsentwickler? weil du ja ne ausbildung gemacht hast dafür o0
05/03/2009 18:06 Adroxxx#5
Ich bin staatl. geprüfter Game Hacker!
05/03/2009 21:51 RDTSC#6
"mit einer Nachrichtenschleife, die man selber abfängt"
Hab' mich verschrieben :0
Natürlich sollte es "mit einer eigenen Nachrichtenschleife", "mit selber abgefangenen Nachrichten" o.ä. heißen.

Mit 'viel Aufwand für Pille-Palle' meinte ich, dass dein Tutorial nach (dafür zu viel) Mühe aussieht.

Vielleicht kannst du ja für die Unwissenden das nächste Mal z.B. die Parameter erläutern, oder bei Befehlen, die weniger transparent sind, sagen, was damit erzielt wird ;-)

[ Edit ]
Wollte eigentlich auch noch schreiben (hab's beim Verfassen des Posts dann aber wieder vergessen):
Wenn ich GUIs verwenden will, schreibe ich mir immer eine eigene Nachrichtenschleife, bleibt also alles im Rahmen der WinAPI.
Nur die Dialoge erzeuge ich nicht mit Code, sondern bette sie als Resource ein, wäre sonst zu lästig :-)
05/03/2009 22:01 Adroxxx#7
Quote:
Originally Posted by RDTSC View Post
"mit einer Nachrichtenschleife, die man selber abfängt"
Hab' mich verschrieben :0
Natürlich sollte es "mit einer eigenen Nachrichtenschleife", "mit selber abgefangenen Nachrichten" o.ä. heißen.

Mit 'viel Aufwand für Pille-Palle' meinte ich, dass dein Tutorial nach (dafür zu viel) Mühe aussieht.

Vielleicht kannst du ja für die Unwissenden das nächste Mal z.B. die Parameter erläutern, oder bei Befehlen, die weniger transparent sind, sagen, was damit erzielt wird ;-)

[ Edit ]
Wollte eigentlich auch noch schreiben (hab's beim Verfassen des Posts dann aber wieder vergessen):
Wenn ich GUIs verwenden will, schreibe ich mir immer eine eigene Nachrichtenschleife, bleibt also alles im Rahmen der WinAPI.
Nur die Dialoge erzeuge ich nicht mit Code, sondern bette sie als Resource ein, wäre sonst zu lästig :-)
Wenn ich ein Tutorial mache, heißt es immer viel Mühe für mich xD Brauchst dir nur die anderen mal anschauen, sind auch so lang und mit bildchen usw. Manche sogar länger ^,^

Ich werd vielleicht später...naya eher die Tage mal, das Tutorial nochmal etwas überarbeiten. Ich werd dann im Quelltext Kommentare zu den einzelnen Sachen machen. Damits im Rahmen bleibt, was den Aufwand angeht, aber man dann weiß - mehr oder weniger - wozu die sachen da sind. Werds mir auch mal für folgende Tutorials merken, etwas mehr zu erklären *g*

Ja jeder Programmiert jetzt etwas anders, wiegesagt ich mach's ja über MFC und da siehste ja wie viel das ist. Wenn man das per Hand macht, sollte das aber imo auch nicht weniger Arbeit sein ;)

Als nächstes werd ich mal das Dialog mit Tabs Tutorial machen. Wird aber leider auch in MFC sein :P
05/04/2009 20:08 Gianotti#8
das fänd ich auch toll XD sag mal wirste jetzt mod?o0