Building WHS & CodeSnippet: Building WHS Add-ins
Awhile ago I heard the saying “Microsoft is a platform company” (rather than lots and lots of products), one great example of that is Windows Home Server. WHS’s is built upon Windows Server 2003, so you can create apps and extend it much like any other Windows OS, but you can also extend the “Home Server Console” very easily using Visual Studio/.NET.
Requirements
- Visual Studio 2008 (Download for free if you’re a student, or download a trial, or Visual Studio Express)
- Windows Home Server (Order a 120-day trial)
- Windows SDK (web install or ISO install – you only need “ORCA”)
Setting up your WHS Add-in
Create a .NET 2.0 Library Project (WHS does not ship with .NET 3.0/3.5, although they will work if installed), then you need to reference two libraries to build WHS add-ins which can be found on your WHS box. That’s right, there is no SDK download, the required libraries are found on your server.
From “C:\Program Files\Windows Home Server” copy HomeServerExt.dll and Microsoft.HomeServer.SDK.Interop.v1.dll from your server to your development machine, then reference both of them in your solution. This will give you the namespace Microsoft.HomeServer.SDK.Interop.v1. Alongside those, for the UI you’ll need to add references to System.Forms and System.Drawing.
WHS requires a particular assembly name structure, so right click on your project, change the Assembly name to “HomeServerConsoleTab.<yourprojectname>”, ie “HomeServerConsoleTab.WHSStats”
WHS Stats
WHS Stats uses Windows Management Interface (WMI) to return the names of several pieces of hardware on the server. This could be turned into a fully fledged hardware monitor, but I’m trying to keep it a very simply example that has more real world value than the veteran Hello World.
WHS Tab Add-ins (which appear in the main WHS Console screen versus Settings Add-in’s which appear after you click Settings from the Console) require two classes. In this case it’s WHSStats(.cs) which implements Microsoft.HomeServer.Extensibility.IConsoleTab and WHSStatsPanel(.cs), a UserControl, which contains the UI.
WHSStats.cs
using System; using System.Text; using Microsoft.HomeServer.Extensibility; using Microsoft.HomeServer.SDK.Interop.v1; using System.Drawing; using System.Collections.Generic; using System.Management; namespace WHSTempAddin { public class WHSTempAddin : Microsoft.HomeServer.Extensibility.IConsoleTab { private IConsoleServices services; private WHSTempAddinUI nPanel; private WHSInfoClass whsInfo; public WHSTempAddin(int width, int height, IConsoleServices consoleServices) { nPanel = new WHSTempAddinUI(); whsInfo = new WHSInfoClass(); this.services = consoleServices; nPanel.Load += new EventHandler(nPanel_Load); } public Bitmap TabImage { get { return Properties.Resources.WHSTempAddinImg; } } public bool GetHelp() { throw new NotImplementedException(); } public Guid SettingsGuid { get { return Guid.Empty; } } public System.Windows.Forms.Control TabControl { get { return nPanel; } } public string TabText { get { return "WHS Stats"; } } void nPanel_Load(object sender, EventArgs e) { nPanel.lstCPUDetails.DataSource = getCPUDetails(); nPanel.lstGPUDetails.DataSource = getGPUDetails(); nPanel.lstNetworkDetails.DataSource = getNetworkInterfaceDetails(); } private List<String> getCPUDetails() { List<String> data = new List<string>(); ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * from Win32_Processor"); foreach (ManagementObject adapterObject in searcher.Get()) { data.Add(adapterObject["Name"].ToString()); data.Add("CPU Load: " + adapterObject["LoadPercentage"] + "%"); } return data; } private List<String> getNetworkInterfaceDetails() { List<String> data = new List<string>(); ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_PerfRawData_Tcpip_NetworkInterface"); foreach (ManagementObject adapterObject in searcher.Get()) { UInt64 i = (UInt64)adapterObject["CurrentBandwidth"]; data.Add("Adapter name: " + adapterObject["Name"]); data.Add("Current bandwidth: " + (i / 1000000) + "MB/s"); data.Add("KBytes In/sec: " + ((UInt64)adapterObject["BytesReceivedPersec"] / 100000) + "KB/s"); data.Add("KBytes Out/sec: " + ((UInt64)adapterObject["BytesSentPersec"] / 1000000) + "KB/s"); } return data; } private List<String> getGPUDetails() { List<String> data = new List<string>(); ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * from Win32_VideoController"); foreach (ManagementObject adapterObject in searcher.Get()) data.Add(adapterObject["Name"].ToString()); return data; } } }
The constructor, TabText, SettingsGuid, TabImage and GetHelp the minimum methods to implement for a WHS Add-in. Key things to note, TabImage is a Resource added to the project, its recommended to be a 32×32 image (I used one slightly larger, that could explain why it is skewed off to one side); TabText is what appears on the Tab to select your add-in so don’t make it too long!
The rest of the code is hooking up the listboxes (below) to WMI queries about the hardware.
WHSStatsPanel.cs
Building and deploying the project
These particular instructions are mostly copied from MSDN
- Add New Project, select Setup and Deployment Projects, and then select Setup Project.
- In the File System editor (of the Setup Project), select the Application Folder node. Right-click the Application Folder, point to Add, then select Project Output.In the Add Project Output Group dialog, verify that Primary Output is highlighted. Click OK to add the project output and close the dialog box.
- In the File System editor, right-click Application Folder and then click Properties Window. In the properties window, in DefaultLocation, type [ProgramFilesFolder]\Windows Home Server.
- In the Solution Explorer, expand the Detected Dependencies. Right-click HomeServerExt.dll and Microsoft.HomeServer.SDK.Interop.v1.dll, then click Exclude.
- Now in Visual Studio 2008, you’ll need to set the .NET Framework under Launch Conditions to .NET 2.0.That is View –> Editor –> Launch Conditions. Regardless of whether you’ve selected .NET 2.0, 3.0, 3.5 or 3.5 SP1, this needs to be set. VS2008 defaults to .NET 3.5 in the launch conditions, which stops the installer from even running!
- This step is “sort of” optional. If you plan to Remote Desktop into your server and run the installer that way, you don’t need to do this…but if you plan to run the installer through the Windows Home Server console, you need to place the installer in \\Server\Software\Add-Ins. Even then, you need to insert the “WHSLogo” property (and set it to 1) in the MSI before WHS will pick it up.
To do this, you’ll need ORCA (it’s in the Windows SDK, see above for the links to that; Once you install the SDK, you’ll find the ORCA installer in C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\Orca.MSI).

- With ORCA open, click File, click Open, browse to the location of the MSI file that contains your Add-in, and then click Open.
- In the Tables column, click Property.
- Right-click anywhere in the column area where the Property and Value columns are listed, and then click Add Row.
- In the Add Row dialog, type WHSLogo for the Property, click Value, and then type 1. Click OK to enter the property and to close the dialog.
- Click File, click Save, and then click Exit to close ORCA.
Comments
2 Comments
Trackbacks / Pingbacks
-
[...] here: Building WHS & CodeSnippet: Building WHS Add-ins application, development, hardware, image, installer, management, project, projects, property, [...]




[...] Original Paul [...]