in

CodePrairie .NET

South Dakota .NET User Group

I Hate Linux

  • Windows Home Server Power Pack 1

    As you already now know, the Windows Home Server team has announced Windows Home Server Power Pack 1.

    I like this... big time.

    Not only does it mean that the long awaited 64-bit connector software will soon be ours (soon being sometime during the vague 'first half of 2008'), but also that Windows Home Server is not a normal product that you buy and get bug patches for... but is also one that (in theory) Microsoft will be extending over time as well (granted, Power Pack 1 could end with a similar fate to Quake II Netpack 1: Extremities (ie being the only pack)).

    As useful as 64-bit support (for my Media Center box) and the other added features will be, I think the most important part of PP1 (for me) is going to be the ability (or at least a mechanism to attempt) to prepare a corrupted backup database as I've had plenty of issues with this (I still suspect them to be hardware related) and the only way to resolve the error is to completely wipe out all backups or the entire WHS.

  • Multiple OEM Home Server Tabs

    The Windows Home Server Console reserves the left most tab position to a tab supplied by the OEM who builds the actual Windows Home Server... such as what is seen in the HP MediaSmart server:

    mediasmart-server

    Did you know that you can specify your own?

    It's simply a matter of breaking out the HomeServerConsole.exe.config file on the server and specifying an appSettings key and value based on the name of the tab in question.

    For me to set my Web Folders add-in to show up as the OEM tab my config file could be as simple as this:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <appSettings>
            <add key="Web Folders" value="1" />
        </appSettings>
    </configuration>

    Once done the third party tab you've specified will show up in the OEM position:

    Web Folders as OEM Tab

    Did you know that you can specify more than 1 OEM tab?

    Just use the same trick in the config file... only do it again for other tabs:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <appSettings>
            <add key="Web Folders" value="1" />
            <add key="DHCP Server" value="1" />
        </appSettings>
    </configuration>

    DHCP and Web Folders as OEM Tabs

    Just remember that when two tabs have the same numerical value, their display names are used to sort them alphabetically.

  • WHS Developer Tip #13: MessageListBox

    Q: How can I create my own list like what I see in the Home Server Console's Network Health dialog?

    A: Another one of the custom ListBox (like) controls exposed by Windows Home Server is the MessageListBox control, the very control that is used to display network health messages as well as the installed and available add-ins:

    Home Network Health

    Like so many other controls, in order to use it we need only drag an instance from the toolbox to our form or control in the designer... but it is here where the simplicity ends.

    While called a ListBox... MessageListBox inherits from the Panel class and offers only a few extra enhancements over it... the most notable being the Items field which is the collection of MessageListBoxItem instances which correspond to the visual items we see.

    In order to add new items to the list, it can be as simple as:

    MessageListBoxItem redItem = new MessageListBoxItem(Color.Red);
    messageListBox1.Items.Add(redItem); 
     
    MessageListBoxItem yellowItem = new MessageListBoxItem(Color.Yellow);
    messageListBox1.Items.Add(yellowItem); 
     
    MessageListBoxItem greenItem = new MessageListBoxItem(Color.Green);
    messageListBox1.Items.Add(greenItem);

    Which gives us the following:

    Empty MessageListBoxItems

    Once we've created our items, we want to tweak them a bit through the use of the Title and Description properties which corresponds to the bold title text and body text respectively:

    redItem.Title = "Big ole problem";
    redItem.Description.Text = "Important information on the specifics of this error goes here.";
     
    yellowItem.Title = "Minor issue";
    yellowItem.Description.Text = "The world is going to end... just not today.";
     
    greenItem.Title = "All is well";
    greenItem.Description.Text = "Pay no attention to the man behind the curtain.";

    Which brings us to this point:

    MessageListBoxItems - With Text

    And for good measure, lets add some eye candy with some existing icons:

    redItem.Icon = CommonImages.StatusCritical24Icon;
    yellowItem.Icon = CommonImages.StatusAtRisk24Icon;
    greenItem.Icon = CommonImages.StatusHealthy24Icon;

    to bring us to:

    MessageListBoxItems - With Icons

    ActionButton

    Each MessageListBoxItem comes with a button ready for us... all we need to do is set it's text to make it visible:

    redItem.ActionButton.Text = "Fix Error";

    Of course to make it truly useful, we also have to manually wire up an event handler and the code to do something with the event:

    redItem.ActionButton.Click += new EventHandler(ActionButton_Click);
     
    ...
     
    void ActionButton_Click(object sender, EventArgs e)
    {
       //Determine which button was clicked
       Button b = sender as Button;
       //Determine which MessageListBoxItem the button exists on
       MessageListBoxItem mlbi = b.Parent as MessageListBoxItem;
     
       //Do useful processing
     
       //Remove specified MessageListBoxItem
       messageListBox1.Items.Remove(mlbi);
    }

    MessageListBoxItems - With Button

    CheckBox

    Instead of using a button for a single action, we can use the built in CheckBox functionality to allow toggling of a setting.

    Using the supplied CheckBox is similar to using the Button where we set the properties Text property and wire up and event handler... note that we are also required to set the CheckBox's Visible property to true:

    yellowItem.CheckBox.Text = "Ignore this";
    yellowItem.CheckBox.Visible = true;
    yellowItem.CheckBox.CheckedChanged += new EventHandler(CheckBox_CheckedChanged);

    Once wired up we can use the CheckBox very similar to how we used the ActionButton:

    void CheckBox_CheckedChanged(object sender, EventArgs e)
    {
       CheckBox cb = sender as CheckBox;
       MessageListBoxItem mlbi = cb.Parent as MessageListBoxItem;
     
       if (!mlbi.CheckBox.Checked)
       {
          //Do useful processing
          mlbi.GradientColor = (Color)mlbi.Tag;
       }
       else
       {
          //Do useful processing
          mlbi.GradientColor = Color.Gray;
       }
    }

    Which brings us to:

    MessageListBoxItems - With CheckBox

    Note the above example assumes that we are also storing the enabled color in the MessageListBoxItem's Tag property (as in the sample for this post).

    Be aware that while you can use both the ActionButton and CheckBox... doing so isn't very advisable due to the way both controls are rendered together:

    MessageListBoxItems - CheckBox and button

    Link

    In order to set the description of the MessageListItem we have to set Description.Text instead of just Text is because Description is a LinkLabel which gives is more control than just displaying text... it allows us to define a specific area to be a clickable hyperlink.

    To set that up, we need to modify or replace the LinkArea property of the Description property to specify where the link should begin and for how long it will as well as wire up an event handler:

    greenItem.Description.Text = "Pay no attention to the man behind the curtain.\nClick here for more information";
    //Link starts on 48th character and is 31 character long
    greenItem.Description.LinkArea = new LinkArea(48, 31);
    greenItem.Description.LinkClicked += new LinkLabelLinkClickedEventHandler(Description_LinkClicked);
     
    ...
     
    void Description_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    {
       //Do something based on link
    }

    To achieve:

    MessageListBoxItems - With Link

    Limitations

    Like so many other of the Windows Home Server Controls, MessageListBox is lacking in a few ways.

    Aside from it's limited designer support, it does also suffer from a bit of an issue... choppy redrawing which most often occurs whenever a MessageListBoxItem is added or removed from the visible list.

    Ideally after a MessageListBox is populated, its contents should not be altered while visible. While this is not a requirement, doing so will reduce the likelihood of the various sub controls used in each MessageListBoxItem from flashing about.

    Examples

    Putting it all together, again I've provided a pair of add-ins that show off the simplicity of MessageListBox and how we can use it visually:

    MessageListBoxItems - Example Add-ins

    Downloads:

    Conclusion

    MessageListBox provides a simple way to create a rich list of color coded messages for a user provided the drawing issues are understood and worked around.

    Next Time

    I'm not sure yet... What would you like to see? I'd love to hear your ideas.

    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.

  • I love my state!

    To many... South Dakota is a backwater, podunk, cold as hell, boring, uninhabited wasteland with fowl-tasting water and a former powerful senator.

    To me... it's not just home, but a place I thoroughly love.

    Sunday night after attending the wedding of my good friend Sonja in the wee town of Colton, SD (pop ~650) I embarked at ~11:30 for the 30 min drive home to Madison (pop ~6500)... only to realize that I'd taken a wrong turn on my way out of town and attempted to turn around using the driveway to some private property... only to end up in the ditch:

    In the ditch

    Needless to say I was ticked, especially after I got myself more stuck, but also because it was my first time after living here for 8 years and driving only vehicles incapable of getting themselves out on their own.

    Just 5 minutes after I got stuck and as I was thinking of walking the half mile back to town on that a driver on this low traffic road stops to ask if he can offer a hand... after some pushing I was still stuck.

    A minute later another driver (with a pickup (a staple of South Dakota living (and with any luck, my next vehicle purchase (some day)))) stops and offers me a pull.

    Only one problem... no one had a tow rope or chains with them... so both vehicles raced home to try to find something.

    While they were gone I spent a few minutes trying to shovel some of the 4-6 inch deep snow (mixed with tall grass) away from the vehicle so that we'd be able to look underneath easier as well as have slightly more traction on the way up... not to mention taking a quick picture.

    20 minutes later the pickup driver returns with a chain and after some quick rigging, he pulls me out and back on to the road and a Kurt Anderson became my hero for the time being.

    This is part of why I love this state so... When we see someone along the side of the road in need of assistance... instinctively we stop to see if we can render assistance. We aren't worried that the person who is pulled over (or the person pulling over) might be some homicidal maniac or other crazy... we know all to well (or know someone who knows) what it's like to be stranded along the road in the middle of seemingly nowhere.

    I know that I'll have to leave this fine state one day... but until then I get to enjoy every minute of it... even if that includes 50+ mph cross winds in the middle of a blizzard where people (like me) still feel comfortable driving down the interstate.

  • How many tabs is too many?

    Ever wonder how many console tabs the Windows Home Server Console can display?

    So did I... so I built a few extra projects and deployed them to my Home Server:

    Projects Dir

    The answer is... 100 and believe it or not... that's a bad thing!

    100 Tabs

    As much as I would like to see such wide spread WHS development that there were 100+ add-ins to choose from... it'll likely be a long while before we see anything like that ... it's also probably unlikely that when that day happens very many people (if any) will install that many add-ins... but for those that do an obvious problem will hit them hard... some tabs not being displayed.

    Look again at the above image of all of the tabs being scrolled through. Missing a few important things isn't it?

    When tabs are loaded, the assemblies they are contained within are loaded in alphabetical order and once the limit is reached, no new tabs are added to the Console and only warnings are added to the event HomeServerConsole log file:

    [1]071230.131656.5468: Init: Error: Too many tabs - extra is ignored
    [1]071230.131656.5625: Init: Error: Too many settings - extra is ignored
    [1]071230.131656.6562: Init: Error: Too many tabs - extra is ignored
    [1]071230.131656.7031: Init: Error: Too many settings - extra is ignored
    [1]071230.131656.7656: Init: Error: Too many tabs - extra is ignored
    [1]071230.131656.8906: Init: Error: Too many settings - extra is ignored
    [1]071230.131657.4218: Init: Error: Too many tabs - extra is ignored
    [1]071230.131657.6250: Init: Error: Too many settings - extra is ignored
    [1]071230.131657.7031: Init: Error: Too many settings - extra is ignored

    This is an interesting non-graceful failure as it is very possible that after a user adds too many tabs to their Home Server Console... they will not be able to easily remove an add-in or two to bring them back under the 100 tab limit using the Add-ins Settings page as they ordinarily would as it is very possible that it would be one of the first victims of this limit... after all it is located in the HomeServerConsoleTab.Storage.dll assembly which is pretty late in the alphabet

    For reference, here is how the same non-graceful failure appears in the Settings dialog:

    Settings - Start

    Settings - End

  • Aliens vs. Predator: Requiem - OMG WTF?

    This afternoon I was compelled to join a friend and his cousin in seeing this... horrible movie, and aside from making me wish that I had that 86 minutes and $5.25 back... I left encouraged to not go back and watch the first Alien vs Predator movie (which I've never seen) or any of the original Alien movies (one or two of which I've seen), let alone read any of the comic books or give any more thought to the experience than what will be involved in writing this post.

    This movie was bad, so very very bad. Not a Michael Jackson "you know I'm bad, I'm bad - you know it" bad, a Shredder "It feels so good to be so bad" bad, or even a "oh know my Windows Home Server burned down with the rest of my uninsured house and now I have nothing" bad ... but so horribly awful that... aside from wishing I was having dental work at the time, forgiveness for my friend and his suggestion of this film may never come and yet amazingly... it did have inklings of potential.

    There is obvious some kind of back story to this movie other than "The Aliens and Predators try to kill each other", and had some of the following topics been covered... or at least included as captions at the bottom of the screen during the opening... some clarity would be gained:

    • What is the relationship between the Aliens and Predators?
    • Why is there a hybrid Alien/Predator?
    • Why does a single (implied) bad-ass Predator have to strip a fallen one for the equipment needed to take on the Aliens just after he arrives?
    • Why is the original Predator ship so stocked full of dangerous specimens?
    • What is the relationship between the crashed ship and the Predator who comes to clean up after it?
    • Why is that clean up a one man job?

    Just to name a few.

    I will give the Predator credit though... he does seem to be a firm believer in the Prime Directive as demonstrated by his careful removal of all physical evidence of the Aliens... but then I don't recall Captain Kirk or Picard killing and skinning someone who found them cleaning up.

    I should mention that I am not a fan of horror or slasher movies... if I were I'm sure I would have enjoyed the fact that I fully expect that the following conversation likely occurred on set at one point:

    It just occurred to me, we haven't gratuitously killed anyone in over 5 minutes.

    Yea, we should fix that

    I know lets have the stereotypical quasi sex scene which turns bad in the high school pool to try to keep the teenage boys interested

    Good idea, hey though, we are starting to run out of money so lets lets turn down the lights a bit so as to hide some of the cheesiness

    That's not a bad idea... in fact lets just stop using extra lights all together and break out some overused rain, not only will it add to the atmosphere, but will also let avoid those expensive and complicated long shots

    My friend and his cousin dared to call this movie science fiction, a concept I balked at and said "if so... what was the lesson, moral or contemporary issue that it dealt with?"

    The only explanation I could think of was that it had to do with trauma often caused to the average American family through the deployment of a parent overseas and the problematic reunifications that occur even when the parent returns unscathed.

    The moral of the story was that that kids should be extra thrilled their fighting parent is home and tell them so immediately and without delay, never once letting them feel guilty for serving their country or being absent from their child's life for even a day... cause if they don't, their father is likely to be eaten by an alien and their entire town is will be nuked by their own government.

    Lesson learned!

    The one upshot of this movie... was that after seeing it I felt only slight less dumber than I had after watching the Sci Fi channel's horrendous mini-series "Tin Man"... (something I've yet to blog about) as I'd only wasted 83 minutes on AvP while I'd wasted ~4-6 hours on Tin Man (depending on commercials).

  • Indefinite WHS testing in VPC

    In many homes this morning countless children screamed and yelled as they discovered Santa had visited and left them just what they'd asked for.

    What follows is something I learned a few weeks ago and that made me act similarly... only I was giggling like a school girl.

    This blog post last week was my Santa.

    A major pain point I've encountered with testing custom code in an unactivated copy of Windows Home Server running in Virtual PC is that it automatically syncs the guest PC's clock to that of the host PC, ensuring only 30 days of testing before needing to reinstall, not so anymore with the host_time_sync section in a .vpc file:

    <microsoft>
      <components>
        <host_time_sync>
          <enabled type="boolean">true</enabled>
        </host_time_sync>
      </components>

    Needless to say I was quite let down when months ago I saw this blog post from the same author, saying there was no way to do it. What's worse is that I missed the comment saying how it is possible.

    Now my test VPC will keep on reporting that it was installed on 12/2/2007, that today is 12/9/2007 and I've got 23 days until Windows requires activation... something it will keep thinking so long as I don't commit changes to the virtual hard disks.

    If however I save changes to the undo disks the counter will proceed forward... until I throw out those changes and revert back to the previous state with a mouse click.

    It should be noted that this kind of hack is largely worthless for piracy purposes (as far as Windows Home Server is concerned) and only useful for testing as it is only effective so long as you do not commit changed to the virtual hard disks... because if you do you allow the activation timer to keep on counting down and eventually expire.

    Merry Christmas and Happy Testing!

  • WHS Dev Tip #12: QButton, ConsoleToolBar, and LineBox

    Q: What are some of the other Home Server Controls that I can take advantage of in my add-in?

    A: Three of the most commonly used controls are QButton, ConsoleToolBar and LineBox which individually behave virtually identical to existing controls, only draw themselves in a more Home Server-ish style.

    QButton

    Likely the most commonly used Home Server Control is the simple QButton control which gives you a Vista like button... unfortunately does not offer as many options as the standard Button control, things like:

    • Height is locked
    • Limited TextImageRelation functionality
    • Changing the following properties does nothing:
      • ForeColor
      • BackColor
      • BackgroundImage
      • TextAlignment

    Despite these and other differences, the QButton is still a fantastic way to easily get a little more Home Server-ish styling in ones add-in.

    ConsoleToolBar

    One of the staples of most add-ins is the common use of the blue ConsoleToolBar control as seen the majority of Microsoft and third-party add-ins alike that try to stay with a WHS like theme:

    ConsoleToolBarButton - Existing Example

    To add one to a Home Server Add-in control, it's simply a matter of dragging it to the form and then using the designer to add new ConsoleToolBarButtons:

    Add ConsoleToolBarButton

    Note: you are free to add any other object that inherits from ToolStripItem, ConsoleToolBarButton is the only control that maintains the theme.

    One problem with using the designer to do this is that when a user moves the mouse over the button, the font color does not change as it does with the Microsoft built tabs:

    Default ConsoleToolBarButton

    vs

    Existing ConsoleToolBarButton

    This is due to the default constructor (required for and used by the Forms Designer) of ConsoleToolBar does not add a pair of event handlers to change the font color, instead we must do so ourselves if we want the effect:

    consoleToolBarButton1.MouseLeave += new System.EventHandler(consoleToolBarButtons_MouseLeave);
    consoleToolBarButton1.MouseEnter += new System.EventHandler(consoleToolBarButtons_MouseEnter);
    consoleToolBarButton2.MouseLeave += new System.EventHandler(consoleToolBarButtons_MouseLeave);
    consoleToolBarButton2.MouseEnter += new System.EventHandler(consoleToolBarButtons_MouseEnter);
     
    ...
     
    private void consoleToolBarButtons_MouseEnter(object sender, EventArgs e)
    {
       ConsoleToolBarButton button = sender as ConsoleToolBarButton; 
     
       button.ForeColor = Color.Black;
    } 
     
    private void consoleToolBarButtons_MouseLeave(object sender, EventArgs e)
    {
       ConsoleToolBarButton button = sender as ConsoleToolBarButton;
       button.ForeColor = Color.White;
    } 

    Once added we'll get this:


    Colorized ConsoleToolBarButton


    One possible issue that may arise using the above method is the text color not reverting if the button is disabled after the MouseEnter event, something that will keep a MouseLeave event from ever being fired. Instead it is good to be aware of this edge case and manually change the color when disabling the button.


    Line


    All throughout the Microsoft settings pages we see a style not often seen since Visual Basic 6 applications we all the rage: colored horizontal lines.


    Right off the bat we can use the Line control by dragging it to the form, however it can be rather finicky as it is used best when only one pixel tall, however other heights are certainly possible:


    Lines


    Problems can quickly be had if one attempts to change the size in the designer (ie without using the Properties window) where the line can get very large and unwieldy.


    Furthermore, when the line is only a pixel tall it is almost impossible to click on to select and then move around on the form.


    There is however a better way to use this throwback to a simpler time...


    LineBox


    The most common use for the Line control is through the LineBox control which looks and acts just like a GroupBox (ie a container control), only doesn't have a visible border and instead has a stylish blue line along the top next to the header text:


    LineBox1


    Unfortunately LineBox is another one of those controls written without the designer in mind, something we see when we find we are unable to change the header text in the designer.


    Instead LineBox exposes a member field named Header which is nothing but a custom label which controls what is actually displayed. To modify it in code it is as easy as:



    lineBox1.Header.Text = "Some Text Goes Here";

    One upshot of exposing the full control instead of just a Text property is that we can tweak it and make it even prettier... or uglier:


    LineBox2


    Of course we can avoid manually setting the text this way if we create our LineBox programmatically:



    LineBox lineBox2 = new LineBox("Header Text");

    A problem that you will likely encounter with LineBox is that you do not know at design time the actual height of the header which can easily lead to a child control being overlapped by the header:


    LineBox Overlap


    Examples


    Once again I have created a couple of simple add-ins which demonstrate how QButton, ConsoleToolBar, and LineBox can be used:


    HomeServerConsole with Controls Example 2


    Downloads:



    Conclusion


    QButton, ConsoleToolBar and LineBox are three semi-new controls that provide a fantastic way for a Home Server add-in developer to get the same functionality they are used to with existing controls, but with the benefit of staying with the Windows Home Server style of design.


    Next Time


    Next week we'll discuss the MessageListBox control, the very control that is used to display messages in the Home Network Health dialog and messages and the available and installed Add-ins.


    Tomorrow though as a special Christmas gift, a little tip that made me giggle like a little girl when I learned it.


    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.

  • WHS Developer Tip #11: FancyListView

    Q: How can make a ListView that looks more like what I see in the Home Server Console with so many images and progress bars?

    A: Another one of the wonderful undocumented features of Windows Home Server is the FancyListView control (Microsoft.HomeServer.Controls, HomeServerControls.dll) that is used by all of the official Home Server Console tabs for displaying of the system's shares, users, computers and hard drives.

    The first difference a user will notice is that it is drawn differently than a regular ListView, automatically making it look more Windows Home Server-ish in terms of it's shading, but also allows for the easy adding of images and progress bars in various different locations.

    Terminology

    Before digging in, lets go through a few terms used with ListViews so as to better understand the mechanics of what is used under the hood to draw a normal one.

    A ListView is the actual control itself which has multiple different ways of displaying lists of data which are controlled by the View property which include:

    • LargeIcon - Each item appears as a full-sized icon with a label below it.
    • Details - Each item appears on a separate line with further information about each item arranged in columns. The left-most column contains a small icon and label, and subsequent columns contain sub items as specified by the application.
    • SmallIcon - Each item appears as a small icon with a label to its right.
    • List - Each item appears as a small icon with a label to its right. Items are arranged in columns with no column headers.
    • Tile - Each item appears as a full-sized icon with the item label and subitem information to the right of it. The subitem information that appears is specified by the application.

    The most common View used in the Windows Home Server Console is Details which gives us the familiar row and column look.

    A ListView contains a collection of ListViewItems named Items which corresponds to the item in the first column when in Details view.

    Each ListViewItem has a collection of ListView.ListViewSubItems called SubItems which correspond to later items in the row.

    In order to automatically display an image inside of a ListViewItem, a programmer would specify with ImageKey or ImageIndex property the value corresponding to an ImageList instance that has been set to the SmallImageList property, in C# this would look like (assuming a ListView named listView1 has been created on the form and it's View property has been set to Details):

    //Create ImageList
    ImageList imageList1 = new ImageList();
    //Adjusting the size of the images can change the height of a row of data
    imageList1.ImageSize = new Size(32, 32);
    imageList1.ColorDepth = ColorDepth.Depth32Bit;
     
    //Add some image to the list with no keys
    imageList1.Images.Add(CommonImages.ErrorImage32x32);
    imageList1.Images.Add(CommonImages.HomeServerImage32x32);
    imageList1.Images.Add(CommonImages.InformationImage32x32);
     
    //Add an image to the list with the key Healthy key
    imageList1.Images.Add("Healthy", CommonImages.StatusHealthy32);
    //Add an image to the list with the key Warning key
    imageList1.Images.Add("Warning", CommonImages.WarningImage32x32);
     
    //Associate the ImageList with the ListView
    listView1.SmallImageList = imageList1;
     
     
    //Create first ListViewItem
    ListViewItem listViewItem1 = new ListViewItem();
    listViewItem1.Text = "Item 1";
    //Display the first image in the list
    listViewItem1.ImageIndex = 0;
    listView1.Items.Add(listViewItem1);
     
     
    //Create second ListViewItem
    ListViewItem listViewItem2 = new ListViewItem();
    listViewItem2.Text = "Item 2";
    //Display the image from the ImageList with the Warning key
    listViewItem2.ImageKey = "Warning";
    listView1.Items.Add(listViewItem2);
     
     
    //Add Column to the ListView to enable item(s) to show up
    ColumnHeader column1 = new ColumnHeader();
    column1.Text = "Column 1";
    column1.Width = 100;
    listView1.Columns.Add(column1);

    Which gives us:

    Standard ListView

    This is how a normal ListView functions and a FancyListView works in virtually the same way, only it adds to new ListViewSubItems to the mix.

    ImageSubItem

    A drawback of the stock ListViewSubItem class is that it does not have any built-in support for images and leaves such work to the programmer to implement themselves. This is where ImageSubItem comes into play, providing the ImageIndex and ImageKey properties that use the same ImageList as any other ListViewItems on the list.

    To expand the earlier example, lets start with the following nearly identical code (assuming a FancyListView named fancyListView1 has been created on the form and it's View property has been set to Details):

    //Create ImageList
    ImageList imageList1 = new ImageList();
    //Adjusting the size of the images can change the height of a row of data
    imageList1.ImageSize = new Size(32, 32);
    imageList1.ColorDepth = ColorDepth.Depth32Bit;
     
    //Add some image to the list with no keys
    imageList1.Images.Add(CommonImages.ErrorImage32x32);
    imageList1.Images.Add(CommonImages.HomeServerImage32x32);
    imageList1.Images.Add(CommonImages.InformationImage32x32);
     
    //Add an image to the list with the key Healthy key
    imageList1.Images.Add("Healthy", CommonImages.StatusHealthy32);
    //Add an image to the list with the key Warning key
    imageList1.Images.Add("Warning", CommonImages.WarningImage32x32);
     
    //Associate the ImageList with the FancyListView
    fancyListView1.SmallImageList = imageList1;
     
     
    //Create first ListViewItem
    ListViewItem listViewItem1 = new ListViewItem();
    listViewItem1.Text = "Item 1";
    //Display the first image in the list
    listViewItem1.ImageIndex = 0;
    fancyListView1.Items.Add(listViewItem1);
     
     
    //Create second ListViewItem
    ListViewItem listViewItem2 = new ListViewItem();
    listViewItem2.Text = "Item 2";
    //Display the image from the ImageList with the Warning key
    listViewItem2.ImageKey = "Warning";
    fancyListView1.Items.Add(listViewItem2);
     
     
    //Add Column to the FancyListView to enable item(s) to show up
    ColumnHeader column1 = new ColumnHeader();
    column1.Text = "Column 1";
    column1.Width = 100;
    fancyListView1.Columns.Add(column1);

    Which in turn displays the following for us:

    FancyListView - Just ListViewItems

    In order to add a pair of ImageSubItems that use an image from the existing Image List, we need only add the following code:

    //Create ImageSubItem using ImageIndex and add to first ListViewItem
    FancyListView.ImageSubItem imageSubItem1 = new FancyListView.ImageSubItem();
    imageSubItem1.Text = "Sub Item 1";
    //Set to imageIndex 1
    imageSubItem1.ImageIndex = 1;
    listViewItem1.SubItems.Add(imageSubItem1);
     
    //Create ImageSubItem using ImageKey and add to second ListViewItem
    FancyListView.ImageSubItem imageSubItem2 = new FancyListView.ImageSubItem();
    imageSubItem2.Text = "Sub Item 1";
    //Set image with Healthy key
    imageSubItem2.ImageKey = "Healthy";
    listViewItem2.SubItems.Add(imageSubItem2);
     
    //Add an extra Column to ListViewFancy to enable new Sub Items to show up
    ColumnHeader column2 = new ColumnHeader();
    column2.Text = "Column 2";
    column2.Width = 100;
    fancyListView1.Columns.Add(column2);

    Which makes our example look something like this:

    FancyListView - ImageSubItems

    FilledBarSubItem

    Another neat feature we've seen on the Computers & Backups tab is a progress bar, something that programmatically behaves not unlike the progress bars and SubItems we've already used or added.

    To create and add them, we need only add this code to the end of our running example:

    //Create new Filled Bar of the Rectangle style
    FancyListView.FilledBarSubItem filledBar1 = new FancyListView.FilledBarSubItem();
    filledBar1.Text = "Bar 1";
    filledBar1.PercentageFilled = 33;
    filledBar1.DrawStyle = FancyListView.FilledBarStyle.Rectangle;
    listViewItem1.SubItems.Add(filledBar1);
     
    //Create new Filled Bar of the RoundedRectangle style
    FancyListView.FilledBarSubItem filledBar2 = new FancyListView.FilledBarSubItem();
    filledBar2.Text = "Bar 2";
    filledBar2.PercentageFilled = 66;
    filledBar2.DrawStyle = FancyListView.FilledBarStyle.RoundedRectangle;
    listViewItem2.SubItems.Add(filledBar2);
     
     
    //Add third column to allow new FilledBars to show up
    ColumnHeader column3 = new ColumnHeader();
    column3.Text = "Column 3";
    column2.Width = 150;
    fancyListView1.Columns.Add(column3);

    which makes our example now look like:

    FancyListView - FilledBarSubItem

    Aside from our ability to change the style of the bar (Rectangle vs RoundedRectangle) which we see demonstrated by the two FilledBarSubItem instances used above, another very useful option we have is the ability to specify additional colors for ranges.

    Ordinarily if you need to specify some visual range difference, the ProgressBar control isn't enough, instead other controls may be employed or worse yet... writing your own which would likely involve manually checking the ranges ourselves, instead FilledBarSubItem gives us the following properties to do that for us:

    • WarningColor
    • WarningPercentage
    • CriticalColor
    • CriticalPercentage

    Together we can get automatic colorization:

    FancyListView - Colorized FilledBarSubItem

    All by just by these lines to the above running example:

    filledBar1.WarningPercentage = 33;
    filledBar1.WarningColor = Color.Orange;
    filledBar1.CriticalPercentage = 66;
    filledBar1.CriticalColor = Color.Red;
     
    filledBar2.WarningPercentage = 33;
    filledBar2.WarningColor = Color.Orange;
    filledBar2.CriticalPercentage = 66;
    filledBar2.CriticalColor = Color.Red;

    And that's in addition to being able to specify an arbitrary color for our bar in the first place.

    Refreshing

    Unlike a control like the TextBox or Button classes, simply updating properties of a ImageSubItem or FilledBarSubItem will not cause them to visually be updated because they aren't controls, instead they are only visually updated when the parent FancyListView is redrawn, something that ordinarily will occur when ever the containing form is hidden and then shown, something is dragged over the control, or you click on it.

    Instead of relying on the system or the user, you as the programmer can call the FancyListView's Invalidate() or Refresh() methods to force it to redraw itself and all of the ImageSubItem or FilledBarSubItem instances so that any chances are then visible just as you can with most other controls, however FancyListView which inherits from ListView offers an even better option, namelyRedrawItems() which allows you to redraw only those items you want to in the list which can be as simple as:

    filledBar1.PercentageFilled += 1;
    filledBar2.PercentageFilled += 1;
     
    fancyListView1.RedrawItems(startIndex, endIndex, false);

    Sizing and Stretching

    In the previous examples I've focused on using icons with a size of 32x32 which causes each row in the FancyListView to be 32 pixels tall. Want to make it shorter? Simply change the size of the ImageList that the FancyListView uses.

    One quirk of using this method to define the size of our rows, is that it is not uncommon to have a large 32x32 image for the first column, but then want a small 16x16 image for a status icon... not unlike how the Home Server Console notes drive or duplication status, you'll find that the smaller image will automatically be stretched to fill the available area.

    In order to make such a small image stay small, you should use a larger image that contains the smaller image, not unlike how the CommonImages class exposes GrayIcon, GreenIcon and RedIcon which are each only 16x16, but also available as part of larger 32x32 images as GrayIcon32, GreenIcon32 and RedIcon32 as well.

    ListViewItemSorter

    Another one of the advantages of FancyListView is that does sorting right out of the box without any work from you as a programmer whenever a user clicks on a column header.

    With an ordinary ListView, simply creating a class that implements the IComparer interface and setting an instance of it to the ListViews ListViewItemSorter property is all that is needed. FancyListView takes this a step further by defining a custom sorting class ListViewColumnSorter (Microsoft.HomeServer.Controls, HomeServerControlls.dll) which it automatically uses and requires.

    Unfortunately an ordinary custom sorting class that simply implements the IComparer interface cannot be used because internally FancyListView.ListViewItemSorter typecasts the value to a ListViewColumnSorter, which forces any other sorter to from ListViewColumnSorter.

    Examples

    I have built a pair of sample add-ins that demonstrate a few of the things discussed above in a (very) mock (and not very accurate) Shared Folders like display which shows off several static ImageSubItems and a FilledBarSubItem that is updated and then moved once it's maximum value has been reached:

    FancyListViewDemo

    Downloads:

    Conclusion

    FancyListView provides an easy to use mechanism for displaying additional information to a user by allowing images in any columns and progress bars to better inform the user of the current state of the system or whatever else the add-in wants to say.

    Next Time

    Next week we'll dive into a few more controls in the HomeServerControls.dll assembly, some of their quirks and how they can be better used to make our add-ins look more at home in the Home Server Console.

    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.

  • WHS Developer Tip #10: Home Server Controls

    Did you know that most of the custom visual controls used in the Windows Home Server Console (with the exception of the graphs) are unofficially available for your use in your add-ins?

    In order to access them in the designer, simply add the controls to your Toolbox, to do so:

    1. Launch Visual Studio
    2. Open desired project
    3. Open form or user control in designer
    4. If the Toolbox is not displayed, use the View -> Toolbox menu option to display it
    5. Right click inside of Toolbox and select Add Tab
    6. Specify name of tab (ie Windows Home Server)
    7. Right click inside of new tab and select Choose Items...
    8. In the Choose Toolbox Items dialog, click the Browse button and browse to location of HomeServerControls.dll (C:\Program Files\Windows Home Server\ if working directly on the server)
    9. Press the space bar to check all selected controls from HomeServerControls.dll
    10. Click the OK button to close the dialog

    Once done you should be greeted with a new list of available controls:

    Populated Toolbox

    Designer Friendliness

    Because the controls in HomeServerControls.dll were not intended for use by third-party programmers, most of the controls are not the most designer or developer friendly. While the majority of the controls that are displayed in the Toolbox can be dragged to the form and modified there, some cannot... either because they lack a default constructor or other dependencies. Of those that can be, issues will be seen from time to time of a property or other operation that needs to be done that cannot be made via the designer... leading to the necessity of some extra manual tweaks in code.

    A little historical note... initially the biggest problem with these controls was that very few of them had a default (parameterless) constructor which made it it impossible for a programmer to use the Windows Forms designer to use a good number of them without manually creating each control programmatically (ie how the official tabs in the Home Server Console were built) and largely ignoring the benefits of the designer.

    It is here where the necessity for some of these extra tweaks come into play.

    Despite the majority of the controls now having default constructors... a number of them have extra configuration work being done in the their non-default constructors but not in the default one, forcing a third-party developer to go without the additional functionality (likely not even knowing what they are missing), guessing as to what is being done and doing it themselves, or reverse engineering to determine exactly what they lack.

    Another issue (albeit minor) encountered when dealing with HomeServerControls.dll is that not one of the controls in it is decorated with the ToolboxBitmap attribute (which enables the displaying of a descriptive icon in the Toolbox) which means developers must rely on the names of the controls instead if icons for finding what they want in the Toolbox.

    Administrative Permissions

    For years we've heard that we should not log into our computers as an Administrator unless it is absolutely necessary... they are right. Unfortunately there are a few times when dealing with HomeServerControls.dll it is necessary.

    While I cannot provide a list of controls and cases, it is possible that when viewing a form or user control in the Visual Studio Forms designer (when not run as Administrator) that designer errors would be encountered informing you that certain assemblies cannot be loaded.

    If you are sure that those assemblies should be accessible, re-launching Visual Studio with administrative permissions should allow you to proceed.

    Does this mean that you should run Visual Studio as administrator all the time when working on your add-in? Certainly not. Just be aware that if you encounter these errors... you've likely hit one of these rare cases and will need to re-load your project in an instance of Visual Studio that is running as Administrator.

    Other Assemblies

    HomeServerControls.dll does not live in a vacuum and in turn references multiple other assemblies when one of it's controls is used... assemblies that your add-in project will also need to reference. The easiest way to achieve is through the same registry hack features in Dev Tip #6 to allow Visual Studio to know where the assemblies are, allowing Visual Studio to automatically add the references for you.

    Next Time

    Tomorrow will come the previously promised post on the FancyListView control and will discuss other controls from HomeServerControls.dll in future posts.

    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.

  • WHS Dev Tips: Correction

    On Monday and Tuesday I made a horrible mistake in the two part WHS Dev Tip on remote and local debugging as I completely forgot about the static Control.CheckForIllegalCrossThreadCalls property that can be used to get around debug time exceptions such as this one:

    Invalid Operation Exception

    Both tips #9 and #9.5 have been updated to reflect this new information and to make working with Express sound less full of doom and gloom.

    I must admit that until very recently... I didn't know about this property as I had no need for it. When I'd have an issue with an illegal cross thread operation in my code, I'd fix it as I'm quite anal about fixing easily reproduced bugs and not just suppressing them.

    None the less the underlying problem that lead to my initial statements of doom and gloom are still accurate... the Home Server Console is doing some illegal cross threading, something that really should be fixed.

  • Visual Studio 2008 Thank You Cube Unboxing

    ... aka "Ship It Award"

    This afternoon I found this box (which weighed a good pound and a half) at my door:

    Shipped Package

    And inside a well bubble wrapped package:

    Bubble wrap

    The box:

    The box

    Inside:

    The box

    Sadly it seems the cube was just too large for it's container as it had broken free of some of the perforated cardboard:

    Broken holder 1

     

    Broken holder 2

    Once out, it was beautiful:

    The Cube

    And for scale, next to a Channel 9 guy:

    C9 & Cube

    (I apologize for the quality of my camera/flash)

  • Now merely overweight

    This morning I hopped on the scale for my daily weigh in and it told me I'd reached 246 lbs.

    Woot!

    While not an important number on it's own... nor is the 169.2 lbs I've lost since starting very special either, a quick look at a BMI calculator (along with my height of 6'4") tells me that I've now got a BMI (yes I know it's a flawed system) of 29.9... which means reached the zone of 'overweight' instead of 'obese'.

    Yippie.

    Today:

    169.2 Down - Front

    169.2 Down - Side

    Compare that to before this all started:

    Before - Front

    Next stop... a BMI of <25 and being of 'normal weight' which we should see in another... 42 lbs or so.

  • Proof of concept add-in: Tab Management

    Part of the reason I created Tab Scroller was that at times I just have too many tabs to deal with in the Windows Home Server Console and today I came up with another method of dealing with large numbers of them... a Tab Management tab.

    What does it do? It is a tab itself, which in turn loads a specified group of add-ins itself instead of having the Home Server Console do so (via renaming of the files) and then displaying the appropriate control when the desired one is selected from the presented list box:

    Tab Management Test

    The amazing thing about this add-in... is that it doesn't do any crazy hacks the way Tab Reorderer or Tab Scroller do.

    Unfortunately this add-in is just a proof of concept test right now and is not something I'm likely to release anytime soon... largely because I can't decide on a good way to display the settings in the Settings dialog (something I am responsible for in order to make the main form work the way it does).

    I figure though that this will be a good place to add the functionality of Tab Reorderer and Tab Scroller in once it does see the light of day and users.

  • WHS Developer Tip #9.5: Debugging (Part 2: Local)

    Q: Remote debugging is fine and dandy... but what about debugging my application locally?


    A: For those who don't want to deal with the complexities of remote debugging, want the simplicity of having everything on a single machine and/or do not have a full copy of Visual Studio 2005 or 2008... then local debugging can be the way, however can also be problematic and limited.


    Software Requirements



    • Visual Studio (2005, 2008 or Express)
    • Running copy of Windows Home Server

    It is highly suggested that if you install a tool like Visual Studio to a Home Server, that you only do so to one running in Virtual PC in case something gets screwed up, leaving your running Home Server pristine and untouched except for testing near final versions of your add-in.


    Installing Visual Studio (Express)


    After downloading the Express Edition of your choice (C# or VB.NET is suggested), simply launch it and go through the setup process, accepting all defaults.


    During the setup process the installer will download the necessary files, install them and let you know when it's all done and ask you to reboot (which you should accept).


    Configuring Visual Studio


    So as to make Visual Studio on our Home Server more integrated with the development experience, we should tell Visual Studio where to look for the common Home Server assemblies that your add-in will need to reference, to do so you'll want to add a registry key as noted in Dev Tip #6, or download and import this file into the registry on your Home Server.


    Next, to make Visual Studio help you build a project from a template, you should download one of the Add-in Project Templates (C# Template, VB.NET Template) and copy it to one of the following locations (depending on the language and version of Visual Studio you will be using):


    C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual Basic\


    or


    C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\


    Remember when using the project that due to the Visual Studio bug (2005, 2008) you will need to change the assembly name of the project.


    Configuring Project (Express)


    While the previous changes we've made affect the entire system, the next ones affect only the project that we'll be working with which means it is here you will want to create your new project (and save it) or open an existing one.


    Your method of configuration will depend on the version of Visual Studio you are running... if you are running a non-Express version of Visual Studio, skip ahead to the next section... otherwise get ready for a little bit of project file hacking.


    As discussed in Dev Tip #7, the Express Editions honor many configuration options in the Project files that they themselves do not provide a user interface to specify... two of those items we will need to set to copy the newly built add-in to the appropriate directory and launch the Home Server Console, to do so:


    It is suggested that you back up your project file prior to following these steps in case a mistake is made.



    1. Open the your project file in a text editor(ProjectName.csproj or ProjectName.vbproj depending on the language)

    2. Modify the file to end with the following:


    3. <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        ...
        <PropertyGroup>
          <PostBuildEvent>copy "$(TargetDir)\$(TargetName).*" "C:\Program Files\Windows Home Server\"</PostBuildEvent>
        </PropertyGroup>
      </Project>

    4. Close the project file

    5. Create a new text file named ProjectName.csproj.user or ProjectName.vbproj.user in the same directory as the previously edited project file

    6. Add the following contents to that file:


    7. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
          <StartAction>Program</StartAction>
          <StartProgram>C:\Program Files\Windows Home Server\HomeServerConsole.exe</StartProgram>
          <StartWorkingDirectory>C:\Program Files\Windows Home Server\</StartWorkingDirectory>
        </PropertyGroup>
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
          <StartAction>Program</StartAction>
          <StartProgram>C:\Program Files\Windows Home Server\HomeServerConsole.exe</StartProgram>
          <StartWorkingDirectory>C:\Program Files\Windows Home Server\</StartWorkingDirectory>
        </PropertyGroup>
      </Project


    An alternative to steps 5 and 6 is that you can download this file, rename it as appropriate and place it next to the project file in question.


    In the above steps, you have configured your project to copy the new add-in to the C:\Program Files\Windows Home Server\ directory, and then optionally launch the Home Server if you wish to debug your add-in in it.


    Configuring Project (non-Express)


    If you have installed a full copy of Visual Studio to your Home Server, after launching it and opening the project in question and...



    1. Right click on the project in Solution Explorer and select Properties
    2. Select Build Events tab
    3. Enter the following text into the Post-build event command line text box:

      • copy "$(TargetDir)\$(TargetName).*" "C:\Program Files\Windows Home Server\"

    4. Select the Debug tab
    5. Check the Start external program and specify the following path:

      • C:\Program Files\Windows Home Server\HomeServerConsole.exe

    6. Specify the following path for the Working directory:

      • C:\Program Files\Windows Home Server\

    7. Exit settings

    Now your Visual Studio is configured to automatically copy the updated build to the Home Server Directory and launch the Home Server Console to test it out when you choose.


    Debugging


    When it comes time to debug... simply pressing F5, selecting the Debug -> Start debugging or clicking the Start Debugging will rebuild the add-in and launch the Windows Home Server Console, allowing you many of the same debugging features that you are used to.


    Unfortunately early into your debugging you will likely encounter an exception such as this one:


     Invalid Operation Exception


    This is caused by the Home Server Console throwing an exception that it probably shouldn't.


    Unfortunately here we hit a limitation the Express Editions which we can't so easily work around, while the non-Express versions Visual Studio allow you to attach to a running process at any time, Express only allows you to attach to the process when first launching it, nor does it allow for launching of the project (or some program that will use it's output) from the development environment without attaching the debugger as you can in the higher versions.


    Hopefully some of the issues in the Home Server Console that keep it from being easily debuggable will be resolved in a later update or version.


    In the mean time however this means that debugging and testing an add-in in a copy of Visual Studio Express that is running on a Windows Home Server is much more difficult than than if a higher version is used, however with some care these errors can be mitigated by slowly learning which operations you carry out raise an exception. The most common place I've seen it for instance is when entering Settings.


    Alternative


    At first glance, ones Settings page may seem impossible to test with the debugger because the exception is raised prior to your ever being able to display it. One alternative is to temporarily change the HomeServerTabExtender class to create an instance of your add-ins settings page control instead of the normal main tab, effectively changing something like this:



    Private consoleServices As IConsoleServices
    Private m_tabControl As MainTabUserControl
     
    Public Sub New(ByVal width As Integer, ByVal height As Integer, ByVal consoleServices As IConsoleServices)
       Me.m_tabControl = New MainTabUserControl()
       Me.consoleServices = consoleServices
    End Sub

    to this:



    Private consoleServices As IConsoleServices
    Private m_tabControl As SettingsTabUserControl
     
    Public Sub New(ByVal width As Integer, ByVal height As Integer, ByVal consoleServices As IConsoleServices)
       Me.m_tabControl = New SettingsTabUserControl()
       Me.consoleServices = consoleServices
    End Sub

    This then allows you to have the debugger attached when working with your settings page, just be sure to change it back before releasing your new add-in to the world.


    Conclusion


    Local debugging with Visual Studio is very possible, it is not recommended with Express due to its inability to attach to an existing running process and the Home Server Consoles propensity to raise InvalidOperationExceptions, leading to the requirement to be extraordinarily careful of what operations are carried out with the debugger attached, and rendering certain area's


    Next Time


    Next week I'll go into the FancyListView control which is used by most of the existing tabs to show a list of data with multiple attributes attached and show you how you can add status icons and even a progress bar in places you cannot easily do with a run-of-the-mill ListView control.


    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.

More Posts « Previous page - Next page »
Powered by Community Server (Commercial Edition), by Telligent Systems