.comment-link {margin-left:.6em;}

I Hate Linux

Wednesday, January 23, 2008

New Home Server Add-in: Tab Manager

In yet another attempt to make the Home Server Console a little more manageable with regards to multiple tabs, Tab Manager allows a user to bypass the normal Home Server Add-in loading mechanism and display whatever tabs they want inside of another tab.

Say what?

Rather than having a cluttered tab tool bar full of lots and lots of add-ins:

Home Server Console - Lots of tabs

A user can offload the tabs they use less often to be only displayed:

Home Server Console - With Tab Manager

And after you've selected the tab you want, you can collapse the list:

Home Server Console - With Tab Manager - Hidden

All the while still making all of the settings pages in the Settings dialog (relatively) normally available:

Tab Manager Settings

How it works

Existing readers of this blog will likely know that the Home Server Console looks for add-in tabs in assemblies with the following naming style: HomeServerConsoleTab.TabName.dll

By simply renaming those assemblies (ie HomeServerConsoleTab.SomeAddin.dll to HomeServerConsoleTab.TabManager.SomeAddin.dll), the add-in will no longer be loaded automatically by the Home Server Console and through the use of some code borrowed from Test Loader, are loaded instead by Tab Manager.

Aside from providing a new organizational home for the tabs, Tab Manager provides much of the same functionality as the Home Server Console with regards to tab ordering and ITabExtender (with the exception of ITabStatus support).

On the Settings side of things, Tab Manager's Settings tab uses ITabExtender to create a chain of custom settings tabs (using the Next property) to provide the Settings form access to the actual settings pages in a way that it expects/can handle.

In a later version I may offer a way to remove Settings tabs from view in a manner similar to... however I need to come up with reasonable way of doing this visually.

Warning

As is the case with (now) the majority of my add-ins, this add-in utilizes undocumented and unsupported mechanisms of Windows Home Server that could be misunderstood by me or change at any time possibly leading to a users Home Server no longer functioning correctly.

This add-in is by no means done and still is in need of some polish and is not advised at this time for wide spread use.

Please use caution with this add-in and use at your own risk.

If you are feeling daring and want to give it a try and offer feedback... please do.

If not, don't fret, the next version(s) will be even better thanks to those daring folks that tested out and gave feedback on earlier versions.

Usage

After you have installed the add-in...

  1. Launch the Windows Home Server Console
  2. Launch the Settings dialog
  3. Select the Tab Manager tab
  4. Select an assembly from the Standard Assemblies list and press the button with the Right arrow to move it to the Managed Assemblies list
  5. Repeat this process until all assemblies you want to be under the control of Tab Manager have been moved
  6. Press the OK button
  7. Click the Yes button to close the Windows Home Server Console
  8. Relaunch the Windows Home Server Console
  9. Select the Tab Manager tab
  10. Select desired tab from list.

Assemblies listed on the Standard Assemblies list are those that are automatically loaded by the Home Server Console, while those under the Managed Assemblies list are loaded by Tab Manager instead. Moving assemblies between the lists is as simple as double clicking on the item, or single clicking and using the appropriate button to move it.

Uninstalling this add-in does not automatically rename the modified files back to their original names. This is something I am looking into for the next version, in the mean time if/when you do decide to uninstall this add-in, you will need to add the desired files back to the Standard Assemblies list.

Note: No file name changes are made until the settings are applied through the use of the OK or Apply buttons.

Known issues

  • Tab Reorderer is unaware of tabs loaded through Tab Manager and can result in not all tabs being displayed on it's list or even phantom tabs without icons.
  • If loaded through Tab Manager, Tab Scroller still functions however it does not remove it's own icon.

Both of these issues will be resolved in a later version that will include the functionality of Tab Reorderer and Tab Scroller being added natively to Tab Manager (and reduce my add-in count from 5 to 3).

  • Any add-in that exposes status information (ie the main Microsoft tabs) will still work, however no status bar information will be displayed.
  • Some third-party add-ins that expect a given assembly name may not be able to load/save their settings.
  • Non-English systems may have issues loading the correct language for localized add-ins.

Downloads

Labels: ,

Saturday, January 19, 2008

Updated: WHS Test Loader

Due to the recent news that WHS add-in's must start with a capital letter (HomeServerConsoleTab.TabName.dll (correct) vs HomeServerConsoleTab.tabName.dll (incorrect))... I've updated WHS Test Loader (instructions) to also check for this condition.

Downloads:

Friday, January 18, 2008

Star Trek XI Teaser

Apparently someone snuck a camera into a recent showing of Cloverfield and got this:

Oh what chills ran down my spine when the theme began to play.

Wednesday, January 16, 2008

Coming Soon: Tab Management

Last month I mentioned a proof of concept add-in I was working on to change the way a user looks at some of the tabs in the Home Server Console.

I'm pleased to say that this add-in still proceeds (granted fairly slowly over the last month) and with any luck will be available in an early form before too long.

It works quite well today... only it needs a little more polishing, eye candy (not to mention a fair bit more testing) before I'll make it available.

The current build gives a better look when expanding and hiding the secondary tab list.

Expanded:

Tab Management - Main View

Hidden:

Tab Management - Hidden

Part of the delay was figuring out a good way to not display tabs in the main console view... but still make them available in the Settings panel:

Tab Management - Settings

A bit of work remains with regards to preserving existing tab order (on both sides) as well as other general sorting.

Labels: ,

Tuesday, January 15, 2008

Amazing New Add-in: Disk Management

After first seeing the announcement of Sam Wood's new Disk Management add-in I cursed at being beaten out of the door with a tool to help a user figure out which drive is which in their Home Server Console as my attempt kept getting pushed back due to other priorities.

Then I used it... and was thrilled, and floored.

Not only does it provide a fairly nice user interface, it also includes some undocumented functionality for adding and removing disks making it (in some parts) a replacement for the Storage Management tab.

Great job Sam!

Links:

One other fairly impressive thing about this is that Sam isn't just a WHS add-in author... but also a blogger on the subject of 4GW (4th Generation Warfare).

(Take a look at this this quick post from my buddy Dan (aka tdaxp) for a quick primer on the generations of warfare)

Part of what makes the subject so interesting (as well as the talk of 5GW) is that many of it's implications also have parallels in software development with regards to overall agility of strategy and resources.

Labels: ,

Suddenly I care about VS2008 SP1

... and Visual Studio 2008 hasn't even hit retail shelves yet.

From the sounds of it... the bug in VS 2005 and 2008 (at least) that prevents proper automatic specification of the new project's assembly name based on the settings of the project template will be included in Service Pack 1 for Visual Studio 2008.

Huzaah!

While this kind of bug thankfully doesn't affect many (hence why it seems to have gone largely unnoticed until recently), it does get in the way of users of my my Windows Home Server Add-in Project Templates or any other template that requires specific naming of the output assembly... leading to the developer having to manually rename the assembly (as specified in the Project properties) whenever they create a new project.

Monday, January 14, 2008

WHS Dev Tip #15: Terminal Services

Did you know the Home Server Console uses the Remote Desktop Protocol/Terminal Services to bring the application to clients? Did you know that you can launch additional applications in the session?

Terminal Services

Before getting into what we can do... lets make sure we all understand what we are using...

Windows Terminal Services is a server component dating back to NT4 which allows remote machines to connect to a server and be presented with a (nearly) fully functional desktop where a user can do their work almost as fast and easily as if it was local without having to having access to anything more than a client app (available as either a desktop app or ActiveX control) and a network connection.

We saw this same technology brought to Windows XP for it's Remote Desktop feature and now in Windows Home Server for both normal Console use as well as more complicated administration.

Using Remote Desktop

Ordinarily when we want to connect to our Home Server to do administrative tasks that cannot be achieved in the Home Server Console, we'll do the following:

  1. Launch the Remote Desktop client
    • XP/2003: Start -> Run -> mstsc
    • Vista/2008: Start -> mstsc
  2. Specify server name/address
  3. Click the Connect button
  4. Provide credentials and click the OK button.

This is the simple way to connect and with default options. The client and protocol have many more options than we normally use.

Regular Connect

Startup Program

Rather than connecting to a new (or existing) user session on the server complete with desktop and start menu, we can instead request that a specific application (on the server) be launched on the server, to do so we need only:

  1. Click the Options button on the main Remote Desktop Connection Window
  2. Select the Program tab
  3. Check "Start the following program on connection"
  4. Specify a program or file

Once done, we can do something a simple as launch the Windows Calculator right away when we connect...

Calculator

Calculator in RDP

Or even just the Windows Home Server Console:

Start program

Console in regular Remote Desktop

The only thing missing (aside from the parent client window being sized better) is the removal of the window frame... which can be achieved by throwing in the -b argument:

Resized

That's right... the WHSConsoleClient application on WHS client PC's is largely just a fancy Terminal Services client that executes "homeserverconsole.exe -b" on the server on connect as well as provides the plumbing to make IConsoleServices.OpenHelp() and IConsoleServices.OpenUrl() calls be passed back to and launched on the client.

With this in mind we have a number of possibilities.

Warning

Before going any further I want to make clear that what I will be describing below is completely unsupported by me and by Microsoft and can result in loss of key files.

This information is provided for informational purposes only and for those who wish to do some hacking of their own server. Nothing in this post should be used as part of any add-in or other software on Home Server's that are not owned by reader of this post and author of said add-in or software.

Replacement

The simple method is simply to rename (and backup) HomeServerConsole.exe on the server and put in it's place an application of our choice or design that can handle being used in the strange window size used by the Home Server Console.

It's interesting to note that HomeServerConsole.exe like a good number of the Home Server files are not protected by Windows File Protection, nor is there any other security mechanism in place to prevent a malicious user from replacing HomeServerConsole.exe with their own application.

So what should we replace it with?

One method

I find myself often using the Remote Access web site to connect to my main desktop PC and sometimes need to do something on my Home Server... which requires launching one Remote Desktop connection inside of another one.

While this works... it's certainly not ideal. Instead what if we were to launch Windows Explorer in the same Terminal Services session that we have the Home Server Console in?

As easy as this would be with an add-in... a problem we have is is that the Console is displayed there without a Window frame or title bar...

So one option would be something like this:

class Program
{
   static void Main(string[] args)
   {
      string initalProgram = TerminalServices.GetInitialProgram(Process.GetCurrentProcess().SessionId);
 
      //In Home Server Connector?
      if (initalProgram.ToLower().StartsWith("homeserverconsole"))
      {
         //then launch explorer
         LaunchExplorer();
      }
 
      //Launch the Home Server Console anyway.
      LaunchHomeServerConsole();
   }
 
   static void LaunchHomeServerConsole()
   {
      Process.Start(@"C:\Program Files\Windows Home Server\HomeServerConsole1.exe");
   }
 
   static void LaunchExplorer()
   {
      Process.Start(@"explorer.exe");
   }
}

In the above code, I use some methods from the Terminal Services API to determine if the session our app is running in was asked to launch the Home Server Console, if so we'll launch the real thing (named HomeServerConsole1.exe in this example) as well as a copy of Explorer... otherwise we'll just launch the Home Server Console.

The actual check for to determine the startup application involves a call to WTSQuerySessionInformation() with the WTS_CONFIG_CLASS.WTSUserConfigInitialProgram enumerated value.

As simple and as workable as this is... it does have a major flaw... the Home Server Console expects to be named HomeServerConsole.exe for any number of operations including access to it's .config file. Instead of launching a new processes.. an alternative is to load the assembly containing the real thing and launch it within our own application (gotta love .NET reflection):

static void LaunchHomeServerConsole()
{
   Assembly whsConsole = Assembly.LoadFile(@"C:\Program Files\Windows Home Server\HomeServerConsole1.exe");
   whsConsole.EntryPoint.Invoke(null, new object[] { new string[0] });
}

Note the above code is remarkably slow on my WHS when it comes to launching the Home Server Console... resulting in a load time of several minutes, something I have not spent much time debugging as yet.

Home Server Console with Explorer

Improvements

With a little additional work, we could enumerate the currently running processes (with WTSEnumerateProcesses() ) and determine if an instance of explorer is already running, and if not launch one.

The Future

Likely this method will only work so long as there is no protection of the WHS files, although should that not change this option will be even more powerful should the next version of Windows Home Server be based on Windows Server 2008 and use TS RemoteApp for displaying of the Home Server Console.

Sample

No sample this week as this post is intended to be more theoretical and informational rather than practical.

Hopefully this has given you some ideas of how you could use this on your own.

Conclusion

With a little use of the Terminal Services API and a bit of file renaming it is possible to execute ones own custom code prior to the Home Server Console being launched, giving numerous options for additional customization of the Windows session that the Console is loaded in... be it launching Windows Explorer, other applications or applying custom external settings to the Home Server Console.

Next Time

Hacking the Home Server Console (in place) using reflection.

As always though, I'd love to hear your ideas of what you'd like to see in future.

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels:

Thursday, January 10, 2008

WHS Dev Tip #14, ITabExtender, Part 4: Tab Status

Plenty of times we've seen the little status notifications at the bottom of the Home Server Console telling us who is logged in through the remote access web site or the status of the storage balancing:

StatusBarStrip - Logged in and balanced

How would you like to put your own information there? With ITabExtender it is possible.

A word of warning

Before digging into how this can be done it needs to be made very clear that unlike all of the other features of ITabExtender that I've discussed so far this week, having a third-party add-in expose status information using ITabExtender is dangerous as the Home Server Console only has a few places to display such information, places that are normally used by the Microsoft tabs... potentially leading to a third-party add-in visually overwriting important information.

Ideally if a third-party does implement ITabExtender and does make use of the status functionality they don't distribute the add-in and instead just use it for in house functionality and testing... and should later they decide to share it, they disable the status functionality.

Status

An ITabExtender exposes the read only Status property which returns an object that implements the ITabStatus interface which defines the following:

  • OnClick()
  • StatusEvents()
  • StatusImage
  • StatusNext
  • StatusOrdinal
  • StatusText

Right off the bat we can create a custom class that implements this interface:

public class TabStatus : ITabStatus
{
   public void OnClick()
   {
 
   }
 
   public void StatusEvents(System.Diagnostics.EventLog whsEvents)
   {
 
   }
 
   public Bitmap StatusImage
   {
      get
      {
         return Properties.Resources.DefaultToolBarIcon16;
      }
   }
 
   public ITabStatus StatusNext
   {
      get { return null; }
   }
 
   public int StatusOrdinal
   {
      get { return 0; }
   }
 
   public string StatusText
   {
      get { return "Some Status: " + DateTime.Now.ToString(); }
   }
}

An alternative to implementing a stand alone class is to have our implementer of ITabExtender also implement ITabStatus to allow for easier setting and monitoring of status values.

For simplicity this post and the later example add-in build them as two separate classes.

StatusImage & StatusText

Similar to IConsoleTab, ITabStatus expose a pair of properties that define the image and text that should be associated with.

A quick note is that while TabImage is expected to return a Bitmap that is 32x32 pixels in size, StatusImage is expected to return a bitmap that is 16x16 pixels in size.

StatusOrdinal

The status bar along the bottom of the Home Server Console is an instance of the custom StatusBarStrip control which contains 3 separate StatusBarButton instances; the first for Remote login notification, the second for storage balancing status and the third for backup/restore progress.

The StatusOrdinal property of an ITabStatus implementer specifies which StatusBarButton that the status will be displayed on (0-2).

StatusEvents()

Rather than setting up some messaging system using named pipes, remoting or other a simple option is used with ITabStatus... the event log.

StatusEvents is called once, not long after a the Status property is first read, passing in a reference to the HomeServer event log... enabling the receiver to parse the log looking for specific events as well as use the EntryWritten event to be informed with a new log entry is written.

OnClick()

OnClick() is an interesting case... and one that I do not believe was implemented in any of the Microsoft tabs, despite it's existence (or at least support of it) causing a visual bug, it still sorta works and will still be discussed here.

OnClick() is treated like an event handler that is raised when a user clicks the StatusBarButton that is being used by an ITabExtender... only simply clicking the mouse on it isn't enough, instead you have to press the space bar to cause the click to actually occur.

StatusNext

Likely intended to be similar in functionality to ITabExtender.Next for ITabStatus instances... this work appears to be only half complete as nothing I have done has been able to use this to display multiple ITabStatus instances without employing multiple tabs.

Updating

Like many of the other undocumented features of the Home Server Console, changing the visual look of the ITabStatus implementer isn't as simple as just updating the applicable property, instead we need to request that the StatusBarStrip update the status for us.

In order to accomplish this the static CommonState class (Microsoft.HomeServer.Controls, HomeServerControls.dll) exposes a property named MainStatusBar which references the StatusBarStrip at the bottom of the main form... giving us access to a SetStatus() method that requests that this be done.

So from our Home Server Console tab (ideally) we need to call SetStatus and pass in a reference to the tab whose status we want to update:

CommonState.MainStatusBar.SetStatus(this);

After that the Console takes care of the update for us.

Remember though that any update will overwrite any existing updates to the same StatusOrdinal, potentially throwing out important information... just as the information placed there by us can be overwritten by a call to SetStatus() from another add-in.

Another potential issue that can be encountered with updating is removing the status information once it's no longer relevant (ie a user is no longer logged into the system via the web page). One possible option is to remove the existing ITabStatus instance and have ITabExtender.Status return null/Nothing and then call CommonState.MainStatusBar.SetStatus(this). This method will not cause a visual change, instead a more workable option  is to change the StatusText and StatusImage properties of the ITabExtender to return and empty string and null/Nothing respectively for the update to actually occur.

Settings

Because the Settings form does not have a StatusBarStrip on it, the ISettingsExtender.Status property is largely worthless for tabs on the Settings side of things.

Sample

At long last... a pair of demo applications that demonstrate the functionality that's been discussed this week.

In each project are six tabs for the main console window that implement the ITabExtender interface that also display the time the last time Refresh() and Prepare() methods are called on it.

Similar functionality exists (sans Refresh() and Prepare() functionality in the settings window with three tabs that implement the ISettingsExtender interface.

On the first tab there are three buttons that allow enable the tab to output a status message, refresh that message and disable that message (which requires one last refresh).

All the while all tabs specify a unique TabOrdinal to ensure that they are displayed in order one after another.

ITabExtender Demo - First Tab

Downloads:

Conclusion

ITabExtender through ITabStatus provides a relatively easy to use mechanism for a tab to display additional information to the user. Unfortunately because ITabExtender and ITabStatus were never intended for end user use, conflicts can easily exist between existing status messages either overwriting or being overwritten by status messages from third-party add-ins.

Next Time

Replacing the Home Server Console with our own application to give us just a little more control over our system when working remotely.

As always though, I'd love to hear your ideas of what you'd like to see in future.

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels:

Wednesday, January 09, 2008

WHS Dev Tip #14: ITabExtender, Part 3: Multiple-Tabs

Under the current tab model we are familiar with... the Home Server Console looks for a class named HomeServerTabExtender in a namespace based on the name of the assembly (ie HomeServerConsoleTab.MyTab.dll holds Microsoft.HomeServer.HomeServerConsoleTab.MyTab) for information on the display of a given Console add-in.

As simple as this system is, it is extremely limiting as it means that an assembly can only contain a single tab, which leads to multiple assemblies being required for a more complicated add-in that might require multiple tabs (such as in Settings), ITabExtender changes that.

Next

ITabExtender defines a read-only property named Next which returns another ITabExtender, enabling a programmer to create a linked-list of add-in tabs with remarkable ease.

Lets look back at the code sample from Monday of the extra properties and methods we get with ITabExtender over IConsoleTab:

public ITabExtender Next
{
   get { return null; }
}
 
public void Prepare()
{
   
}
 
public void Refresh()
{
   
}
 
public ITabStatus Status
{
   get { return null; }
}
 
public int TabOrdinal
{
   get { return 33; }
}

Right now Next is just returning null... in order to return something useful we first need to create another class that implements the ITabExtender interface, create an instance of it and return it. Unlike with the main class, this time though we can choose an arbitrary name and put it in any namespace we want:

public class ExtraConsoleTabClass : ITabExtender
{
   private IConsoleServices consoleServices;
   private MainTabUserControl tabControl;
 
   public ExtraConsoleTabClass(int width, int height, IConsoleServices consoleServices)
   {
      this.consoleServices = consoleServices;
 
      tabControl = new MainTabUserControl(width, height, consoleServices);
 
      //Additional setup code here
 
 
 
   }      
 
   #region ITabExtender Members
 
   public ITabExtender Next
   {
      get { return null; }
   }
 
   public void Prepare()
   {
      
   }
 
   public void Refresh()
   {
      
   }
 
   public ITabStatus Status
   {
      get { return null; }
   }
 
   public int TabOrdinal
   {
      get { return 34; }
   }
 
   #endregion
 
   #region IConsoleTab Members
 
   public bool GetHelp()
   {
      return false;
   }
 
   public Guid SettingsGuid
   {
      get { return Guid.NewGuid(); }
   }
 
   public Control TabControl
   {
      get { return tabControl; }
   }
 
   public Bitmap TabImage
   {
      get { return Properties.Resources.DefaultToolBarIcon; }
   }
 
   public string TabText
   {
      get { return "Extra Tab"; }
   }
 
   #endregion
}

Note: You are free to create your lower classes/tabs anyway you like, I prefer sticking to the same conventions and constructors as in the parent tab for simplicity.

At this point all we need to do is wire up the new ITabExtender with the one that will be automatically found by the Home Server Console... and in order to do this all we need to do is create an instance of the new class, store it some where and spit it back out when the Next property is read:

ExtraConsoleTabClass extraTab;
 
...
 
public HomeServerTabExtender(int width, int height, IConsoleServices consoleServices)
{
   this.consoleServices = consoleServices;
 
   tabControl = new MainTabUserControl(width, height, consoleServices);
 
   //Additional setup code here
 
   extraTab = new ExtraConsoleTabClass(width, height, consoleServices);
 
}
 
...
 
public ITabExtender Next
{
   get { return extraTab; }
}

And when it's all said and done (and loaded in the Home Server Console) we are greeted with our two tabs:

ITabExtender - Two Tabs

Because this method works just like a (read only) linked-list, we can do it almost indefinitely (provided we remember that the Home Server Console only supports a finite number of tabs):

ITabExtender - Six Tabs

A word of warning though... do not have an ITabExtender refer to itself... or have any kind of circular dependency in your tab set as it will run indefinitely and cause the Home Server Console to take quite a while to load as it waits for your add-in to fail.

Settings

Like so many of the other features of ITabExtender, the same functionality works with ISettingsExtender when used in the settings dialog:

ISettingsExtender x3

Sample

A sample add-in demonstrating everything discussed here will be part of the last post on Thursday.

Conclusion

ITabExtender and it's Next property enables programmers to easily define multiple tabs in a single assembly, offering the opportunity to visually break one large and complicated add-in into smaller and more manageable sub components that can each be represented by their own tab, keeping in mind the whole while that the Windows Home Server Console only supports a finite number of tabs.

Next Time

Tomorrow: Tab status

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels: