Wie ermittle ich die Position eines TrayIcons?
-
Hallo,
ich habe ein Problem mit der Bestimmung der Position eines TTrayIcons in der SysTray.
Ich würde die Koordinaten des TrayIcons ermitteln, aber irgendwie gibt es keine Funktion oder Eigenschaft in der Klasse TTrayIcon.
Kennt jemand einen Rat oder hat ne Idee?
P.S. Also ich will es nicht mit GetCursorPos machen, sondern ohne irgendwelche Maus-Funktionen!
-
Hallo,
die Top-Position kann man berechnen...
Screen->Height - ((Screen->Height - Screen->WorkAreaHeight) / 2 - (ImageList1->Height) / 2); /* ImageList1 ist die ImageList, aus der du das Icon für dein TrayIcon holst... */
...weiter wüsst ich auch nicht. Wofür brauchst du das denn? Und was spricht gegen die Nutzung der Mausposition.
LG, Micha
-
Da es sich beim Systray um eine Komponente handelt, welche über Button-Elemente verfügt, besteht die Möglichkeit diese Auszulesen.
Die Windows API bietet auch die Möglichkeit, die Position der Buttons zu Bestimmen und deren Grösse.
Soviel ich in Erinnderung habe, handelt es sich bei diesen Befehlen um Messages welche mit dem Prefix "LB_" beginnen.
Ich werden mal nachsehen. Vielleicht kann ich am Abend ein kleinen Beispielcode dazu liefern.
-
Wie versprochen hier der Quelltext einer kurzen Testanwendung.
Folgendes wird gemacht.
- Auslesen der sichtbaren Traysymbole
- Speicherung in einem Map-Container
- Ermitteln der Positionen in Bezug auf den oberen linken Punkt (0,0) des MonitorsGetestet mit:
- C++Builder 2009
- Windows XP Service Pack 3Hier der Hauptcode:
Main.h//--------------------------------------------------------------------------- #ifndef mainH #define mainH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> //--------------------------------------------------------------------------- #include <map> #include "needStructs.h" //--------------------------------------------------------------------------- class TF_Hauptformular : public TForm { __published: // IDE-verwaltete Komponenten TButton *BTN_Tray_Generate_List; void __fastcall BTN_Tray_Generate_ListClick(TObject *Sender); private: // Benutzer Deklarationen void __fastcall vf_Generate_TrayList(HWND hwndTrayNotifyWND,std::map<int,structTrayItemInfo> *mapTrayItems); void __fastcall vf_Generate_TrayPositions(HWND hwndTrayNotifyWND,std::map<int,structTrayItemInfo> *mapTrayItems); HWND __fastcall Get_Tray_Handle(); public: // Benutzer Deklarationen __fastcall TF_Hauptformular(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TF_Hauptformular *F_Hauptformular; //--------------------------------------------------------------------------- #endif
Main.cpp
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "main.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TF_Hauptformular *F_Hauptformular; //--------------------------------------------------------------------------- __fastcall TF_Hauptformular::TF_Hauptformular(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TF_Hauptformular::BTN_Tray_Generate_ListClick(TObject *Sender) { std::map<int,structTrayItemInfo> mapTrayItems; std::map<int,structTrayItemInfo>::iterator mapItTrayItems; HWND hwndTray; mapTrayItems.clear(); hwndTray=Get_Tray_Handle(); vf_Generate_TrayList(hwndTray,&mapTrayItems); vf_Generate_TrayPositions(hwndTray,&mapTrayItems); } //--------------------------------------------------------------------------- void __fastcall TF_Hauptformular::vf_Generate_TrayList(HWND hwndTrayNotifyWND,std::map<int,structTrayItemInfo> *mapTrayItems) { //Struct welches die Daten aufnimmt structTrayItemInfo stiiTrayInformations; int iAnzahlItems; //Definition der Variabeln zur Auslesung der Informationen TBBUTTONINFOA tbBtnInfo, *_tbBtnInfo; //Struktur zur Auslesung der Button Informationen char cButtonText[256],*_cButtonText; //Speichert den Text des Buttons //Definition der Processvariabeln NMHDR nmMessageStructure; HANDLE hwProcess; unsigned long ulProcessID; //Auslesen der Anzahl Elemente iAnzahlItems=SendMessage(hwndTrayNotifyWND,TB_BUTTONCOUNT,0,0); //Auslesen der ProcessorID des Fensters (Speicherung in ulProcessID) //Starten eines neuen Prozesses mit lese und schreibrechten //Das Ganze in einer Informationsabfrage GetWindowThreadProcessId(hwndTrayNotifyWND, &ulProcessID); hwProcess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ| PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, ulProcessID); //Freigabe des Speichers (Buffer) für das Element und den Text _tbBtnInfo=(TBBUTTONINFOA*)VirtualAllocEx(hwProcess, NULL, sizeof(TBBUTTONINFOA), MEM_COMMIT, PAGE_READWRITE); _cButtonText=(char*)VirtualAllocEx(hwProcess, NULL, 256, MEM_COMMIT, PAGE_READWRITE); for (int i = 0; i < iAnzahlItems; i++) { //dwMask (TBIF_COMMAND) -> Ermitteln mittels eindeutigen Identifikator //dwMask (TBIF_TEXT) -> Auslesen des Textes //dwMask (TBIF_STYLE) -> Auslesen des Styles, damit Gruppierbuttons nicht beachtet werden //(pszText) Angabe der Textgrösse; (pszText) Pointer zur Variabel welche den Text aufnimmt //(cbSize) Übergabe der Grösse der Struktur, damit die Informationen abgeholt werden können tbBtnInfo.dwMask=TBIF_COMMAND | TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT; tbBtnInfo.cchText=256; tbBtnInfo.pszText=_cButtonText; tbBtnInfo.cbSize=sizeof(TBBUTTONINFOA); //Freigabe des Buffers, damit die Informationen reingeschrieben werden können WriteProcessMemory(hwProcess, _tbBtnInfo, &tbBtnInfo, sizeof(TBBUTTONINFOA), NULL); //Senden der Informationen, welche gelesen werden sollen SendMessage(hwndTrayNotifyWND, TB_GETBUTTONINFO, (WPARAM)i, (LPARAM)_tbBtnInfo); //Auslesen der Angaben des Textes und der anderen Informationen ReadProcessMemory(hwProcess, _tbBtnInfo, &tbBtnInfo, sizeof(TBBUTTONINFOA), NULL); ReadProcessMemory(hwProcess, _cButtonText, cButtonText, 256, NULL); //Der Button wird nur hinzugefügt, wenn dieser auch sichtbar ist if (static_cast<BOOL>(tbBtnInfo.fsStyle & TBSTATE_HIDDEN)==false) { //Hinzufügen des Eintrags zur Map stiiTrayInformations.~structTrayItemInfo(); stiiTrayInformations.iID=tbBtnInfo.idCommand; stiiTrayInformations.sCaption=static_cast<UnicodeString>(cButtonText); mapTrayItems->insert(std::pair<int,structTrayItemInfo>(stiiTrayInformations.iID,stiiTrayInformations)); } } //Freigeben des Reservierten Speichers VirtualFreeEx(hwProcess, _tbBtnInfo, 0, MEM_RELEASE); VirtualFreeEx(hwProcess, _cButtonText, 0, MEM_RELEASE); } //--------------------------------------------------------------------------- void __fastcall TF_Hauptformular::vf_Generate_TrayPositions(HWND hwndTrayNotifyWND,std::map<int,structTrayItemInfo> *mapTrayItems) { std::map<int,structTrayItemInfo>::iterator mapItTrayItems; POINT ptPosition; unsigned long pid; HANDLE process; char cTaskText[512]; char *_cTaskText; NMHDR MessageStructure; RECT *_Rechteck,Rechteck; GetWindowThreadProcessId(hwndTrayNotifyWND, &pid); process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ| PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid); _Rechteck=(RECT*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE); mapItTrayItems=mapTrayItems->begin(); while (mapItTrayItems!=mapTrayItems->end()){ WriteProcessMemory(process, _Rechteck, &Rechteck, sizeof(RECT), NULL); SendMessage(hwndTrayNotifyWND, TB_GETITEMRECT, (WPARAM)mapItTrayItems->first, (LPARAM)_Rechteck); ReadProcessMemory(process, _Rechteck, &Rechteck, sizeof(RECT), NULL); //Konvertieren der Position ptPosition.x=Rechteck.left; ptPosition.y=Rechteck.top; ::ClientToScreen(hwndTrayNotifyWND,&ptPosition); mapItTrayItems->second.iXPos=ptPosition.x; mapItTrayItems->second.iYPos=ptPosition.y; mapItTrayItems->second.iWidth=Rechteck.right-Rechteck.left; mapItTrayItems->second.iHeight=Rechteck.bottom-Rechteck.top; ++mapItTrayItems; } VirtualFreeEx(process, _Rechteck, 0, MEM_RELEASE); } //--------------------------------------------------------------------------- HWND __fastcall TF_Hauptformular::Get_Tray_Handle() { HWND hwndReturnValue; //Als erstel wir die komplette Taskleiste ermittels hwndReturnValue=FindWindow("Shell_TrayWnd", NULL); //Anschliessend wird der 2 Bereich gesucht, welcher die Traysymbole beinhaltet hwndReturnValue=FindWindowEx(hwndReturnValue,NULL,"TrayNotifyWnd",NULL); //Nun kann die Leiste mit den Traysymbolen ermittelt werden hwndReturnValue=FindWindowEx(hwndReturnValue,NULL,"Syspager",NULL); //Und nochmals ein unterelement hwndReturnValue=FindWindowEx(hwndReturnValue,NULL,NULL,"Infobereich"); return hwndReturnValue; } //---------------------------------------------------------------------------
Und hier noch das Struct in einer separaten Datei welches ich für den Map-Container verwendet habe.
neesStructs.h//--------------------------------------------------------------------------- #include <vcl.h> #ifndef needStructsH #define needStructsH //--------------------------------------------------------------------------- struct structTrayItemInfo{ int iID; UnicodeString sCaption; int iXPos; int iYPos; int iWidth; int iHeight; structTrayItemInfo(); }; //--------------------------------------------------------------------------- #endif
needStructs.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "needStructs.h" //--------------------------------------------------------------------------- #pragma package(smart_init) structTrayItemInfo::structTrayItemInfo(){ iID=-1; sCaption=EmptyStr; iXPos=-1; iYPos=-1; iWidth=-1; iHeight=-1; };
Ich hoffe, dir mit diesem Beispiel geholfen zu haben.
Falls du mit Position die Position des Items in der Liste meinst (nicht koordinaten). So kannst du "i" in der for-Schleife für die Position verwenden. (Prozedur [vf_Generate_TrayList]). Denn das Tray wird von rechts nach links ausgelesen.Für die eindeutige Identifikation des Buttons dient die ID (kann einen anderen Wert haben als die Position).
Unter "Link war ungültig. Der neue steht in meinem nächsten Beitrag" könntest du sonst auch das Beispielprojekt herunterladen.
-
Wow! Herzlichen Dank! Es ist genau das, was ich gesucht hatte...
Ich werde es mal ausprobieren!
-
Ich habe noch kurz einen kleinen Fehler korrigiert, welcher aufgetreten wäre, wenn eines der Icons geschlossen worden wäre, denn dann hätten nicht mehr alle ausgelesen werden können.
Die korrigierte Zeile ist in der Main.cpp
-> Eigenschaft hinzugefügt (TBIF_BYINDEX)tbBtnInfo.dwMask=TBIF_COMMAND | TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT;
Anmerkung.
Für Symbole die ausgeblendet wurden, sollte bei der Position und grösse -1 oder sonst ein ungültiger wert erscheinen. (das hab ich jetzt nicht abgefangen).ps: der download wurde auch nochmals angepass.
!!! Edit:
Der Link heisst nun http://rrworldfiles.foroomy.com/download/file.php?id=6