tray icon ohne Fenster?

AckiB

Mitglied
hallo, ich habe mal wieder ein Problem ;)
ich habe folgenden Code, um ein Programm als Icon in der "tray bar" anzuzeigen:

tray.h
Code:
#ifndef _TRAY_H_
#define _TRAY_H_


#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>
#include "resources.rch"

#ifndef RC_INVOKED //variable definitions and function prototypes just confuse the resource compiler

void minimize(HWND hwnd);
void restore(HWND hwnd);

bool minimized = false;
const int TASKBARCREATED = RegisterWindowMessage("TaskbarCreated");

#endif // 8: #ifndef RC_INVOKED

#define IDI_ICON        0
#define IDC_MINIMIZE    1
#define IDI_TRAYICON    2
#define IDM_TRAYEXIT    3
#define IDM_TRAYHELP    4
#define IDM_TRAYABOUT   5
#define MSG_MINTRAYICON (WM_USER+0)


#endif // 1: #ifndef _TRAY_H_

tray.cpp
Code:
#include "tray.h"
#include <stdio.h>

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

char szClassName[ ] = "TrayMinimizerClass__";

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil){
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;

    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);

    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))
        return 0;

    hwnd = CreateWindowEx (
           0,
           szClassName,
           "Minimize to Tray Example",
           WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           544,
           375,
           HWND_DESKTOP,
           NULL,
           hThisInstance,
           NULL
           );

    ShowWindow (hwnd, nFunsterStil);

    while (GetMessage (&messages, NULL, 0, 0)){
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    if ( (message == TASKBARCREATED) && (minimized) ){
        minimize(hwnd);
        return 0;
    }

    switch (message){
        case WM_CREATE:
            CreateWindowEx(0, "BUTTON", "Click to minimize to tray", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT | BS_CENTER | BS_VCENTER, 200, 50, 300, 25, hwnd, (HMENU)IDC_MINIMIZE, GetModuleHandle(NULL), NULL);
            break;
        case WM_COMMAND:
            if ( (HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_MINIMIZE) ){
                if (minimized) restore(hwnd);
                else minimize(hwnd);
            }
            break;
        case MSG_MINTRAYICON:{
            if (wParam != IDI_TRAYICON) break;
            if (lParam == WM_LBUTTONUP){
                restore(hwnd);
            }

            else if (lParam == WM_RBUTTONUP){
                HMENU myMenu = NULL;
                myMenu = CreatePopupMenu();

                AppendMenu(myMenu, MF_STRING, IDM_TRAYEXIT, "Exit");
                AppendMenu(myMenu, MF_STRING, IDM_TRAYHELP, "Help");
                AppendMenu(myMenu, MF_STRING, IDM_TRAYABOUT, "About");

                DWORD mp = GetMessagePos(); //get the position of the mouse at the time the icon was clicked (or, at least, the time this message was generated).

                SetForegroundWindow(hwnd); //even though the window is hidden, we must set it to the foreground window because of popup-menu peculiarities. See the Remarks section of the MSDN page for TrackPopupMenu.
                UINT clicked = TrackPopupMenu(myMenu, TPM_RETURNCMD | TPM_NONOTIFY /*don't send me WM_COMMAND messages about this window, instead return the identifier of the clicked menu item*/, GET_X_LPARAM(mp), GET_Y_LPARAM(mp), 0, hwnd, NULL); //display the menu. you MUST #include <windowsx.h> to use those two macros.
                SendMessage(hwnd, WM_NULL, 0, 0); //send benign message to window to make sure the menu goes away.
                if (clicked == IDM_TRAYEXIT) SendMessage(hwnd, WM_DESTROY, 0, 0);
                else if (clicked == IDM_TRAYHELP) MessageBox(hwnd, "Click the button to minimize to the system tray.", "Tray Example Help", MB_OK | MB_ICONINFORMATION);
                else if (clicked == IDM_TRAYABOUT) MessageBox(hwnd, "Tray Example: Demonstrates minimizing a window to the tray.", "About Tray Example", MB_OK | MB_ICONINFORMATION);
            }
        }
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

void minimize(HWND hwnd){
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hwnd;
    nid.uID = IDI_TRAYICON;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage = MSG_MINTRAYICON;
    nid.hIcon = (HICON)LoadImage(
        GetModuleHandle(NULL),
        MAKEINTRESOURCE(prgIcon),
        IMAGE_ICON,
        16, 16,
        0); 
    strcpy(nid.szTip, "My very own system tray icon!");
    Shell_NotifyIcon(NIM_ADD, &nid);
    ShowWindow(hwnd, SW_HIDE);
    minimized = true;
}

void restore(HWND hwnd){
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hwnd;
    nid.uID = IDI_TRAYICON;
    Shell_NotifyIcon(NIM_DELETE, &nid);
    ShowWindow(hwnd, SW_SHOW);
    minimized = false;
}
die Resource-Datei(en) spare ich mir hier, da wird nur das Icon definiert... :D

ok, das läuft wunderbar...

was aber, wenn ich kein Windows-Fenster habe?
z.B. wenn ich ein FLTK-Fenster oder sogar nur eine DOS-Anwendung habe? :eek:
ich kann das Icon dann zwar im Tray anzeigen, aber ich habe dann ja keine Callback-Funktion und kann somit nicht feststellen ob und was/wie das Tray-Icon angeklickt wurde !? :(

bei einem FLTK-Fenster mache ich das jetzt so, dass ich ein Windows-Fenster erstelle (wie oben) und dieses dann verstecke, indem ich es als child des FLTK-Fensters definiere und außerhalb des FLTK-Fensters platziere...
das finde ich aber mehr als unelegant! :rolleyes:

hat da jemand eine Idee zu?

danke, Acki
 
Zuletzt bearbeitet:
Das Fenster muß ja nicht zwingend sichtbar sein, soweit ich weiß. Einfach ein unsichtbares Fenster erzeugen und die Tray-Icon-Messages bearbeiten.
 
Einfach von vornherein nicht
Code:
 ShowWindow (hwnd, nFunsterStil);
ausführen.
Dann brauchst du später auch nichts extra zu verstecken.

Gruß
MCoder
 
Für message only (nicht sichtbar aber fähig nachrichten zu emfangen gilt:

- CreateWindow/CreateWindowEx wird mit hWndParent = HWND_MESSAGE aufgerufen

- ein evt. ShowWindow sollte theoretisch entfällen können, kann jedoch auch explizit mit SW_HIDE aufgerufen werden.
 
vielen Dank, für eure Antworten! :)
aber so, wie ich Das verstehe, muss ich dafür auf jeden Fall ein Fenster erstellen?
wie ich das Fenster dann "verstecke" ist erstmal nebensächlich, aber ohne geht's nicht? :eek:

ich hatte mir schon fast sowas gedacht, aber gehofft, dass es auch ohne geht...
naja, dann muss ich wohl damit leben müssen... :(

sollte noch jemand eine andere Idee haben, immer her damit! :D

danke, Acki
 
Zurück