Using C# in your Windows Vista Sidebar gadgets
Topics: Programming | February 14, 2007 @ 5:29 PM
Vista’s sidebar is magnificent. While it isn’t the way I wanted it to be (design choices, I guess) it still serves to be quite handy – I use the headlines gadget to keep up with RSS/Atom feeds from TG Daily, Google News, and THG and I also keep the weather gadget up. But what I really wanted for it was a POP3 gadget that checks in every 15 minutes and tell me how many new emails I have (totalled over my six email addresses).
Now doing this in C# would have been splendidly simple. I found a C# POP3 class on The Code Project (yay for not having do do any real work myself) which provided me with everything I needed. The problem you run into, though, is that Sidebar gadgets are all HTML. All the gadgets that come with Vista (and many of those you can download) are entirely HTML and JavaScript. This is great for deployment and also makes developing gadgets more familiar to many people, but the fact of the matter is JavaScript is a scripting language, not a programming one. Languages like C# are powerful and robust, and I honestly would have much preferred gadgets that were created as regular executables or perhaps DLL files. You lose a tad of versatility but you gain oh-so-much power.
A point before I continue: for something that runs with a timer like an intervalled POP3 checker, you need to be careful with how you set up the timer. As far as I know, there are two general approaches to using C# in Sidebar gadgets – the first, the way I used, was to compile the C# code into a DLL and register it for COM interop (I’ll outline this below, it’s not difficult at all). The second, the way I really didn’t want to touch, was using a C# web control in the HTML. Each of these gives you a method to set up the timer; the former has the JavaScript do the work whereas the latter gets the C# to do it. The problem with setting up the JavaScript timer – at least for me – was that it just stopped working after a while. I used SetInterval('doWork()', 900000) (as opposed to using SetTimeout('doWork()', 900000) where doWork() would call setTimeout again – this way of doing it is retarded, it’d be an infinite recursion and you’d blow up the fucking stack… you’d be surprised at the number of people who would suggest this solution and don’t even know about SetInterval) and it worked fine for a few hours but after that it just refused to do what it was supposed to. I tested to make sure it wasn’t the C#, and it was indeed the JavaScript. I had to settle for the more ghetto solution of just having it refresh the page every 15 minutes instead (if someone knows how to fix this, please let me know!). This timer issue was also what kept me from setting up a DLL that would retrieve the university’s current temperature info, so that I could hack the weather gadget to display information that would be more accurate for my situation than the generic Edmonton temperature that it gives.
I couldn’t be bothered to worry about creating a settings page for the gadget, so I just made it for myself (i.e. you can’t change its settings without changing the code of the DLL). Instead of describing what exactly you need to do to make this work (it’s not much), I’ll just paste down the C# class itself below. The POP3 client that I downloaded has everything in namespace Pop3, so I did the same. Any method calls or class types that aren’t defined in the code below are just referring to the POP3 code, which if you want you can just grab from the link above.
namespace Pop3
{
[ComVisible(true)]
public class Wrapper
{
private Timer timer;
private int messages;
public int Messages
{
get
{
return messages;
}
}
public void Start()
{
timer = new Timer();
timer.Interval = 900000;
timer.Enabled = true;
timer.Tick += new EventHandler(Tick);
Check();
}
private void Tick(object sender, EventArgs eArgs)
{
Check();
}
private void Check()
{
Pop3MailClient[] clients = new Pop3MailClient[6];
clients[0] = new Pop3MailClient("pop.gmail.com", 995, true, "myusername", "myultrasecretpasswordthatyou'llneverguess");
clients[1] = new Pop3MailClient("shawmail.ed.shawcable.net", 110, false, "myusername", "myultrasecretpasswordthatyou'llneverguess");
clients[2] = new Pop3MailClient("mail.stoptheqtip.ca", 110, false, "myusername", "myultrasecretpasswordthatyou'llneverguess");
clients[3] = new Pop3MailClient("pop.srv.ualberta.ca", 995, true, "myusername", "myultrasecretpasswordthatyou'llneverguess");
clients[4] = new Pop3MailClient("amisk.cs.ualberta.ca", 995, true, "myusername", "myultrasecretpasswordthatyou'llneverguess");
clients[5] = new Pop3MailClient("pop.ece.ualberta.ca", 995, true, "myusername", "myultrasecretpasswordthatyou'llneverguess");
messages = 0;
foreach (Pop3MailClient client in clients)
{
int num = 0, size;
try
{
client.ReadTimeout = 10000;
client.Connect();
client.GetMailboxStats(out num, out size);
client.Disconnect();
}
catch (Exception)
{
// if something goes wrong, ignore it.
// it'll probably be fixed by next check anyway.
}
messages += num;
}
}
}
}
As you can see, all you really need to do is add the using System.Runtime.InteropServices directive and then add the [ComVisible(true)] attribute to the class that you want to expose for COM use. On top of that, you’ll need to go to the project’s Properties page and make sure that “Register for COM Interop” is checked under the “Build” section. Note that whenever you build your project/solution it will overwrite the DLL and re-register it for COM; so you won’t be able to rebuild if the DLL is currently being used by the gadget. Even taking the gadget off the sidebar won’t remove the reference (at least right away) so you’ll need to exit the sidebar before rebuilding.
Once you’ve built the C# DLL and set it up properly for COM interop, the rest is simple. Just scour the net for how to make gadgets and you’ll get the HTML information that you need (how to set it up, etc.). To get access to the object (in my case, the Pop3.Wrapper object) just use something like:
var wrapper = new ActiveXObject("Pop3.Wrapper"); //new ActiveXObject("namespace.classname")
in your JavaScript to get access to the class; for example, after doing the above, I can just call wrapper.Start(), wait a few seconds, and then wrapper.Messages will represent the number of new emails I have. Enjoy the awesome C#ness!
Edit: I recently came across Nikhil Kothari’s Script# that compiles C# into JavaScript, and more recently even has integrated Gadget support. This is absolutely great for the simpler stuff, but for things that require more .NET stuff like the POP3 checker above (or anything that uses generics, or some other stuff that isn’t supported yet), as far as I know you still have to compile into a COM-visible DLL. Unfortunate, because mine keeps hanging up. I honestly don’t know why Microsoft didn’t go with C# or some other .NET language for Gadgets. HTML/JavaScript is so bloody crippling it isn’t even funny.
9,386 views | Trackback




March 18th, 2009 @ 6:23 AM
Hi,
I tried Using C# Code in Vista gadget as you mentioned in your blog, below is the Wrapper class which i created for User32.dll
using System;
using System.Runtime.InteropServices;
namespace CheckDesktop
{
[ComVisible(true)]
public class CheckWindow
{
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow", SetLastError = true)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll", EntryPoint = "GetForegroundWindow", SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
}
}
And i created the ActiveX object for using this in gadget Javascript as follows:
var wrapper;
wrapper = new ActiveXObject(“CheckDesktop.CheckWindow”);
Also I have registered the CheckDesktop DLL, but my code goes in exception when the ActiveXObject is created and i am not able to resolve it as i am not getting any Error Description, i am getting just an error code.
Please help,
Thanks,
Shreyas
March 18th, 2009 @ 11:43 PM
That sounds a bit out of my area of expertise, and it’s been a long time since I’ve done anything remotely COM-related. What do you get when you google the error code?