Gadgets: Registering managed objects

Andrew posted about the PowerShell Gadget he recently built. Its a pretty cool piece of kit really exercising all of the possibilities in hosting .NET within the Sidebar infrastructure. In fact its currently my most actively used Gadget!

There are some good examples in there are how to wire up to .NET eventing, managed interop and use of platform invoke. AP spent quite a bit of time refactoring this and learning a lot of about the Gadget host in the process – I think he is now the guru of managed gadgets :)

One of the things that initially presented itself through the use of a managed component that needs to be registered through COM is that you need some way of installing that component on to the system in the first place. Normally you would build a MSI to do this, however we found an example of how this can be circumvented and you can have the Gadget “self register” a COM object itself allowing you to retain the .gadget drag and drop packaging and install experience.

In order to do this, we have an initial check to validate the existence of the COM object on the system and if it doesn’t exist we execute a script to add the required registry keys which register the ProgId and CLSID on the system.

In the PowerShell gadget, this is done on the Gadget.html file as a script directive:

<script>  
  InitializeInterop();
</script>

That in turn simply wraps the creation of the required COM object in a try/catch block to validate its existence.

try
{
  var proxy = new ActiveXObject("Mindscape.ConsoleHost");
  proxy = null;
  return true;
}
catch (e)
{
  return false;
}

If it doesn’t exist the registration steps required are:

codeBase = System.Gadget.path + "\\Bin\\Mindscape.Gadgets.PowerShell.dll"; 
 
shell = new ActiveXObject("WScript.Shell");
 
shell.RegWrite(root + "Mindscape.ConsoleHolder\\",
                    "Mindscape.Gadgets.PowerShell.ConsoleHolder");
shell.RegWrite(root + "Mindscape.ConsoleHolder\\CLSID\\",
                    "{91267DB9-9914-4524-A757-9024B99D02E9}");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\",
                    "Mindscape.Gadgets.PowerShell.ConsoleHolder");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\",
                    "mscoree.dll");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\ThreadingModel",
                   "Both");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\Class",
                    "Mindscape.Gadgets.PowerShell.ConsoleHolder");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\Assembly",
                    "Mindscape.Gadgets.PowerShell, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5bd33ec22e477ed5");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\RuntimeVersion",
                    "v2.0.50727");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\CodeBase",
                    "file:///" + codeBase);
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\1.0.0.0\\Class",
                    "Mindscape.Gadgets.PowerShell.ConsoleHolder");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\1.0.0.0\\Assembly",
                    "Mindscape.Gadgets.PowerShell, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5bd33ec22e477ed5");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\1.0.0.0\\RuntimeVersion",
                    "v2.0.50727");
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\InprocServer32\\1.0.0.0\\CodeBase",
                    "file:///" + codeBase);
shell.RegWrite(root + "CLSID\\{91267DB9-9914-4524-A757-9024B99D02E9}\\ProgId\\",
                    "Mindscape.ConsoleHolder");
shell.RegWrite(root + "Component Categories\\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}\\0    ",
                    ".NET Category");

We are using the WScript.Shell object to RegWrite the associated entries. Most importantly with the managed component we are setting the CodeBase entry to specifically identify the location of the managed DLL on the system (because we don’t have it registered in the GAC and the Sidebar process is not going to locate it in a known search path)

You would run through these steps for each managed object you want to register. You need to know the CLSID and ProgId of your Gadget.

You will notice that we use use a root specifier to direct where exactly we want to load this in the registry. The code calling our Registration function makes up to 2 calls to try and register the Gadget because of UAC.

try
{
  Register("HKCR\\");
}
catch (e)
{
  try
  {
    Register("HKCU\\Software\\Classes\\");
  }
  catch (e)
  {
  }
}

Initially we try and register it globally in HKEY_CLASSES_ROOT, but if you are running as a standard user or with UAC enabled you wont be able to do this. So if we hit an exception on this call we try again but this time using the HKEY_CURRENT_USER area to register it for the current user only.

Using this approach you can now register your managed objects as part of your Gadgets install. You could also use the reverse approach to unregister when your Gadget closes down but keep in mind that the Sidebar will lock managed components so the Gadget uninstall will still not work correctly while the assembly is locked.

Happy Gadget coding! :)

Tagged as Lab Samples

PowerShell Gadget

I’ve recently been having a play around with building some Gadgets for Windows Vista. Since all of us at Mindscape have been playing around with PowerShell I decided it would be cool to integrate PowerShell into the Windows Sidebar in Gadget form. This means you don’t have to fire up your command shell all the time – just type your command into the sidebar to execute it. If you need data displayed the fly-out mode displays the output for the command (e.g. try running ipconfig /all).

This is my first version release of the gadget, I hope that some of you get good mileage out of it. We will soon be releasing the complete source code and some documentation about how we achieved this integration up on the site shortly for those developers who want to learn more about building very rich gadgets.

The gadget leverages the following technologies:

  • Windows PowerShell
  • Windows Vista SideBar
  • Hosting .NET within a Gadget

We are committed to releasing some of the cool things that we build in our spare time in the hope that some people will find them interesting and cool. We always welcome feedback as well. Download the PowerShell Gadget.

UPDATE: This gadget requires PowerShell installed to the default location. :-)
UPDATE: Having more than one instance of the gadget open is broken. I am investigating.

Enjoy,

Andrew Peters

Tagged as Lab Samples

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top