Free SMS Gadget for Vista using .NET Interop

This post is the second in a series of posts covering how to send free SMS messages using the Ung1881 web site. The first post discussed how to use screen scraping to wrap the Ung1881 web site into a .NET library we could use to send messages from the command line. In this post I'm going to discuss how to create a Vista Sidebar Gadget that allows us to use the .NET library to send free messages.

Now that we have a nice and clean SMS library at our disposal it's time to do something more fun (and useful) than sending messages from a Console application. The next step is to create a Vista Sidebar Gadget that uses the .NET library to send SMS messages. I'm not going to walk you through the basics of a Sidebar Gadget in this post. There is an excellent article for absolute beginners up on MSDN. The focus of this post is going to be .NET interop, and how to read phone numbers from your Vista address book.

Throughout the development cycle of Vista we've seen various versions of the sidebar. I still remember seeing some awesome WPF gadgets up on Channel9 when Vista still was known as Longhorn, and all we had was early CTP builds. However, as most of you know the final version of the Sidebar is limited to HTML, CSS and JavaScript. To many (including me) this was quite a disappointment…

To be honest, it's not fair to say that Vista Gadgets can't run .NET code. You can expose your .NET code as COM object, and it's fairly easy to create COM instances from script languages.

The real problem is to register your .NET code for COM interop. This involves modifying your code to become COM compatible and to create a MSI installation package to register and distribute your code. This is to much hassle for a simple gadget.

Thankfully Tyler (he doesn't include his full name) have found a really elegant solution to .NET Interop in Gadgets, and have posted an excellent article on this on "The Code Project". You should definitely check out the article. His solution to the problems involves creating a general purpose GadgetAdapter, which is a .NET assembly, that supports COM interop, that can load other .NET assemblies dynamically using reflection. The GadgetAdapter assembly is registered on the end users machine using shell scripting from JavaScript. So the first time you use the interop layer the GadgetAdapter gets registered on the clients machine. Once the GadgetAdapter is registered you can create an instance of it from your own gadget script and load up any .NET class you want from your own assembly.

So to backup for a second, your Gadget folder structure looks something like this:



In your Gadget Script file all you have to do to create a new instance of a .NET type is this:
// Instance of the GadgetBuilder to load/unload .NET assemblies. See GadgetInterop.js.
var builder = new GadgetBuilder();

// Initialize the adapter to call .NET assemblies.
builder.Initialize();

// Use the builder to add the username and password as constructor argument values.
builder.AddConstructorParam(username);
builder.AddConstructorParam(password);

// Load the Ung1881.dll assembly and create an instance of the Ung1881.Ung1881Client type.
ung1881Client = builder.LoadType(System.Gadget.path + "\\bin\\Ung1881.dll", "Ung1881.Ung1881Client");

//Get values from the UI.
var number = txtPhoneNumber.value;
var message = txtMessage.innerText;

//Sending the message
var status = ung1881Client.SendMessage(number, message);

The Ung1881Client is a new class I added to the library to make it even easier to use it from a Gadget. The class takes care of wrapping long messages into smaller chunks, and it returns a status code instead of throwing exceptions when something goes wrong.

During testing of the gadget I discovered one bug/issue with the GadgetInterop JavaScript library provider by Tyler. If you turn of UAC (the "cancel or allow" stuff in Vista), or right click and run Sidebar.exe as administrator, the gadget stops working. After doing some debugging I figured out that I was unable to load the GadgetAdapter. After digging some more I located the bug in the RegisterGadgetInterop function in the GadgetInterop.js file. The problem is that if you run with out UAC, or run sidebar.exe as an administrator, you can't write to HKCU (Current User). Instead you have to register the GadgetAdapter under HKLM (Local Machine). I have notified Tyler on the Code Project message board, but article isn't updated. I've included the updated version of the RegisterGadgetInterop function below:
////////////////////////////////////////////////////////////////////////////////
//
// Add the Gadget.Interop dll to the registry so it can be used by COM and
// created in javascript as an ActiveX object
//
////////////////////////////////////////////////////////////////////////////////
function RegisterGadgetInterop()
{
try
{
// Full path to the Gadget.Interop.dll assembly
var fullPath = System.Gadget.path + assemblyStore;
var asmPath = fullPath + assemblyName;

// Register the interop assembly under the Current User registry key
RegAsmInstall("HKCU", progID, "Gadget.Interop.GadgetAdapter", guid,
"Gadget.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9389e9f4d8844504",
"1.0.0.0", asmPath);

if(InteropRegistered() == false)
{
// Try Register the interop assembly under the Local Machine registry key
RegAsmInstall("HKLM", progID, "Gadget.Interop.GadgetAdapter", guid,
"Gadget.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9389e9f4d8844504",
"1.0.0.0", asmPath);
}
}
catch(e)
{
System.Debug.outputString("RegisterGadgetInterop fails: " + e.message);
}
}

Another interesting feature of the gadget is the Vista Contacts integration. Since this is an SMS gadget you obviously want to access your address book to look up mobile phone numbers of your friends and family. This is fairly straight forward, since contact support is included in the Vista Sidebar Object Model. The function reading the address book and adding contacts who have a mobile phone to a drop down list is included below:
///////////////////////////////////////////////////////////////
//
// Load contacts from the Vista address book.
//
///////////////////////////////////////////////////////////////
function loadContacts()
{
var contactMgr = System.ContactManager;
var contacts = contactMgr.Contacts;
var contact = null;
var element = null;

for(var i=0; i < contacts.count; i++)
{
contact = contacts.item(i);
if(contact.mobilePhone != "")
{
element = document.createElement("option");
element.text = contact.name;
element.value = contact.mobilePhone;
ddlContacts.add(element, ddlContacts.options.length);
}
}

element = document.createElement("option");
element.value = "";

if(ddlContacts.options.length > 0)
{
element.text = "";
ddlContacts.disabled = false;
}
else
{
element.text = "";
ddlContacts.disabled = true;
}
ddlContacts.add(element, 0);
ddlContacts.selectedIndex = 0;
}





I've gotten a few requests from friends who want their Outlook 2007 contacts to show up in the gadget. Since this isn't supported directly by the Vista Sidebar Object Model I'd have to do the Outlook 2007 interop my self. I assume this wouldn't be too hard, but I haven't had time to figure this out yet. Drop me a comment if you have any good resources on how to read the Outlook 2007 address book from script. However, if you're running Outlook 2007 I have something far cooler up my sleeves for the next part of this series on how to make the most fun out the SMS library!

The download link points to the Windows Live Gallery site, so if you download and like the gadget please rate it. Feel free to post any comments, suggestions, questions or feedback.

No comments:

Post a Comment