This is the third part in a series of tutorials aimed at guiding novice developers though building a "Hello World" Windows Home Server Add-In, using only freely-available tools (including Visual Studio Express).

For Part 3, we'll actually be writing some code and responding to Windows Home Server notifications.

For this tutorial, we're building a Windows Home Server Add-In that detects changes to Shared Folder permissions. You can access the other parts of the tutorial, or download the code I'm using in the screenshots, using the links below.

  • Part 1: Installing and configuring your development environment
  • Part 2: Designing a GUI and initial deployment test
  • Part 3: Responding to Windows Home Server Notifications (code)
  • Part 4: Using FancyListView and comparing permissions (code)
  • Part 5: Building an installer package using WiX (code)

 

Step 1: Adding References

Before we can interact with Windows Home Server components, we need to tell our Add-In code where it can find the WHS-specific libraries it needs.

Instead of using the designer, we will edit our Add-In code directly this time. Right-click MainTabUserControl.cs in Solution Explorer, and choose View Code. You'll see a bunch of using statements at the top of the code file, and a couple of methods under those.

Back in Solution Explorer, right-click the References folder and choose Add Reference.

074-Add-WHSInfo 075-Add-WHSInfo

Scroll down in the list, choose microsoft.homeserver.sdk.interop.v1 and click OK. Unpin Solution Explorer for now.

076-Add-WHSInfo 077-Add-WHSInfo

At the bottom of your list of using statements, add a reference to the library:

using Microsoft.HomeServer.SDK.Interop.v1;

078-Add-WHSInfo

Now our code knows about a whole bunch of WHS interoperability functions. In order to access those functions, we need to create an object that will talk to Windows Home Server for us.

Underneath the IConsoleServices object, add a WHSInfoClass. We add the object at this level so all of the code in our MainTabUserControl can access it. The first part of the statement tells the compiler what type of object this is (WHSInfoClass, in our case), and the second part is the name we're going to use to refer to this particular instance of the type (whsInfoClass for us).

WHSInfoClass whsInfoClass;

079-Add-WHSInfo

Once we've defined how we're going to access WHSInfoClass, we need to create an instance of it that we can interact with. In the constructor for our MainTabUserControl, add the following:

this.whsInfoClass = new WHSInfoClass();

080-Add-WHSInfo

We're now ready to start interacting with WHS in our code.

 

Step 2: Receiving Notifications

We haven't really talked about what our Add-In is going to do yet; it's a secret. First, we're going to tell our Add-In to listen to WHS for notifications.

Windows Home Server is very chatty; all we have to do is tell WHS that we're listening, and WHS will share all sorts of interesting information about the current state of the server, in real time. We're going to tap into the notification infrastructure and listen out for some specific events.

First, we need to change our MainTabUserControl to implement some specific code. Tack INotificationCallback on the end of the line, like so:

public partial class MainTabUserControl : UserControl, INotificationCallback

081-Add-WHSInfo

Right click INotificationCallBack and choose Implement Interface.

082-Add-WHSInfo

Visual Studio helpfully adds the code that makes up INotificationCallback for us. This code will be a contract between our Add-In and WHS; we agree to implement this code exactly as WHS expects so that WHS can send us notifications.

This is the code added automatically for us:

#region INotificationCallback Members
 
public void BackupStateChanged(WHSBackupState State)
{
    throw new NotImplementedException();
}
 
public void Disconnected()
{
    throw new NotImplementedException();
}
 
public void NotificationChanged(string UniqueID, WHS_Notification_Type Type, WHS_Notification_Severity Severity, int IsSuppressed, string textHeader, string textDescription, string helpFilename, string helpSection, string helpLinkText)
{
    throw new NotImplementedException();
}
 
public void PhysicalDiskChanged(IDiskInfo pDiskInfo)
{
    throw new NotImplementedException();
}
 
public void ReConnected()
{
    throw new NotImplementedException();
}
 
public void UserInfoChanged()
{
    throw new NotImplementedException();
}
 
#endregion
 

 

The first thing we want to do is comment out all the exceptions. A couple of forward slashes at the beginning of the line tells the compiler to ignore this code.

#region INotificationCallback Members
 
public void BackupStateChanged(WHSBackupState State)
{
    //throw new NotImplementedException();
}
 
public void Disconnected()
{
    //throw new NotImplementedException();
}
 
public void NotificationChanged(string UniqueID, WHS_Notification_Type Type, WHS_Notification_Severity Severity, int IsSuppressed, string textHeader, string textDescription, string helpFilename, string helpSection, string helpLinkText)
{
    //throw new NotImplementedException();
}
 
public void PhysicalDiskChanged(IDiskInfo pDiskInfo)
{
    //throw new NotImplementedException();
}
 
public void ReConnected()
{
    //throw new NotImplementedException();
}
 
public void UserInfoChanged()
{
    //throw new NotImplementedException();
}
 
#endregion
 

 

We need to tell WHS that when our Add-In loads it's ready to listen for notifications. Add this to the bottom of our MainTabUserControl constructor:

this.whsInfoClass.RegisterForNotifications(this);

083-Add-WHSInfo

 

Step 3: Responding to Notifications

Right now, our Add-In can receive notifications from WHS. That's great, but we haven't written any code to actually do anything about those notifications.

Each method in INotificationCallback gets called by WHS depending on which notification it's trying to send us. Right now, we want a generic catch-all; we want to see and act on all the normal notifications WHS adds to the notification queue.

Let's change our NotificationChanged method, and add some quick code to dump out each notification to our ListBox so we can see it.

Notice that WHS sends us a bunch of information about the notification that we can display or act on in other ways. We'll use the Type, Severity, textHeader, and textDescription parameters to add an entry to our ListBox.

public void NotificationChanged(string UniqueID, WHS_Notification_Type Type, WHS_Notification_Severity Severity, int IsSuppressed, string textHeader, string textDescription, string helpFilename, string helpSection, string helpLinkText)
{
    //throw new NotImplementedException();
    this.listBox1.Items.Add(Type + " " + Severity + ": " + textHeader + " " + textDescription);
}

084-Add-WHSInfo

We're also interested in this UserInfoChanged thing. We'll add another quick line to tell us when this gets called by WHS. Unfortunately, WHS doesn't send us any information for this method, so the only information we have is that WHS fired this notification at us.

public void UserInfoChanged()
{
    //throw new NotImplementedException();
    this.listBox1.Items.Add("User info changed!");
}

085-Add-WHSInfo

We're going to get a lot of information showing up in our ListBox. We'll make use of our button to clear the list when it gets too long.

Open MainTabUserControl.cs in the designer (open Solution Explorer and double-click it, remember?) and select our button. Expand the Properties pane.

By default, the Properties pane shows us properties of the selected object (funny that), like background colour, text, and size. But if you click the little lightning bolt icon in the Properties pane toolbar, you'll change to the events tab.

Click the lightning bolt to change to the events tab for our button, and then double-click the Click event. This will jump you back to viewing your code, with a new Click event handler created. This method gets called every time you click the button.

089-Add-button-event 090-Add-button-event

Add some code to the event handler to clear the ListBox.

private void consoleToolBarButton1_Click(object sender, EventArgs e)
{
    this.listBox1.Items.Clear();
}

091-Add-button-event

Let's build this sucker. Expand Solution Explorer again, right-click the project and choose Build.

086-Add-WHSInfo

Copy the compiled Add-In to Windows Home Server using Remote Desktop, as we did yesterday. Make sure the WHS Console is closed, or you won't be able to overwrite the file (you may have to open and then close the Console again to kill any other sessions that have it open remotely).

071-Build-assembly 072-Build-assembly

Now open up the WHS Console and have a look at your creation. There's lots of text here, so drag your SplitView over to the right to see our notifications. If anything changes (you add a new share, or a disk suddenly goes offline), the notification will show up here.

Let's explore that UserInfoChanged notification. Jump over to the User Accounts tab and create a new user. Have a look at the notifications sent to our Add-In.

UserInfoChanged gets called when we add or remove users, and when permissions are changed on folders, so when the new user creation process adds the new user to share permissions, we get notified (a lot).

087-Test-WHSInfo 088-Test-WHSInfo

Click the toolbar button to clear the ListBox. Got to the Shared Folders tab and change user permissions on a shared folder. Check back to see that we were notified.

092-Test-WHSInfo

That's cool, but what can we do with that notification? Hmm... what if we want to keep track of which users have permissions to specific shared folders, and throw an alert if something is changed?

 

Step 4: Extracting Information from Windows Home Server

Change back to Visual Studio. Open MainTabUserControl.cs in the designer.

Select the FancyListView, and then click the arrow in the top right corner. Choose Edit Columns, and then change each column's Text property.

The first column should be "Share",  the second should be "Username, and the third should be "Permission".

093-Add-share-permissions 094-Add-share-permissions

Change back to code view.

We're going to add a method that uses GetShareInfo2 from our WHSInfoClass instance. GetShareInfo2 is just one of the many methods that WHSInfoClass exposes; you can interrogate Windows Home Server for all sorts of juicy information using just WHSInfoClass.

GetShareInfo2 returns an array of objects that represent all the shares that WHS knows about, including the name, path, and current permissions of the share.

Our method will cycle through each share object and extract each permission assigned to that share. The permissions information will be displayed in our FancyListView.

Add a new method at the bottom of our code file:

private void DisplaySharePermissions()
{
    this.fancyListView1.Items.Clear();
 
    foreach (IShareInfo2 info in whsInfoClass.GetShareInfo2())
    {
        Array perms;
        info.GetPermissions(out perms);
        WHSUserPermission[] permissions = perms as WHSUserPermission[];
 
        for (int i = 0; i < permissions.Length; i++)
        {
            ListViewItem permissionItem = new ListViewItem(info.Name);
            permissionItem.SubItems.Add(permissions[i].userName);
            permissionItem.SubItems.Add(permissions[i].permission.ToString());
            fancyListView1.Items.Add(permissionItem);
        }
    }
}

099-Add-share-permissions

Fire our new method from UserInfoChanged, so that when WHS tells us that share permissions have changed we run our permissions enumeration code.

public void UserInfoChanged()
{
    //throw new NotImplementedException();
    this.listBox1.Items.Add("User info changed!");
    DisplaySharePermissions();
}

096-Add-share-permissions

Do the same thing to our MainTabUserControl constructor, so we pull down the current share permissions when our Add-In loads.

097-Add-share-permissions

Build the Add-In (right-click the project in Solution Explorer and choose Build). Copy the compiled Add-In to your server using Remote Desktop, and reopen the console.

098-Add-share-permissions

Success!

For fun, change some permissions on a shared folder and see that they get updated in our FancyListView.

Unfortunately, our FancyListView doesn't look very fancy at the moment. And the ListBox was just there for testing purposes; now that we know what WHS notifications look like the ListBox needs to be removed and replaced with a shiny graphic of some kind.

We'll make everything look pretty next time, along with adding some code to alert our administrator when a Shared Folder permission has been changed.

 

posted on Sunday, December 07, 2008 4:31 PM | Filed Under [ Windows Home Server Development ]

Comments

Gravatar
# re: "Hello World" Windows Home Server Add-In: Part 3 (Kennet @ 12/12/2008 9:33 AM)

Thanks for a really good and well made tutorial!
I also have a question: how do you debug when you developing an Add-in.
 
Gravatar
# re: "Hello World" Windows Home Server Add-In: Part 3 (Sam Wood @ 12/12/2008 10:58 AM)

Thanks Kennet.

Debugging takes a bit of work; I'm saving that for another tutorial.

For starters, you can look at the C:\Documents and Settings\All Users\Application Data\Microsoft\Windows HomeServer\Logs\HomeServerConsole.xxx.log file if your Add-In crashes - exception messages are logged there.

I also tend to make liberal use of MessageBox.Show and Support.TrError (which logs to the above log file).

Brendan has a post on debugging which I'll probably expand on.
 
Gravatar
# re: "Hello World" Windows Home Server Add-In: Part 3 (noor @ 5/13/2010 3:57 AM)

the software is best of my computer

Post Comment

Title *
Name *
Email
Url
Comment *  
Remember me
Please add 3 and 3 and type the answer here:

Search

Site Sections

Recent Posts

Archives

Post Categories

WHS Add-In Tutorial

WHS Blogs

WHS Development