Pi-hole in the Tasktray & The Windows Store

Hey everybody, first time posting here, hope its a good read. 
But the other day I was wanting to help contribute to ecosystem of Pi-hole monitoring tools, and to be able to get an app onto the Microsoft Store. Now as you may have already assumed this was very largely fueled by  a Web 2.0 childlike wonder in the capabilities of API's. But regardless with some excitement I got to work. Now I have never before built a Windows Desktop Application and had a lot to figure out, mainly the API's that are needed and the entirety of the C# language. 

Which for both of those big thanks to the Team at Microsoft for the expansive documentation they have for this information and to the team at Code Project. Their help was very valuable during this project. To Preface the examples shown for this project are meant to be a more High-Level overview on how the project was created, rather than a step by step guide to it.

The first challenge to building this app was having it exist only within the System Task Tray, since WinForms applications like to start in an actual window.

Now luckily what I was able to do this within the template Program.cs file by calling a class that would then create a NotifyIcon right away.

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace PiholeTaskbarManager
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            using (ProcessIcon pi = new ProcessIcon())
            {
                pi.Display();
                Application.Run();                
            } 
        }
    }
}

Then from here I have the class ProcessIcon.cs file that then initializes a new NotifyIcon Object, and adds some extra information like what happens if you left click on it, and hover over it. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Diagnostics;
using System.Windows.Forms;
using PiholeTaskbarManager.Properties;
namespace PiholeTaskbarManager
{
    class ProcessIcon : IDisposable
    {
        public static NotifyIcon ni;

        public static ConfigBox config_box = new ConfigBox();
        
        // Initializes a new instance of the <see cref="ProcessIcon"/> class.
        public ProcessIcon()
        {
            config_box.ConfigBox_Settings();
            //Instantiate the NotifyIcon object.
            ni = new NotifyIcon();
            
    }
        //dispalys the icon in the system tray.
        public void Display()
        {
            //puts the icon in the system tray and allow it to react to mouse clicks
            ni.MouseClick += new MouseEventHandler(ni_MouseClick);
            ni.Icon = Resources.ICOPiHole;
            ni.Text = "Manage Pi-hole from the Taskbar!";
            ni.Visible = true;

            //Attach a context menu.
            ni.ContextMenuStrip = new ContextMenus().Create();
        }
        //releases resources
        public void Dispose()
        {
            ni.Dispose();
        }
        //handles the MouseClick event of the ni control.
        private async void ni_MouseClick(object sender, MouseEventArgs e)
        {
            //handle mouse button clicks.
            if (e.Button == MouseButtons.Left)
            {
                //start pihole admin page
                Process.Start("https://pi-hole.net");
            }

        }
    }
}

Now with the first major hurtle solved I had to find a way to work with the API data from the Pi-hole itself.
The first step in this process for me was finding a proper way to format the information. Which amazingly enough there was a built in way to do this inside Visual Studio.
All that had to be done was grab the raw json data that the Api would be getting from Pi-hole, which in this case can be easily grabbed from http://localhost/admin/api.php in your web browser. (Where localhost == Your Pi-hole IP Address.)
Then within Visual Studio:
  • Click "Edit" At the top Menu Bar
  • Hover over "Paste Special"
  • Click "Paste JSON As Classes"
  • And this will create a class based off the Json data in your clipboard.




And lastly we have to have a way to contact the Pi-hole itself. For this I ended up using the System.Net.Http.HttpClient class. I then added "application/json" as the Accept field in the header request.

1
2
3
4
5
6
7
8
9
public static HttpClient APIClient { get; set; }

public static void InitializeAPI()
{
   APIClient = new HttpClient();
   APIClient.DefaultRequestHeaders.Accept.Clear();
   APIClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

Now obviously there was a bit more to make this project complete, like the saving of settings, a timer in order to repeatedly ask the API for new data, and controls for updating the Context Menu in the Task Tray with the new API data. But to get better insight into exactly what was needed to make the full application you can view the full source on GitHub.

But for the next chapter in this story is where the Microsoft Store factors in.
 Now recall earlier when I said that I started this project unfamiliar with the territory, I made a discovery that the project flat out couldn't work the way I was hoping.

Really I wrote the whole program within WinForms, which due to it being an older system is not allowed onto the Microsoft Store. Meaning I had to recreate the app using UWP to allow it onto the store. While there are tools like Desktop Bridge to help convert my existing app, this project has all been about learning, so I will just take the hit and take my time to create the app from scratch in a UWP environment. 

Although once I started re-writing the whole app with UWP I made a final discovery.
UWP doesn't natively support putting anything in the SysTray.  At this point I though the project was done. Either it couldn't go onto the Microsoft Store, or it couldn't live in the SysTray. That was until I found some information from Stefan Wick, who is a Principal Program Manager at Microsoft, that has created a series of guides about creating a Desktop Extension to allow the application in the SysTray. While this will created a more difficult on boarding process to get my app onto the store will allow it to function as I hoped. Now that I have a solution for this final hurdle I'll get to work, and update you guys once I'm done. 

tldr;

 Having the WinForms program unable to be listed on the Microsoft Store, it'll be listed here.
Visit the project on GitHub here
Download the Project here! (Link available soon)

Popular Posts