public void GetLocationPrepare()
        {
            // Get a screenshot of the notification area...
            Rectangle notifyAreaRect = NotifyAreaUtility.GetRectangle();
            Size      notifyAreaSize = notifyAreaRect.Size;

            using (Bitmap notifyAreaBitmap = GetNotifyAreaScreenshot()) {
                // Something gone wrong? Give up.
                if (notifyAreaBitmap == null)
                {
                    return;
                }

                // Determine a good spot...
                if (notifyAreaSize.Width > notifyAreaSize.Height)
                {
                    nearColor = notifyAreaBitmap.GetPixel(notifyAreaSize.Width - 3, notifyAreaSize.Height / 2);
                }
                else
                {
                    nearColor = notifyAreaBitmap.GetPixel(notifyAreaSize.Width / 2, notifyAreaSize.Height - 3);
                }

                // And now we have our base colour!
                nearColorSet = true;
            }
        }
        private static Bitmap GetNotifyAreaScreenshot()
        {
            Rectangle notifyAreaRect   = NotifyAreaUtility.GetRectangle();
            Bitmap    notifyAreaBitmap = new Bitmap(notifyAreaRect.Width, notifyAreaRect.Height);

            using (Graphics notifyAreaGraphics = Graphics.FromImage(notifyAreaBitmap)) {
                try {
                    notifyAreaGraphics.CopyFromScreen(notifyAreaRect.X, notifyAreaRect.Y, 0, 0, notifyAreaRect.Size);
                }
                catch (System.ComponentModel.Win32Exception) {
                    return(null);
                }
            }
            return(notifyAreaBitmap);
        }
        public Point?GetLocation2(int accuracy)
        {
            // Got something fullscreen running? Of course we can't find our icon!
            if (SysInfo.ForegroundWindowIsFullScreen)
            {
                return(null);
            }

            // The accuracy can't be below 0!
            if (accuracy < 0)
            {
                throw new ArgumentOutOfRangeException("accuracy", "The accuracy value provided can't be negative!");
            }

            // The notification area
            var notifyAreaRect = NotifyAreaUtility.GetRectangle();

            if (notifyAreaRect.IsEmpty)
            {
                return(null);
            }

            // Back up the NotifyIcon's icon so we can reset it later on
            var notifyIconIcon = _notifyIcon.Icon;

            // Have we got a colour we could base the find pixel off?
            if (!nearColorSet)
            {
                GetLocationPrepare();
            }

            // Blah
            var   colMatchIndexes = new List <int>();
            Point last            = new Point(-1, -1);
            int   hits            = 0;
            int   hitsMax         = accuracy + 1;

            // Our wonderful loop
            for (int attempt = 0; attempt < 5 && hits < hitsMax; attempt++)
            {
                // Set the notify icon thingy to a random colour
                Random random   = new Random();
                int    rgbRange = 32;
                Color  col;
                if (nearColorSet)
                {
                    col = Color.FromArgb(
                        SafeColourVal(nearColor.R + random.Next(rgbRange) - 8),
                        SafeColourVal(nearColor.G + random.Next(rgbRange) - 8),
                        SafeColourVal(nearColor.B + random.Next(rgbRange) - 8));
                }
                else
                {
                    col = Color.FromArgb(
                        SafeColourVal(255 - random.Next(rgbRange)),
                        SafeColourVal(255 - random.Next(rgbRange)),
                        SafeColourVal(255 - random.Next(rgbRange)));
                }

                // Set the find colour...
                SetFindColour(col);

                // Take a screenshot...
                Color[] taskbarPixels;
                using (Bitmap notifyAreaBitmap = GetNotifyAreaScreenshot()) {
                    // If something goes wrong, let's just assume we don't know where we should be
                    if (notifyAreaBitmap == null)
                    {
                        return(null);
                    }

                    // We can reset the NotifyIcon now, and then...
                    _notifyIcon.Icon = notifyIconIcon;

                    // Grab the pixels of the taskbar using my very own Pfz-derived bitmap to pixel array awesomeness
                    taskbarPixels = BitmapToPixelArray(notifyAreaBitmap);
                }

                // Get every occurence of our lovely colour next to something the same...
                bool colMatched    = false;
                int  colMatchIndex = -1;
                int  colAttempt    = 0; // this determines whether we -1 any of the RGB
                while (true)
                {
                    Color col2 = Color.FromArgb(0, 0, 0);
                    //int colModAmount = colAttempt < 8 ? -1 : 1;
                    int colMod1 = (colAttempt % 8) < 4 ? 0 : -1;
                    int colMod2 = (colAttempt % 8) < 4 ? -1 : 0;

                    switch (colAttempt % 4)
                    {
                    case 0:
                        col2 = Color.FromArgb(SafeColourVal(col.R + colMod1), SafeColourVal(col.G + colMod1), SafeColourVal(col.B + colMod1));
                        break;

                    case 1:
                        col2 = Color.FromArgb(SafeColourVal(col.R + colMod1), SafeColourVal(col.G + colMod1), SafeColourVal(col.B + colMod2));
                        break;

                    case 2:
                        col2 = Color.FromArgb(SafeColourVal(col.R + colMod1), SafeColourVal(col.G + colMod2), SafeColourVal(col.B + colMod1));
                        break;

                    case 3:
                        col2 = Color.FromArgb(SafeColourVal(col.R + colMod1), SafeColourVal(col.G + colMod2), SafeColourVal(col.B + colMod2));
                        break;
                    }

                    colAttempt++;

                    colMatchIndex = Array.FindIndex <Color>(taskbarPixels, colMatchIndex + 1, (Color c) => { return(c == col2); });

                    if (colMatchIndex == -1)
                    {
                        if (colAttempt < 8)
                        {
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (taskbarPixels[colMatchIndex + 1] == col2)
                        {
                            colMatched = true;
                            break;
                        }
                    }
                }

                if (colMatched)
                {
                    hits++;
                    last.X = colMatchIndex % notifyAreaRect.Width;
                    last.Y = colMatchIndex / notifyAreaRect.Width; // Integer rounding is always downwards
                }
                else
                {
                    hits   = 0;
                    last.X = -1;
                    last.Y = -1;
                }
            }

            // Don't forget, our current values are relative to the notification area and are at the bottom right of the icon!
            Point location = new Point(last.X, last.Y);

            if (location != new Point(-1, -1))
            {
                return(new Point(notifyAreaRect.X + (last.X - 16), notifyAreaRect.Y + (last.Y - 14)));
            }
            else
            {
                return(null);
            }
        }
        private static Rectangle?GetNotifyIconRectangleLegacy(NotifyIcon notifyIcon, bool returnIfHidden)
        {
            Rectangle?nirect = null;

            NativeMethods.NOTIFYICONIDENTIFIER niidentifier;
            if (!CanGetNotifyIconIdentifier(notifyIcon, out niidentifier))
            {
                return(null);
            }

            // find the handle of the task bar
            IntPtr taskbarparenthandle = NativeMethods.FindWindow("Shell_TrayWnd", null);

            if (taskbarparenthandle == IntPtr.Zero)
            {
                return(null);
            }

            // find the handle of the notification area
            IntPtr naparenthandle = NativeMethods.FindWindowEx(taskbarparenthandle, IntPtr.Zero, "TrayNotifyWnd", null);

            if (naparenthandle == IntPtr.Zero)
            {
                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) || 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, (IntPtr)((int)niinfopointer + (int)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 == niidentifier.hWnd && niidnew == niidentifier.uID)
                        {
                            // 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)
                            {
                                if (returnIfHidden)
                                {
                                    nirect = NotifyAreaUtility.GetButtonRectangle();
                                }
                                else
                                {
                                    return(null);
                                }
                            }
                            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);
        }