|
Antwort |
Razor
(Gast)
n/a Beiträge |
#1
So far i've done this so far but i need help becouse i don't that much c++.
Delphi-Quellcode:
unit Unit3;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm3 = class(TForm) Button1: TButton; Procedure findtray; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form3: TForm3; hwndparent,hwndtray,hwndpager,hwndtoolbar:hwnd; implementation function trayiconcount:integer; var TB_BUTTONCOUNT:integer; begin TB_BUTTONCOUNT:=$418; result:=sendmessage(hwndtoolbar,tb_buttoncount,0,0); end; {$R *.dfm} procedure TForm3.Button1Click(Sender: TObject); begin findtray; form3.caption:=inttostr(trayiconcount); end; Procedure Tform3.findtray; begin hwndparent:=findwindow('shell_traywnd',nil); hwndtray:=findwindowex(hwndparent,0,'traynotifywnd',nil); hwndpager:=findwindowex(hwndtray,0,'syspager',nil); hwndtoolbar:=findwindowex(hwndpager,0,'toolbarwindow32',nil); end; function trayicondata:integer; var hprocess,explorerpid, bytes,length:integer; pexplorerpid,pbyte,pbutt :^integer; begin pexplorerpid:=nil; explorerpid:=0; bytes:=4096; pbyte:=@bytes; pbutt:=windows.VirtualAllocEx(hprocess,pbyte,4096,4096,4); windows.GetWindowThreadProcessId(hwndtoolbar,pexplorerpid ) ; result:=windows.OpenProcess(2035711,false,explorerpid); if hprocess=0 then end; end.
Zitat:
Working with the System Tray in .Net
Introduction Since I released the last version of the Sidebar (admittedly some time ago), Iʼve had a lot of PMs and emails asking how exactly you communicate with the System Tray through .Net. The answer is that itʼs not easy. Unless youʼre very confident in .Net, you should probably turn away. We need to deal with variables in other processes memory spaces, and most of it is done in unsafe code. Note: This article is written with C# code examples only Step One: Find the System Tray The first thing we need to do in order to interact with the tray is find itʼs hWnd. This method uses the native FindWindow function to locate first the whole Taskbar. Then the FindWindowEx function is used to go down the tree of child windows, until we find the hWnd of the tray, which is a window of class ToolbarWindow32. Both FindWindow and FindWindowEx are found in the user32.dll library. One important detail of this code is that we find windows by using their class names and parent windows only. This allows the code to work on machines with different languages. As a result of this method, we have the hWnd of the tray, which is just a ToolbarWindow32 underneath. We can exploit this to access information about the buttons it contains.
Code:
Working with the System Tray in .Net
private IntPtr FindTray()
{ IntPtr hwndParent = NativeMethods.FindWindow("Shell_TrayWnd", null); IntPtr hwndTray = NativeMethods.FindWindowEx(hwndParent, IntPtr.Zero, "TrayNotifyWnd", null); IntPtr hwndPager = NativeMethods.FindWindowEx(hwndTray, IntPtr.Zero, "SysPager", null); hwndParent = NativeMethods.FindWindowEx(hwndPager, IntPtr.Zero, "ToolbarWindow32", null); return hwndParent; } © Karl Wagner, 2008 Page 1 of 7 Step Two: Count the number of tray items As I mentioned earlier, the system tray is just a standard ToolbarWindow32. We can demonstrate this, by having our program count the number of items in the tray. The ToolbarWindow32 responds to the TB_BUTTONCOUNT message, so all we have to do is send that message to the hWnd to count the number of items in the tray. This method simply sends the button count message to the system tray. Note that the number returned will probably be different from what you see, because many applications run with invisible icons, especially those with animated tray icons (more on those later). Step Three: Get the button information This is where things start to get complicated. We can count the number of buttons in the system tray easily, because that gives a result through the messaging system. Getting detailed information back from messages requires a bit more work. There are 2 structures and a String that we need to populate with information for each button: a TRAYDATA and TBBUTTON structure, and a String. • The TRAYDATA and TBBUTTON give us information about the button itself • And weʼll use the String to store its ToolTip text For convenience, I group these members together in the TrayIconData class Note: The definitions for these structures are provided in the Appendix for convenience
Code:
The dwData member of the TBBUTTON structure gives us a pointer to the TRAYDATA
private unsafe TrayIconData[] getButtons()
{ byte[] buffer = new byte[4096]; TrayIconData[] data = new TrayIconData[1]; //Find Explorer’s PID uint ExplorerPID = 0; NativeMethods.GetWindowThreadProcessId(_systray, out ExplorerPID); //Hence get an hProcess IntPtr hProcess = NativeMethods.OpenProcess(2035711, false, ExplorerPID); In this first part of the method, we declare its signature (note that the method is unsafe - we use coding practices that .Net does not typically allow. Make sure you allow unsafe code in your project). private int GetTrayIconCount() { uint TB_BUTTONCOUNT = 0x418; int iconCount = (int)NativeMethods.SendMessage(_systray, TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero); return iconCount; } Working with the System Tray in .Net © Karl Wagner, 2008 Page 2 of 7 We then use the system trayʼs hWnd to find the Process ID (PID) of its process, which is explorer.exe. From explorerʼs PID, we can obtain a handle to the process through the OpenProcess method. [pre]if (hProcess != IntPtr.Zero) { //Allocate some memory for the button data IntPtr butt = NativeMethods.VirtualAllocEx(hProcess, IntPtr.Zero, new UIntPtr(4096), 4096, 4); int length = this.TrayItemCount; data = new TrayIconData[length]; for (int id = 0; id < length; id++) { data[id] = new TrayIconData(); fixed (TBBUTTON* tbbuttonRef = &data[id].button) { IntPtr lpBuffer = new IntPtr((void*)tbbuttonRef); //Get the button data for the id‐th button, let it get written to the memory we allocated NativeMethods.SendMessage(_systray, 1047, new IntPtr(id), butt); int num = 0; IntPtr lpNumberOfBytesRead = new IntPtr((void*)&num); //Read the data back in to our TBBUTTON structure if (NativeMethods.ReadProcessMemory(hProcess, butt, lpBuffer, new UIntPtr((uint)sizeof(TBBUTTON)), lpNumberOfBytesRead)) [/pre] With this section of the method, we first check if the hProcess for explorer that we obtained before is valid. If it is, we use the VirtualAllocEx method to allocate some memory in explorerʼs context. Since we are using .Net, we need to create our structures in explorerʼs memory space, call the methods to retrieve button information, having the results stored where we allocated before, and then read the results out. So after we have allocated some memory in explorerʼs space, we create an array of TrayIconData classes for each button in the system tray (using the counting method from Step Two). Then, we use the fixed statement to stop the Garbage Collector moving the class we are working on, and create a pointer to the TBBUTTON member of the class (this is were we need unsafe code). Once we have the pointer, we ask the system tray to populate the TBBUTTON structure we allocated in explorerʼs space, and then read that memory back in to the TBBUTTON structure that we fixed in our own space. Working with the System Tray in .Net © Karl Wagner, 2008 Page 3 of 7 { //Create a fixed TRAYDATA structure fixed (TRAYDATA* traydataRef = &data[id].traydata) { IntPtr ptr5 = new IntPtr((void*)traydataRef); //Read the value back in to our TRAYDATA structure NativeMethods.ReadProcessMemory(hProcess, new IntPtr(data[id].button.dwData), ptr5, new UIntPtr((uint)sizeof(TRAYDATA)), lpNumberOfBytesRead); } structure for the button. However, we copied this from explorerʼs memory space, so that pointer points to a location in explorerʼs space. To retrieve the TRAYDATA structure from explorerʼs space, we use the ReadProcessMemory function, as we did for the TBBUTTON.
Code:
In this final section of the method, we create a buffer for the string giving us the buttonʼs
fixed (byte* numRef = buffer)
{ //Get the button's text in to the allocated memory int len = (int)NativeMethods.SendMessage(_systray, 1099, (IntPtr)data[id].button.idCommand, butt); if (len != ‐1) { //And read it back, putting it in the text object IntPtr ptr6 = new IntPtr((void*)numRef); if (NativeMethods.ReadProcessMemory(hProcess, butt, ptr6, new UIntPtr(4096), lpNumberOfBytesRead)) data[id].Text = Marshal.PtrToStringAuto(ptr6, len); else data[id].Text = ""; } else data[id].Text = ""; } } } } NativeMethods.VirtualFreeEx(hProcess, butt, UIntPtr.Zero, 32768); } return data; } text. In much the same way as we have done before, we send the tray a message put the buttonʼs text in to explorerʼs memory space, and read it out. We end the method by calling the VirtualFreeEx method to free the memory that we allocated in explorerʼs space, and returning the array of TrayIconData classes - each class containing the information we need to reconstruct the button it represents. Working with the System Tray in .Net © Karl Wagner, 2008 Page 4 of 7 Step Four: Get the buttonʼs icon Retrieving the icon for a button is a simple procedure. However, you should be aware of the state of each button before retrieving its icon. The system tray has many invisible icons - some for applications, some for animation purposes (each frame gets a new icon, and one is visible at any time). Obviously we donʼt want these to be shown. To check for invisibility, check the fsState member of the TBBUTTON structure. If it equals 8, the button is hidden and should not be displayed.
Code:
This method creates an ImageSource from the hIcon of a button. This image source can
private ImageSource makeImageSource(TrayIconData ButtonData)
{ ImageSource img = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(ButtonData.traydata.hIcon, Int32Rect.Empty, null).Clone(); DestroyIcon(ButtonData.traydata.hIcon); return img; } then be applied to any WPF object that supports it, and we will have recreated the icon. We return a clone of the source that is created from the hIcon, as the original is destroyed to avoid leaving open handles to the original icon. It is worth noting that some applications (such as Windows Live Messenger) use a nonstandard icon format that is not supported by this method. There does not seem to be any documentation on this icon format. Step Five: Interact with the button Simply having an icon is not enough to duplicate the system tray - we need some type of interaction with the buttons. We have already seen how to retrieve the tooltip text. Now we will see how to send events to the buttons. What happens is that we use event handlers for our icon to emulate clicking the real tray icon. We use the messaging system to send the tray button the click event. Most tray buttons will launch a standard system context menu, which is placed wherever the mouse is when the system gets the command to show it. Hence when the user clicks our button, the menu appears to have been created from our button, but it has actually been created by the real tray button.
Code:
This event handler uses the PostMessage method to send the left button down event to
void SysTrayIconView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ PostMessage(ButtonData.traydata.hwnd, ButtonData.traydata.uCallbackMessage, (int)ButtonData.traydata.uID, 0x201); IntPtr ptr = SetForegroundWindow(ButtonData.traydata.hwnd); e.Handled = true; } the button specified by the ButtonData member. Working with the System Tray in .Net © Karl Wagner, 2008 Page 5 of 7 For each event, there is a different message to send Event Message Left Button Down 0x201 Left Button Up 0x202 Right Button Down 0x204 Right Button Up 0x205 Final Thoughts This guide has shown you how to interact with the system tray from a .Net application. There are likely more efficient ways to do it, but this method works perfectly well. However, due to the nature of .Net, we are not informed of when changes to the tray occur. What we have are interactive yet not dynamic screenshots of the information represented by the tray. To receive updates, we would have to use some form of code injection to hook messages received and sent by the tray to determine when the data is changing. This should be enough to get you started with working with the system tray. Happy hacking! Karl Working with the System Tray in .Net © Karl Wagner, 2008 Page 6 of 7 Appendix: Structure Definitions
Code:
Working with the System Tray in .Net
[StructLayout(LayoutKind.Sequential)]
public struct TRAYDATA { public IntPtr hwnd; public uint uID; public uint uCallbackMessage; private uint Reserved; private uint Reserved2; public IntPtr hIcon; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TBBUTTON { public int iBitmap; public int idCommand; public byte fsState; public byte fsStyle; public byte bReserved0; public byte bReserved1; public int dwData; public int iString; } public class TrayIconData { public TrayIconData() { button = new TBBUTTON(); traydata = new TRAYDATA(); Text = " "; } public TBBUTTON button; public TRAYDATA traydata; public string Text; } © Karl Wagner, 2008 Page 7 of 7 |
Zitat |
Registriert seit: 7. Jun 2008 708 Beiträge Delphi 10.2 Tokyo Professional |
#2
Why do you try to translate something from a language you don't understand rather than trying to understand the principle behind it, unless the used language?
|
Zitat |
Razor
(Gast)
n/a Beiträge |
#3
I understand it and i got what i wanted now but still dont get the whole picture
Delphi-Quellcode:
trayicondata.Wnd:=hwndtoolbar; //<<< toolbarwindow32 handle
trayicondata.uID:=4; // <<< i got this solved this is id of icon in tray trayicondata.cbSize:=sizeof(TrayIconData); TrayIconData.uFlags:=NIF_MESSAGE + NIF_ICON + NIF_TIP; //is this even nessesary? TrayIconData.hIcon:= //how to extract this? |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |