Brad Wardell's site for talking about the customization of Windows.
The basics in creating a useful widget
Published on March 6, 2005 By Frogboy In DesktopX Tutorials

Creating widgets with DesktopX 3 is, relatively speaking, a snap. Today I'm going to walk you through how to create a widget. It's actually going to be a pretty complicated one (for me anyway) but it will hopefully show you the ropes on how to create fully featured widget.

The widget I want to create is one I've been looking for for a long while - A disk space meter that lets the user configure which drive they are monitoring.

Step 1: Load up the DesktopX development environment.

This is the last option on the DesktopX Standard "Welcome" screen.

Once you had loaded it, you will be created with this dialog:

At this point, depending on your skill-level you're going to either want to import an existing widget (which is what I'm going to do because I need to have a sample in front of me) or you'll jump right in to making the widget.

Step 2: Import existing widget or create one from scratch.

Since my widget is going to be getting the amount of disk space available from a particular drive, I will want to look at a similar widget that gets the amount of free memory available. There is a sample included with DesktopX 3 that does this. So I'm going to click on the "Import a widget" button. 

If I had wanted to create from scratch, I would have clicked on the "Desktop" tab in the builder dialog and chosen "New" object and started from scratch.

The widget in question is called the WM-Memory_meter widget. All it does is display the amount of free memory. It's very simple.  But the reason I need it is that I don't personally know how to get system information like this via VB Script or JavaScript.

So now I'm going to right-click on it and choose Edit Script.

Step 3: Write your script.

'Let's allocate the object globally, so we don't waste time allocating it on each call
Dim objWMIService

Sub Object_OnScriptEnter
  object.settimer 123, 5000
  Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
  Object_OnTimer123
End Sub
 

'Let's clean it, as a good practice
Sub Object_OnScriptExit
 Set objWMIService = nothing
End Sub

Sub Object_OnTimer123
 Dim colItems
 Set colItems = objWMIService.ExecQuery("Select AvailableMBytes from Win32_PerfFormattedData_PerfOS_Memory",,48)
 For Each objItem In colItems
   Object.text = "Available memory: " & objItem.AvailableMBytes & " MB"
   'we just really need one result here, so we exit
   Exit Sub
 Next
End Sub

So there's the whole thing. When it starts, it created a timer called "123" that gets called every 5,000ms (5 seconds). He's accessing the WMI stuff (which I'm not that familiar with).  And on the Timer, he's grabbing specific stuff from the WMI object.

So okay, how do I use this to get % of disk space available.  My answer: Google. I am going to look for "Win32_PerfFormattedData_PerfOS_Memory" in Google and see what other goodies are available. And I found this page. And boy are there a lot of different things you can display. But I find the one I want: "Win32_PerfFormattedData_PerfDisk_LogicalDisk".

But there's a bit more I need. The memory thingy in the example doesn't have to grab from a particular drive. I need a way to get the disk space free on a particular drive. That leads me back to Google where I start trying in searches to with my newly found term with drive letters and such. I find this page. It doesn't have what I have but you may find it useful for other things. I eventually make it to this page here. And then I find this gold mine! Holy cow, there are so many things I could make with this one page. Okay, one thing at a time..

I make this change in code:

Sub Object_OnTimer123
 Dim colItems
 Set colItems = objWMIService.ExecQuery("Select * from Win32_PerfFormattedData_PerfDisk_LogicalDisk where Name = 'C:'",,48)
 For Each objItem In colItems
   Object.text = "Available space: " & objItem.FreeMegabytes & " MB"
   Exit Sub
 Next
End Sub

But there's a whole bunch of things I could have instead of .FreeMegabytes.  That page has tons of things (including free space). If I want to display the percentage of free space available, I'd use PercentFreeSpace instead of FreeMegabytes.

It took a bit to figure out that I simply had to plugin 'C:' as the name of the drive in the query. But once I figured that out I was ready for the next step.

Step 4: The Preferences Dialog

What sets this widget apart from others is that you can set which drive you're monitoring the disk space for. To do that, I will need to build a preferences dialog.  So I look in the "DX Scripting Guide" that comes with DesktopX and chapter 8 is "Widget Preferences".

There is only one simple rule with creating preferences -- they have to be the very first thing you do in your script or else they won't be created.  All I want to do is create a simple combo box where the user selects the drive letter.

Therefore: I need to add these lines right after the Object_OnScriptEnter:

Sub Object_OnScriptEnter
  Widget.AddPreference "Combolist1"
  Widget.Preference("Combolist1").Type = "ComboList"
  Widget.Preference("Combolist1").AddValue "C:"
  Widget.Preference("Combolist1").AddValue "D:"
  Widget.Preference("Combolist1").AddValue "E:"
  Widget.Preference("Combolist1").AddValue "F:"
  Widget.Preference("Combolist1").AddValue "G:"
  Widget.Preference("Combolist1").DefaultValue = "C:"
  Widget.Preference("Combolist1").Caption = "Available Drives"
  Widget.Preference("Combolist1").Description = "Disk Drives"

  object.settimer 123, 5000
  Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
End Sub

The current value of the combo box is known as  Widget.Preference("Combolist1").value. So I go back to that other function where I had hard coded 'C:' and change it to:

Set colItems = objWMIService.ExecQuery("Select * from Win32_PerfFormattedData_PerfDisk_LogicalDisk where Name = '" & Widget.Preference("Combolist1").Value &"'",,48)
 

The other thing we will want to add is to have it recheck when the user closes the preferences dialog (after changing the drive letter). This is from the docs.

Sub Widget_OnPreferencesChange
  Object_OnTimer123
End Sub

At this point on our screen we have:

Step 5: Export the object as a widget.

Now it's time to export it as a widget.  To do that, right click on it and choose "Export".

If you have DesktopX Pro, you can export this as a "gadget" which turns it into a stand-alone program you can send to anyone.

And here we go:

My widget is ready to go.

Here is the full source code:

'Let's allocate the object globally, so we don't waste time allocating it on each call
Dim objWMIService
Dim szDrive

Sub Object_OnScriptEnter
  Widget.AddPreference "Combolist1"
  Widget.Preference("Combolist1").Type = "ComboList"
  Widget.Preference("Combolist1").AddValue "C:"
  Widget.Preference("Combolist1").AddValue "D:"
  Widget.Preference("Combolist1").AddValue "E:"
  Widget.Preference("Combolist1").AddValue "F:"
  Widget.Preference("Combolist1").AddValue "G:"
  Widget.Preference("Combolist1").DefaultValue = "C:"
  Widget.Preference("Combolist1").Caption = "Available Drives"
  Widget.Preference("Combolist1").Description = "Disk Drives"
  'If I wasn't so lame I'd write something that would go through the list of drives available and make sure only available drives are here but I'm too lazy for that.

  object.settimer 123,5000
  Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")

End Sub


Sub Object_OnScriptExit
  Set objWMIService = nothing
End Sub

Sub Widget_OnPreferencesChange
  Object_OnTimer123
End Sub

Sub Object_OnTimer123
  Dim colItems
  Set colItems = objWMIService.ExecQuery("Select * from Win32_PerfFormattedData_PerfDisk_LogicalDisk where Name = '" & Widget.Preference("Combolist1").Value &"'",,48)
  For Each objItem In colItems
    Object.text = "Available memory: " & objItem.FreeMegabytes & " MB"
    'we just really need one result here, so we exit
    Exit Sub
  Next
End Sub

 

Some other notes

A few observations worth noting.  DesktopX isn't cross-platform. On a widget enabling program such as this, this should be considered a feature not a limitation.  Because DesktopX is designed exclusively for Microsoft Windows (or 98% of the market) it is able to support all kinds of things that a cross platform program would not.  For instance, this example relied on the WMI Service of Windows. There are tons of things of this nature that are specific to Windows that can be created that wouldn't be practical if it were cross-platform since different platforms have different features and limitations.

You can learn more about DesktopX 3 at http://www.desktopx.net.  It comes in 3 forms: DesktopX Client (a run-time to make use of objects, widgets, and desktops).  DesktopX Standard which is what would be the least you'd need for this example (and comes with Stardock's mega OS enhancement suite, Object Desktop), or DesktopX Pro which allows you to export these widgets as "gadgets" that can be sent to anyone whether they have DesktopX or not.


Comments
on Mar 06, 2005
Wow...thanks Brad for the preview.

Are you really calling available disk space 'memory'?
on Mar 06, 2005
Very interesting article.

However, there is a couple of things I want to point out.
For the preference box, it'd be very practical if the script obtainted a list of drives that can be measures and then populate the list. Otherwise you'd have to manually configure it your self. And that isn't very conveniant for users to will be using the client only version of DX. For instance, I have 2 hard drives split into a total of 8 partitions.
One easy way would be to make an loop that went from C to Z, but from a user point of view you only want to see the drives you actually can measure.
I know this article is meant to point out the basics of creating widgets, but I think it's quite importaint to show how to make widgets as userfriendly as possible. Perhaps for a seperate article.
on Mar 06, 2005
Very nice.

on Mar 06, 2005

thomassen - if you check out the code I had already put in there:

'If I wasn't so lame I'd write something that would go through the list of drives available and make sure only available drives are here but I'm too lazy for that.

I agree such a feature would be nice but that would be beyond the scope of the tutorial.

on Mar 06, 2005
...it'd be very practical if the script obtainted a list of drives that can be measures and then populate the list.


Tiggz Cabal Drives widget has a script that lists the available drives, I'd assume the same script could be used to insert values into the widget preference.
on Mar 06, 2005
Oh! Didn't see that comment. My bad.
on Mar 06, 2005
A real handy program to search through the WMI is "wbemtest.exe", located in your windows/system32/wbem/ directory. Another program to help scripting with WMI is Microsoft's "Script-O-Matic".

Hope this will help some people out.
on Apr 02, 2005
I was unable to find the widget referred to in the article in the list of widgets that came with my copy of DesktopX. Could you please advise where it is located?