public static Rect? GetNotifyIconRectLegacy(NotifyIcon notifyicon)
{
Rect? nirect = null;
FieldInfo idFieldInfo = notifyicon.GetType().GetField("id", BindingFlags.NonPublic | BindingFlags.Instance);
int niid = (int)idFieldInfo.GetValue(notifyicon);
FieldInfo windowFieldInfo = notifyicon.GetType().GetField("window", BindingFlags.NonPublic | BindingFlags.Instance);
System.Windows.Forms.NativeWindow nativeWindow = (System.Windows.Forms.NativeWindow)windowFieldInfo.GetValue(notifyicon);
IntPtr nihandle = nativeWindow.Handle;
if (nihandle == null || nihandle == IntPtr.Zero)
return null;
// find the handle of the task bar
IntPtr taskbarparenthandle = NativeMethods.FindWindow("Shell_TrayWnd", null);
if (taskbarparenthandle == (IntPtr)null)
return null;
// find the handle of the notification area
IntPtr naparenthandle = NativeMethods.FindWindowEx(taskbarparenthandle, IntPtr.Zero, "TrayNotifyWnd", null);
if (naparenthandle == (IntPtr)null)
return null;
// make a list of toolbars in the notification area (one of them should contain the icon)
List<IntPtr> natoolbarwindows = NativeMethods.GetChildToolbarWindows(naparenthandle);
bool found = false;
for (int i = 0; !found && i < natoolbarwindows.Count; i++)
{
IntPtr natoolbarhandle = natoolbarwindows[i];
// retrieve the number of toolbar buttons (i.e. notify icons)
int buttoncount = NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32();
// get notification area's process id
uint naprocessid;
NativeMethods.GetWindowThreadProcessId(natoolbarhandle, out naprocessid);
// get handle to notification area's process
IntPtr naprocesshandle = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.All, false, naprocessid);
if (naprocesshandle == IntPtr.Zero)
return null;
// allocate enough memory within the notification area's process to store the button info we want
IntPtr toolbarmemoryptr = NativeMethods.VirtualAllocEx(naprocesshandle, (IntPtr)null, (uint)Marshal.SizeOf(typeof(NativeMethods.TBBUTTON)), NativeMethods.AllocationType.Commit, NativeMethods.MemoryProtection.ReadWrite);
if (toolbarmemoryptr == IntPtr.Zero)
return null;
try
{
// loop through the toolbar's buttons until we find our notify icon
for (int j = 0; !found && j < buttoncount; j++)
{
int bytesread = -1;
// ask the notification area to give us information about the current button
NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_GETBUTTON, new IntPtr(j), toolbarmemoryptr);
// retrieve that information from the notification area's process
NativeMethods.TBBUTTON buttoninfo = new NativeMethods.TBBUTTON();
NativeMethods.ReadProcessMemory(naprocesshandle, toolbarmemoryptr, out buttoninfo, Marshal.SizeOf(buttoninfo), out bytesread);
if (bytesread != Marshal.SizeOf(buttoninfo))
return null;
if (buttoninfo.dwData == IntPtr.Zero)
return null;
// the dwData field contains a pointer to information about the notify icon:
// the handle of the notify icon (an 4/8 bytes) and the id of the notify icon (4 bytes)
IntPtr niinfopointer = buttoninfo.dwData;
// read the notify icon handle
IntPtr nihandlenew;
NativeMethods.ReadProcessMemory(naprocesshandle, niinfopointer, out nihandlenew, Marshal.SizeOf(typeof(IntPtr)), out bytesread);
if (bytesread != Marshal.SizeOf(typeof(IntPtr)))
return null;
// read the notify icon id
uint niidnew;
NativeMethods.ReadProcessMemory(naprocesshandle, niinfopointer + Marshal.SizeOf(typeof(IntPtr)), out niidnew, Marshal.SizeOf(typeof(uint)), out bytesread);
if (bytesread != Marshal.SizeOf(typeof(uint)))
return null;
// if we've found a match
if (nihandlenew == nihandle && niidnew == niid)
{
// check if the button is hidden: if it is, return the rectangle of the 'show hidden icons' button
if ((byte)(buttoninfo.fsState & NativeMethods.TBSTATE_HIDDEN) != 0)
{
nirect = GetNotifyAreaButtonRectangle();
}
else
{
NativeMethods.RECT result = new NativeMethods.RECT();
// get the relative rectangle of the toolbar button (notify icon)
NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_GETITEMRECT, new IntPtr(j), toolbarmemoryptr);
NativeMethods.ReadProcessMemory(naprocesshandle, toolbarmemoryptr, out result, Marshal.SizeOf(result), out bytesread);
if (bytesread != Marshal.SizeOf(result))
return null;
// find where the rectangle lies in relation to the screen
NativeMethods.MapWindowPoints(natoolbarhandle, (IntPtr)null, ref result, 2);
nirect = result;
}
found = true;
}
}
}
finally
{
// free memory within process
NativeMethods.VirtualFreeEx(naprocesshandle, toolbarmemoryptr, 0, NativeMethods.FreeType.Release);
// close handle to process
NativeMethods.CloseHandle(naprocesshandle);
}
}
return nirect;
}