<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9 - Entries tagged with Productivity</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Tags/productivity/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9 - Entries tagged with Productivity</title>
      <link>http://channel9.msdn.com/Tags/productivity</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Tags/productivity</link>
    <language>en</language>
    <pubDate>Sun, 26 May 2013 06:29:04 GMT</pubDate>
    <lastBuildDate>Sun, 26 May 2013 06:29:04 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>59</c9:totalResults>
    <c9:pageCount>3</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Desktop Wallpaper Cheat Sheets</title>
      <description><![CDATA[ <p>This is a genius idea. ThemeFlash.com has a great list of <a href="http://www.themeflash.com/45-cheat-sheet-desktop-wallpaper-for-web-designers-and-developers/">45 cheat sheet wallpapers</a> for web designers and developers. Some of my favorites so far include the <a href="http://www.smashingmagazine.com/2010/02/10/photoshop-keyboard-shortcuts-cheat-sheet-pdf/">Photoshop shortcuts</a>, <a href="http://www.squidspot.com/Periodic_Table_of_Typefaces.html">Periodic Table of Typefaces</a>, and <a href="http://font.is/2009/07/wallpaper-font-anatomy/">The Anatomy of Type</a>. I'd love to see some Visual Studio or Windows 7 shortcut wallpapers. Remember, if you're working in an application and you want to see the list of shortcuts, all you need to do is drag your mouse down to the bottom right 'show desktop' area, or hit Windows&#43;Space Bar on your keyboard.&nbsp;</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e03710225b164df582b99e7200866993">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Desktop-Wallpaper-Cheat-Sheets</comments>
      <itunes:summary> This is a genius idea. ThemeFlash.com has a great list of 45 cheat sheet wallpapers for web designers and developers. Some of my favorites so far include the Photoshop shortcuts, Periodic Table of Typefaces, and The Anatomy of Type. I&#39;d love to see some Visual Studio or Windows 7 shortcut wallpapers. Remember, if you&#39;re working in an application and you want to see the list of shortcuts, all you need to do is drag your mouse down to the bottom right &#39;show desktop&#39; area, or hit Windows&amp;#43;Space Bar on your keyboard.&amp;nbsp; </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Desktop-Wallpaper-Cheat-Sheets</link>
      <pubDate>Fri, 21 Jan 2011 08:19:36 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Desktop-Wallpaper-Cheat-Sheets</guid>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/d8186288-86da-49a3-b261-971cf1034f89.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/53a8c39d-44cb-4052-87a9-e308508b07cb.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/0b5dfbb5-16ae-4e21-a9f9-ebcacbc1995f.jpg" height="240" width="320"></media:thumbnail>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Desktop-Wallpaper-Cheat-Sheets/RSS</wfw:commentRss>
      <category>Productivity</category>
    </item>
  <item>
      <title>Iconnect The future of Business Productivity </title>
      <description><![CDATA[ <p>Recordings from<a href="https://partner.microsoft.com/belux-nl/40127223"> I connect</a> in Belgium. </p><p>Jan Smessaert introduces his session called 'The Future of Business Productivity' </p><p>&nbsp;</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:f2aa5552086f4f8fb1d79e0d00836f5b">]]></description>
      <comments>http://channel9.msdn.com/Blogs/liese/Iconnect-The-future-of-Business-Productivity</comments>
      <itunes:summary> Recordings from I connect in Belgium.  Jan Smessaert introduces his session called &#39;The Future of Business Productivity&#39;  &amp;nbsp; </itunes:summary>
      <itunes:duration>119</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/liese/Iconnect-The-future-of-Business-Productivity</link>
      <pubDate>Tue, 12 Oct 2010 15:02:47 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/liese/Iconnect-The-future-of-Business-Productivity</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_100_ch9.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_220_ch9.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_320_ch9.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_512_ch9.jpg" height="384" width="512"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_85_ch9.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_2MB_ch9.wmv" expression="full" duration="119" fileSize="44486131" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_ch9.mp3" expression="full" duration="119" fileSize="954757" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_ch9.mp4" expression="full" duration="119" fileSize="12727599" type="video/mp4" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_ch9.wma" expression="full" duration="119" fileSize="972265" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_ch9.wmv" expression="full" duration="119" fileSize="22742145" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_Zune_ch9.wmv" expression="full" duration="119" fileSize="14070200" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://ecn.channel9.msdn.com/o9/ch9/6f5b/f2aa5552-086f-4f8f-b1d7-9e0d00836f5b/iconnectinterviewjansmessaert_ch9.wmv" length="22742145" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Anthony de Bruyn</dc:creator>
      <itunes:author>Anthony de Bruyn</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/liese/Iconnect-The-future-of-Business-Productivity/RSS</wfw:commentRss>
      <category>BeLux</category>
      <category>BPOS</category>
      <category>Cloud</category>
      <category>Exchange</category>
      <category>Online Services</category>
      <category>Partner</category>
      <category>Partners</category>
      <category>Productivity</category>
    </item>
  <item>
      <title>Steve Anonsen and John Rivard: Inside LightSwitch</title>
      <description><![CDATA[
<p>&quot;<a shape="rect" href="http://www.microsoft.com/visualstudio/en-us/lightswitch" shape="rect"><em>Visual Studio LightSwitch</em></a><em>&nbsp;is a new tool aimed at easily building data-driven applications, such as an inventory system or a&nbsp;basic customer relationship
 management system</em>.&quot;<br /><br />Typically, when making difficult things <em>easy</em>, the price is solving a set of very
<em>difficult</em> technical problems. In this case, the LightSwitch engineering team needed to remove the necessity for non-programmer domain experts to think about application&nbsp;tiers (e.g., client, web server, and database) when constructing data-bound applications
 for use in their daily business lives. LightSwitch is designed for non-programmers, but it also offers the ability to customize and extend it, which will most likely be done by experienced developers (see Beth Massi's&nbsp;<a shape="rect" href="http://channel9.msdn.com/posts/funkyonex/Visual-Studio-LightSwitch-Beyond-the-Basics/" shape="rect" target="_blank">Beyond
 the Basics interview</a> to learn about some&nbsp;of&nbsp;the more advanced capabilities).<br /><br />This conversation isn't really about how to use LightSwitch (or how to extend it to meet your specific needs)—that's already been covered. Rather, in this video we meet the architects behind LightSwitch, Steve Anonsen and John Rivard, focusing on how LightSwitch
 is designed and what problems it actually solves as a consequence of the design. Most of the time is spent at the whiteboard, discussing architecture and solutions to some hard technical problems. This is Going Deep, so we will open LightSwitch's hood and
 dive into the rabbit hole.<br /><br />Enjoy!<br /><br />For more information on LightSwitch, please see:</p>
<li><a shape="rect" href="http://msdn.com/lightswitch" shape="rect" target="_blank">Visual Studio LightSwitch Developer Center</a>
</li><li><a shape="rect" href="http://blogs.msdn.com/b/lightswitch" shape="rect" target="_blank">Visual Studio LightSwitch Team Blog</a>
</li><li><a shape="rect" href="http://social.msdn.microsoft.com/Forums/en-us/category/vslightswitch" shape="rect" target="_blank">Visual Studio LightSwitch Forums</a>
</li> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:8b6eb6a82b124413ac079de90185cff5">]]></description>
      <comments>http://channel9.msdn.com/Shows/Going+Deep/Steve-Anonsen-and-John-Rivard-Inside-LightSwitch</comments>
      <itunes:summary>
&amp;quot;Visual Studio LightSwitch&amp;nbsp;is a new tool aimed at easily building data-driven applications, such as an inventory system or a&amp;nbsp;basic customer relationship
 management system.&amp;quot;Typically, when making difficult things easy, the price is solving a set of very
difficult technical problems. In this case, the LightSwitch engineering team needed to remove the necessity for non-programmer domain experts to think about application&amp;nbsp;tiers (e.g., client, web server, and database) when constructing data-bound applications
 for use in their daily business lives. LightSwitch is designed for non-programmers, but it also offers the ability to customize and extend it, which will most likely be done by experienced developers (see Beth Massi&#39;s&amp;nbsp;Beyond
 the Basics interview to learn about some&amp;nbsp;of&amp;nbsp;the more advanced capabilities).This conversation isn&#39;t really about how to use LightSwitch (or how to extend it to meet your specific needs)—that&#39;s already been covered. Rather, in this video we meet the architects behind LightSwitch, Steve Anonsen and John Rivard, focusing on how LightSwitch
 is designed and what problems it actually solves as a consequence of the design. Most of the time is spent at the whiteboard, discussing architecture and solutions to some hard technical problems. This is Going Deep, so we will open LightSwitch&#39;s hood and
 dive into the rabbit hole.Enjoy!For more information on LightSwitch, please see: 
Visual Studio LightSwitch Developer Center
Visual Studio LightSwitch Team Blog
Visual Studio LightSwitch Forums
</itunes:summary>
      <itunes:duration>3974</itunes:duration>
      <link>http://channel9.msdn.com/Shows/Going+Deep/Steve-Anonsen-and-John-Rivard-Inside-LightSwitch</link>
      <pubDate>Wed, 25 Aug 2010 20:08:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/Going+Deep/Steve-Anonsen-and-John-Rivard-Inside-LightSwitch</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/568420_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/568420_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_320_ch9.png" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_512_ch9.png" height="384" width="512"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_85_ch9.png" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_2MB_ch9.wmv" expression="full" duration="3974" fileSize="1517928263" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_ch9.mp3" expression="full" duration="3974" fileSize="31793408" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_ch9.mp4" expression="full" duration="3974" fileSize="811328362" type="video/mp4" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_ch9.wma" expression="full" duration="3974" fileSize="32141769" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_ch9.wmv" expression="full" duration="3974" fileSize="864317269" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_Zune_ch9.wmv" expression="full" duration="3974" fileSize="559229324" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://ecn.channel9.msdn.com/o9/ch9/8420/568420/InsideLightSwitch_ch9.wmv" length="864317269" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Charles</dc:creator>
      <itunes:author>Charles</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/Going+Deep/Steve-Anonsen-and-John-Rivard-Inside-LightSwitch/RSS</wfw:commentRss>
      <category>Architecture</category>
      <category>Databinding</category>
      <category>LightSwitch</category>
      <category>Productivity</category>
      <category>programming tools</category>
      <category>Silverlight</category>
      <category>Visual Studio</category>
    </item>
  <item>
      <title>Personalize Outlook 2010</title>
      <description><![CDATA[As great as the ribbon is in Outlook 2010, often some of the functions you want to use from it can be on different tabs and slow you down a bit. There's a very easy way to customize your messages for the functions you use the most. If you look at the top
 of your email message you'll see a drop down arrow, click that and select More Commands. Here you can select which functions you want to see displayed across the Quick Access Toolbar on the title bar. You can add Insert Hyperlink, Add Photo from File, or any
 of the other functions you use the most. <br /><br />From that drop down arrow, you can set whether the Quick Access Toolbar shows on the title bar or below the Ribbon. You can also minimize the Ribbon so the body of it only shows up when clicking the tab titles at the top of the message.
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:c560dd2a3cd447dd93b99dea00a21368">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/Personalize-Outlook-2010</comments>
      <itunes:summary>As great as the ribbon is in Outlook 2010, often some of the functions you want to use from it can be on different tabs and slow you down a bit. There&#39;s a very easy way to customize your messages for the functions you use the most. If you look at the top
 of your email message you&#39;ll see a drop down arrow, click that and select More Commands. Here you can select which functions you want to see displayed across the Quick Access Toolbar on the title bar. You can add Insert Hyperlink, Add Photo from File, or any
 of the other functions you use the most. From that drop down arrow, you can set whether the Quick Access Toolbar shows on the title bar or below the Ribbon. You can also minimize the Ribbon so the body of it only shows up when clicking the tab titles at the top of the message.
</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/Personalize-Outlook-2010</link>
      <pubDate>Fri, 11 Jun 2010 06:59:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/Personalize-Outlook-2010</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/689d32a3-ace8-4d97-afb7-713adfdf668e.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/553641_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/553641_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/6df9020b-e652-45d8-8ea7-f8adfdf85cf1.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/Personalize-Outlook-2010/RSS</wfw:commentRss>
      <category>Office 2010</category>
      <category>Outlook</category>
      <category>Productivity</category>
    </item>
  <item>
      <title>Coding 4 Fun - Windows 7 Taskbar</title>
      <description><![CDATA[
<p><img title="image" border="0" alt="Windows 7" align="right" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image101.png" width="84" height="84">Looking to take advantage of some new Windows 7 goodness?&nbsp; Learn how to work
 with some of the great new taskbar features to create a more streamlined user interface.</p>
<h3>Introduction</h3>
<p>Windows 7 brings with it a large number of new features that will be available to developers from day one.&nbsp; These are really nice additions that will make applications more natural to work with.&nbsp; One of the new areas of enhancements is the taskbar.&nbsp; The
 taskbar has always been a pretty simple way to see what's running and switch between tasks.&nbsp; Moving from XP to Vista, we got cool previews, but that's about it.&nbsp; With Windows 7, now we can drag-and-drop minimized app icons to change their order, we can pin
 apps there even if they aren't running (replacing Quick Launch functionality).&nbsp; You can also right-click the icons to restore or close the window.&nbsp; Better still, many apps give you additional information upon right-click, such as Recent lists, or actions like
 changing your Live Messenger status:</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image1.png"><img title="Jump list for Windows Live Messenger" border="0" alt="Jump list for Windows Live Messenger" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image1_thumb.png" width="126" height="240"></a><em>
</em></p>
<p align="center"><em>Image 1: Jump list for Windows Live Messenger</em></p>
<p>In this article, I would like to dig into the following notable new features:</p>
<ul>
<li>Customizable preview </li><li>Icon overlays </li><li>Progress indication </li><li>Toolbar buttons </li></ul>
<p>None of these features are very difficult to use due to the <a href="http://code.msdn.microsoft.com/WindowsAPICodePack" target="_blank">
Windows API Code Pack</a>.&nbsp; This download is a free (but unsupported) package from Microsoft on the
<a href="http://code.msdn.microsoft.com" target="_blank">MSDN Code Gallery</a>.&nbsp; Version 1.0 was released on August 6, after a number of earlier pre-releases.&nbsp; Since many of the new features are specific to Windows 7, they are not in the .NET Base Class Libraries.&nbsp;
 This package exposes them for .NET so you don't have to do any of your own interop.</p>
<p>This sample is written for Windows Forms, but it works equally well with WPF.&nbsp; These four features are easy to integrate into any application that you write.</p>
<h3>Customizable Previews</h3>
<p>To start with, we'll dig into customizable previews.&nbsp; This refers to the ability to change the Aero Peek preview that shows up in the task bar when you hover over a minimized application.&nbsp;
</p>
<p align="center"><img title="Aero Peek preview for Windows Live Writer" border="0" alt="Aero Peek preview for Windows Live Writer" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image4_1.png" width="310" height="260"><em>
</em></p>
<p align="center"><em>Image 2: Aero Peek preview for Windows Live Writer</em></p>
<p>If you create any basic application and launch it (F5), the taskbar preview will be an exact copy of the application's main window.&nbsp; In fact, Windows gets this from the DWM, or Desktop Window Manager.&nbsp; This is cached already so it makes sense to use it here.&nbsp;
 Overriding it though is fairly easy.&nbsp; In a photo editing application, it might be better to have the preview show the current image by itself -- without all of the toolbars and menus.&nbsp; You can also choose to take the cached thumbnail from the DWM and just
 crop a portion of it - like to remove a ribbon UI from the top.</p>
<p>The <strong>TaskbarManager </strong>class is responsible for exposing progress state, thumbnail, overlay icons, and other similar properties.&nbsp; These functions would otherwise be scattered across various Win32 API calls, but the Windows API Code Pack simplifies
 this immensely.&nbsp; The first step is to create a reference to it and obtain the static reference:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> windowsTaskbar <span class="kwrd">As</span> TaskbarManager = TaskbarManager.Instance</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> TaskbarManager windowsTaskbar = TaskbarManager.Instance;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p>You'll use this reference throughout your application for any taskbar manipulation.&nbsp; In order to clip your preview, just specify the window handle and the region.&nbsp; An easy way is to specify the
<strong>Location</strong> and <strong>Size </strong>properties of a control.&nbsp; In this sample, it's a
<strong>GroupBox</strong>, but in another application it might make more sense to clip to a
<strong>PictureBox</strong> or other control:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.TabbedThumbnail.SetThumbnailClip(<span class="kwrd">Me</span>.Handle, <span class="kwrd">New</span> Rectangle(groupBox2.Location, groupBox2.Size))</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.TabbedThumbnail.SetThumbnailClip(<span class="kwrd">this</span>.Handle, <span class="kwrd">new</span> Rectangle(groupBox2.Location, groupBox2.Size));</pre>
<p>&nbsp;</p>
<h3>Icon Overlays</h3>
<p>Icon overlays allow you to display a visual representation of your program's state.&nbsp; This has been possible for some time using icons in the notification area (battery level low, anti-virus disabled), but until now it hasn't been possible as part of your
 taskbar icon.&nbsp; Now you can choose any icon (from an ICO file or extracted from an executable or DLL) and the taskbar manager will display it directly in the task bar overlaid on your application icon.&nbsp; This is used in Windows Live Messenger to show your login
 status (offline, busy, available, etc.):</p>
<p align="center"><img title="Windows Live Messenger with overlay for offline status" border="0" alt="Windows Live Messenger with overlay for offline status" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image7_1.png" width="60" height="39"><em>
</em></p>
<p align="center"><em>Image 3: Windows Live Messenger with overlay for offline status</em></p>
<p>This is great for providing information at a glance.&nbsp; Especially as more and more users are hiding their cluttered notification tray icons and wouldn't see the indicator otherwise.</p>
<p>The beautiful thing is that the <strong>TaskbarManager </strong>class allows you to set this with one line of code:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.SetOverlayIcon(<span class="kwrd">me</span>.Handle, My.Resources.Green, <span class="str">&quot;Green&quot;</span>)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.SetOverlayIcon(<span class="kwrd">this</span>.Handle, TaskbarDemo.Properties.Resources.Green, <span class="str">&quot;Green&quot;</span>);</pre>
<p>&nbsp;</p>
<p>The same API call can also lets you clear an overlay:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.SetOverlayIcon(<span class="kwrd">Me</span>.Handle, <span class="kwrd">Nothing</span>, <span class="kwrd">Nothing</span>)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.SetOverlayIcon(<span class="kwrd">this</span>.Handle, <span class="kwrd">null</span>, <span class="kwrd">null</span>);</pre>
<h3>&nbsp;</h3>
<h3>Progress Indication</h3>
<p>As your application works through something, such as file copying, downloading, or processing a data set, you might be tempted to display a progress bar in a popup dialog.&nbsp; If you're really diabolical you might even make this a modal dialog!&nbsp; In our brave
 new world of Windows 7 though, we no longer need to subject our users to this.&nbsp; Instead of cluttering up the screen, we can reflect the current progress of any single operation by displaying a progress bar behind our application icon, such as Windows Explorer
 during a file copy:</p>
<p align="center"><img title="Windows Explorer with file copy progress indication" border="0" alt="Windows Explorer with file copy progress indication" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image10.png" width="58" height="40"><em>
</em></p>
<p align="center"><em>Image 4: Windows Explorer with file copy progress indication</em></p>
<p>It's faint, but you should be able to see the bar at around the 15-20% point behind the folder.&nbsp; There are actually a number of states that you can instruct the taskbar to display, then you just provide progress value updates as needed.</p>
<p>In this sample application, we display the various <strong>TaskbarProgressBarState
</strong>enumerated values in a ComboBox:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">comboBoxProgressState.DataSource = System.<span class="kwrd">Enum</span>.GetNames(<span class="kwrd">GetType</span>(TaskbarProgressBarState))</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">comboBoxProgressState.DataSource = Enum.GetNames(<span class="kwrd">typeof</span>(TaskbarProgressBarState));</pre>
<p>&nbsp;</p>
<p>When changes are made, we update the state using the <strong>SetProgressState </strong>
call:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.SetProgressState(<span class="kwrd">CType</span>(System.<span class="kwrd">Enum</span>.Parse(<span class="kwrd">GetType</span>(TaskbarProgressBarState), comboBoxProgressState.Text), TaskbarProgressBarState))</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.SetProgressState((TaskbarProgressBarState)Enum.Parse(<span class="kwrd">typeof</span>(TaskbarProgressBarState), comboBoxProgressState.Text));</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p>Then, we use a TrackerBar to select the current value which gets posted using the
<strong>SetProgressState </strong>call:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.SetProgressValue(trackProgress.Value, 100)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.SetProgressValue(trackProgress.Value, 100);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3>&nbsp;</h3>
<h3>Toolbar Buttons</h3>
<p>One of the new features that really has me excited is the ability to add buttons to the preview image.&nbsp; This is a very underutilized feature so far, though it's visible in Windows Media Player:</p>
<p align="center"><img title="Windows Media Player preview with toolbar buttons for media control" border="0" alt="Windows Media Player preview with toolbar buttons for media control" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9874533/image13_1.png" width="260" height="248"><em>
</em></p>
<p align="center"><em>Image 5: Windows Media Player preview with toolbar buttons for media control</em></p>
<p>Notice the Pause, Previous, and Next buttons under the Aero Peek.&nbsp; Those are fully-functional.&nbsp; The great thing is that you can add them to your application easily, and bind event handlers to them like any other buttons.&nbsp; You don't get design-time support
 like for forms and menus, but you really don't need it.</p>
<p>Start by decaring a <strong>ThumbnailToolbarButton:</strong></p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">WithEvents</span> buttonFirst <span class="kwrd">As</span> ThumbnailToolbarButton</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> ThumbnailToolbarButton buttonFirst; </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p>You can set the image, a label (shown on hover), enabled or not, and other common Button properties.&nbsp; Here I will create the button and point it to an image stored as a resource, and a label:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">buttonFirst = <span class="kwrd">New</span> ThumbnailToolbarButton(My.Resources.search, <span class="str">&quot;Search&quot;</span>)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">buttonFirst = <span class="kwrd">new</span> ThumbnailToolbarButton(Properties.Resources.first, <span class="str">&quot;First Image&quot;</span>);</pre>
<p>&nbsp;</p>
<p>Next, I need to attach an event handler to it.&nbsp; In Visual Basic, since <strong>
buttonFirst </strong>was declared using <strong>WithEvents</strong>, you can use the
<strong>Handles </strong>keyword in the declaration of the event handler.&nbsp; In C#, you can type &quot;buttonFirst.Click &#43;=&quot; and then press the TAB key twice.&nbsp; This will fill out the rest of the line *and* create an event handler stub:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> buttonFirst_Click(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> ThumbnailButtonClickedEventArgs) <span class="kwrd">Handles</span> buttonFirst.Click</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">buttonFirst.Click &#43;= <span class="kwrd">new</span> EventHandler&lt;ThumbnailButtonClickedEventArgs&gt;(buttonFirst_Click); </pre>
<p>&nbsp;</p>
<p>Finally, add the buttons using the <strong>TaskbarManager </strong>instance.&nbsp; The
<strong>AddButtons </strong>call takes a list of parameters, so you can just add other buttons by separating them with commas:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">windowsTaskbar.ThumbnailToolbars.AddButtons(<span class="kwrd">Me</span>.Handle, buttonFirst)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">windowsTaskbar.ThumbnailToolbars.AddButtons(<span class="kwrd">this</span>.Handle, buttonFirst);</pre>
<p>&nbsp;</p>
<p>Just fill in something for your event handler to do (a simple MessageBox in the sample application), and you're done!&nbsp; It's super-easy and it adds a new dimension of interactivity with your application.&nbsp; This could replace menu commands in a notification
 icon, or simply present common actions.&nbsp; It doesn't make sense in every application, but it's easy to add when you need it.</p>
<h3>Next Steps</h3>
<p>The next step is to evaluate your own applications to see what makes to add.&nbsp; While custom previews and toolbar buttons don't make sense for every application, progress indication and custom overlays can often be a good fit.&nbsp; Of course, remember that if
 you implement any of this, it won't be visible in Windows Vista or earlier.&nbsp; Be sure to have a secondary way to access these same functions.&nbsp; Toolbar buttons and overlays can be accomplished in the notification icon, and progress can always be displayed in
 a popup dialog as a fallback.</p>
<h3>Conclusion</h3>
<p>Windows 7 makes it easier to create very user-friendly applications.&nbsp; You may be able to augment existing applications to take advantage of these features, or at least keep them in mind when designing new applications.&nbsp; Pretty quickly, these will be considered
 common place and you'll want your application to play well on the desktop.</p>
<p>If you haven't yet, download <a href="http://www.microsoft.com/express/" target="_blank">
Visual Studio 2008 Express Edition</a> (Visual Basic or Visual C#), and then download the
<a href="http://code.msdn.microsoft.com/WindowsAPICodePack" target="_blank">Windows API Code Pack</a> so you can get started!&nbsp; Of course you'll need at least the Windows 7 RC build in order to actually test any of this, but the final release is in just a few
 months.&nbsp; Get ready for it now!</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:b648d582de3d4b988d629e7600cb80d1">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Coding-4-Fun-Windows-7-Taskbar</comments>
      <itunes:summary>
Looking to take advantage of some new Windows 7 goodness?&amp;nbsp; Learn how to work
 with some of the great new taskbar features to create a more streamlined user interface. 
Introduction
Windows 7 brings with it a large number of new features that will be available to developers from day one.&amp;nbsp; These are really nice additions that will make applications more natural to work with.&amp;nbsp; One of the new areas of enhancements is the taskbar.&amp;nbsp; The
 taskbar has always been a pretty simple way to see what&#39;s running and switch between tasks.&amp;nbsp; Moving from XP to Vista, we got cool previews, but that&#39;s about it.&amp;nbsp; With Windows 7, now we can drag-and-drop minimized app icons to change their order, we can pin
 apps there even if they aren&#39;t running (replacing Quick Launch functionality).&amp;nbsp; You can also right-click the icons to restore or close the window.&amp;nbsp; Better still, many apps give you additional information upon right-click, such as Recent lists, or actions like
 changing your Live Messenger status: 

 
Image 1: Jump list for Windows Live Messenger 
In this article, I would like to dig into the following notable new features: 

Customizable preview Icon overlays Progress indication Toolbar buttons 
None of these features are very difficult to use due to the 
Windows API Code Pack.&amp;nbsp; This download is a free (but unsupported) package from Microsoft on the
MSDN Code Gallery.&amp;nbsp; Version 1.0 was released on August 6, after a number of earlier pre-releases.&amp;nbsp; Since many of the new features are specific to Windows 7, they are not in the .NET Base Class Libraries.&amp;nbsp;
 This package exposes them for .NET so you don&#39;t have to do any of your own interop. 
This sample is written for Windows Forms, but it works equally well with WPF.&amp;nbsp; These four features are easy to integrate into any application that you write. 
Customizable Previews
To start with, we&#39;ll dig into customizable previews.&amp;nbsp; This refers to the ability to change the Aero Peek </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Coding-4-Fun-Windows-7-Taskbar</link>
      <pubDate>Tue, 25 Aug 2009 13:47:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Coding-4-Fun-Windows-7-Taskbar</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9874533_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9874533_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>ArianKulp</dc:creator>
      <itunes:author>ArianKulp</itunes:author>
      <slash:comments>25</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Coding-4-Fun-Windows-7-Taskbar/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Windows 7</category>
    </item>
  <item>
      <title>Expose your Windows with Switcher</title>
      <description><![CDATA[If you've ever seen Expose on the Mac and wanted something similar for your PC, check out <a shape="rect" href="http://insentient.net/Index.html" shape="rect">Switcher</a>. This application for Vista &#43; Aero allows you to instantly see all your current windows as a dock, grid, or tile by pressing &quot;Win&#43;`&quot; and jump to any one of them with a keypress. (I've been using it all morning on Win7 with no problems, btw.)&nbsp;You can also find your application by just starting to type the name of it. There are plenty of customization options and works across multiple monitors. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:bd2cb05d11d54819bacb9e1000fc7e4f">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/Expose-your-Windows-with-Switcher</comments>
      <itunes:summary>If you&#39;ve ever seen Expose on the Mac and wanted something similar for your PC, check out Switcher. This application for Vista &amp;#43; Aero allows you to instantly see all your current windows as a dock, grid, or tile by pressing &amp;quot;Win&amp;#43;`&amp;quot; and jump to any one of them with a keypress. (I&#39;ve been using it all morning on Win7 with no problems, btw.)&amp;nbsp;You can also find your application by just starting to type the name of it. There are plenty of customization options and works across multiple monitors.</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/Expose-your-Windows-with-Switcher</link>
      <pubDate>Mon, 27 Apr 2009 14:10:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/Expose-your-Windows-with-Switcher</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_7cb289c2-46cb-4c4d-a541-0856a0282fc8.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/on10_25718_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/on10_25718_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_3787ef44-35c8-4ccd-a977-713fca63ff26.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/Expose-your-Windows-with-Switcher/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Utilities</category>
      <category>utility</category>
      <category>Desktop Application</category>
    </item>
  <item>
      <title>TwitterDrive – Author Interview</title>
      <description><![CDATA[<p><img title="tDrive" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/tDrive_3.jpg" alt="tDrive" width="79" height="45" align="left" border="0"> In case you haven't heard, <a href="http://www.brianpeek.com/media/p/3413.aspx">TwitterDrive</a> is going to revolutionize the way files are stored and shared on the Internet.&nbsp; Today, we had the rare privilege of sitting down and talking with <a href="http://www.brianpeek.com/">Brian Peek</a>, creator of this cutting edge product.</p><p><strong>Q: Thanks for taking the time to speak with us today.&nbsp; Why don't you tell us a little bit about yourself?</strong></p><p>A: I'm surprised I even considered this.&nbsp; I'm so above you people now.&nbsp; But anyway, my name is Brian Peek, and until I developed this app, I was working, like you people, at a job that was pointless.&nbsp; Now, I'm on the cusp of owning people like you.&nbsp; Once this takes off, I can finally pursue my life's other passion:&nbsp; hip-hop music.</p><p><strong><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/30872-480-360_2.png"><img title="30872-480-360" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/30872-480-360_thumb.png" alt="30872-480-360" width="364" height="274" align="left" border="0"></a> Q: I don't doubt it.&nbsp; So why don't you tell us a little bit about TwitterDrive and how you came up with the idea?</strong></p><p>A: TwitterDrive is the next “big thing” in cloud storage.&nbsp; There are a ton of cloud storage providers out there now, most of which cost money or have limited disk space available.&nbsp; But why should we live with limitations like these?&nbsp; Twitter provides their users with unlimited storage for sending and saving their “tweets”.&nbsp; My amazingly brilliant idea was to take this service to the next level:&nbsp; using it to store and share files.&nbsp; That is, free cloud storage.&nbsp; Bet you wish you thought of that.</p><p><strong><strong><img title="shatner" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/shatner_3.png" alt="shatner" width="185" height="250" align="left" border="0"></strong>Q: I sure do.&nbsp; So how does TwitterDrive work? </strong></p><p>A: It works perfectly.&nbsp; Simply run the TwitterDrive application, provide your Twitter user credentials, and then start uploading and downloading files.&nbsp; Files are compressed, base64 encoded, and then uploaded to Twitter 140 bytes at a time, fully maximizing the amount of space allowed per tweet.</p><p>Imagine…uploading 14 thousand bytes of data per hour!&nbsp; Or downloading two megabytes per hour!&nbsp; Match that, SkyDrive.</p><p><strong>Q: That sounds amazing.&nbsp; Unlimited storage for free.</strong></p><p>It is amazing.&nbsp; Which is why I thought of it and you didn't.&nbsp; Welcome to the future.</p><p><strong>Q: So are there any limitations?</strong></p><p>Only if you consider uploading 14 thousand <a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/mp_main_wide_EarlyComputerMarketing_2.png"><img title="mp_main_wide_EarlyComputerMarketing" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525555/mp_main_wide_EarlyComputerMarketing_thumb.png" alt="mp_main_wide_EarlyComputerMarketing" width="364" height="282" align="right" border="0"></a>bytes per hour a limitation.&nbsp; But really, who has that much data?&nbsp; 14k should be enough for everybody.</p><p><strong>Q: What about data protection?&nbsp; Is the file data protected in any way?</strong></p><p>The data is compressed, encoded and chunked up into bits.&nbsp; Who needs more security than that?&nbsp; Besides, users would need to know your TwitterDrive account username to get at the data.&nbsp; Security through obscurity is a win for everyone!</p><p><strong>Q: Do you have any new features planned for TwitterDrive?</strong></p><p>New features?&nbsp; No.&nbsp; It's already the most complete, useful and bug free application ever developed.&nbsp; It doesn't require any additional features.</p><p>Now if you'll excuse me, I have to start planning which jet I want to buy.</p><p><strong>Well there you have it, folks.&nbsp; We are at the cusp of a revolution.&nbsp; Are you ready?</strong></p><p><a href="http://www.brianpeek.com/media/p/3413.aspx">Download TwitterDrive here</a>.&nbsp; Want to learn more?&nbsp; Learn <a href="http://blogs.msdn.com/coding4fun/archive/2009/04/01/9525376.aspx">how it was made</a>!</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e52421f86d2e4408974b9e7600ccd94c">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/TwitterDrive--Author-Interview</comments>
      <itunes:summary> In case you haven&#39;t heard, TwitterDrive is going to revolutionize the way files are stored and shared on the Internet.&amp;nbsp; Today, we had the rare privilege of sitting down and talking with Brian Peek, creator of this cutting edge product. Q: Thanks for taking the time to speak with us today.&amp;nbsp; Why don&#39;t you tell us a little bit about yourself? A: I&#39;m surprised I even considered this.&amp;nbsp; I&#39;m so above you people now.&amp;nbsp; But anyway, my name is Brian Peek, and until I developed this app, I was working, like you people, at a job that was pointless.&amp;nbsp; Now, I&#39;m on the cusp of owning people like you.&amp;nbsp; Once this takes off, I can finally pursue my life&#39;s other passion:&amp;nbsp; hip-hop music.  Q: I don&#39;t doubt it.&amp;nbsp; So why don&#39;t you tell us a little bit about TwitterDrive and how you came up with the idea? A: TwitterDrive is the next “big thing” in cloud storage.&amp;nbsp; There are a ton of cloud storage providers out there now, most of which cost money or have limited disk space available.&amp;nbsp; But why should we live with limitations like these?&amp;nbsp; Twitter provides their users with unlimited storage for sending and saving their “tweets”.&amp;nbsp; My amazingly brilliant idea was to take this service to the next level:&amp;nbsp; using it to store and share files.&amp;nbsp; That is, free cloud storage.&amp;nbsp; Bet you wish you thought of that. Q: I sure do.&amp;nbsp; So how does TwitterDrive work?  A: It works perfectly.&amp;nbsp; Simply run the TwitterDrive application, provide your Twitter user credentials, and then start uploading and downloading files.&amp;nbsp; Files are compressed, base64 encoded, and then uploaded to Twitter 140 bytes at a time, fully maximizing the amount of space allowed per tweet. Imagine…uploading 14 thousand bytes of data per hour!&amp;nbsp; Or downloading two megabytes per hour!&amp;nbsp; Match that, SkyDrive. Q: That sounds amazing.&amp;nbsp; Unlimited storage for free. It is amazing.&amp;nbsp; Which is why I thought of it and you didn&#39;t.&amp;nbsp; Welcome to the futu</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/TwitterDrive--Author-Interview</link>
      <pubDate>Wed, 01 Apr 2009 04:10:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/TwitterDrive--Author-Interview</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9525555_100.jpg" height="76" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9525555_220.jpg" height="166" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>9</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/TwitterDrive--Author-Interview/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Web</category>
      <category>Windows</category>
      <category>Holiday</category>
      <category>april fools day</category>
    </item>
  <item>
      <title>TwitterDrive – The Revolution in Cloud Storage</title>
      <description><![CDATA[
<table border="0" cellspacing="0" cellpadding="1" width="100%">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;<img title="tDrive" border="0" alt="tDrive" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525376/tDrive_3.jpg" width="75" height="41">
</td>
<td><span class="entry_description">In this article, Brian Peek will provide a technical overview of TwitterDrive, an application used to store and retrieve files via the Twitter messaging service.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author"><a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a></div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> 2<span class="entry_details_input">-3 hours</span></div>
<div class="entry_details"><b>Cost: </b>Free</div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual C# Express 2008 SP1, Visual Basic Express 2008 SP1, or Visual Studio 2008 SP1, .NET Framework 3.5 SP1</a></span></div>
<div class="entry_details"><b>Hardware: </b>None</div>
<div class="entry_details"><b>Download: </b><a href="http://www.brianpeek.com/media/p/3413.aspx" target="_blank">Application</a>,
<a href="http://www.brianpeek.com/media/p/3414.aspx" target="_blank">Source Code</a></div>
<div class="entry_details"><b>Discussion Forum: </b><a href="http://www.brianpeek.com/forums/44.aspx" target="_blank">Forum</a></div>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h3>Introduction</h3>
<p>As you've probably guessed by now, <b>TwitterDrive</b> is my April Fool's Day application for Coding4Fun this year.&nbsp; While the application does actually work, the limitations of Twitter make it functionally useless.&nbsp; That said, I'll still take you through
 the important parts as there is some value in the code with regard to the Twitter API, LINQ to XML, threading, and a couple other things.</p>
<h4>How It Works</h4>
<p>Not very well, actually.&nbsp; The concept is we take a file, compress it, uuencode/base64 encode it (that is, make a text representation of the binary contents), and then upload it 140 characters at a time to Twitter as status messages.&nbsp; When the file upload
 is complete, an index is written of every file that is currently stored on Twitter with some information that can be used to later retrieve the file.</p>
<h4>Twitter</h4>
<p>Let's start with the Twitter API.&nbsp; Full documentation on this API can be found at:</p>
<p><a title="http://apiwiki.twitter.com/" href="http://apiwiki.twitter.com/">http://apiwiki.twitter.com/</a></p>
<p>TwitterDrive only requires a very small subset of this functionality to work.&nbsp; We need the ability to post a new status message, download a user timeline, destroy a status, and verify the user's credentials.&nbsp; All of these things are handled in the
<b>TwitterService</b> class.</p>
<p>The heart of this class consists of two methods:&nbsp; <b>GetTwitter </b>and <b>PostTwitter</b>.&nbsp;
<b>GetTwitter</b> will make a GET request to Twitter of the specified URL, and <b>
PostTwitter</b> will make a POST request to Twitter of the specified URL with the supplied data.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> XDocument GetTwitter(<span>string</span> url)<br>{<br>    WebClient wc = <span>new</span> WebClient();<br><br>    <span>// only authenticate if we have a password</span><br>    <span>if</span>(!<span>string</span>.IsNullOrEmpty(Password))<br>        wc.Credentials = <span>new</span> NetworkCredential(Username, Password);<br><br>    Stream s = wc.OpenRead(url);<br><br>    <span>// return an XDocument for LINQ</span><br>    XmlTextReader xmlReader = <span>new</span> XmlTextReader(s);<br>    XDocument xdoc = XDocument.Load(xmlReader);<br>    xmlReader.Close();<br>    <span>return</span> xdoc;<br>}<br><br><span>private</span> XDocument PostTwitter(<span>string</span> url, <span>string</span> data)<br>{<br>    <span>byte</span>[] bytes = Encoding.ASCII.GetBytes(data);<br><br>    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);<br>    request.Method = <span>&quot;POST&quot;</span>;<br><br>    <span>// if we're writing, we need to authenticate</span><br>    request.Credentials = <span>new</span> NetworkCredential(Username, Password);<br><br>    <span>// if this is 'true', Twitter breaks</span><br>    request.ServicePoint.Expect100Continue = <span>false</span>;<br>    request.ContentType = <span>&quot;application/x-www-form-urlencoded&quot;</span>;<br>    request.ContentLength = bytes.Length;<br><br>    Stream reqStream = request.GetRequestStream();<br>    reqStream.Write(bytes, 0, bytes.Length);<br><br>    <span>// turn the response into an XDocument for use with LINQ</span><br>    HttpWebResponse resp = (HttpWebResponse)request.GetResponse();<br>    XmlReader xmlReader = XmlReader.Create(resp.GetResponseStream());<br>    XDocument xdoc = XDocument.Load(xmlReader);<br>    xmlReader.Close();<br>    <span>return</span> xdoc;<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Function</span> GetTwitter(<span>ByVal</span> url <span>As</span> <span>String</span>) <span>As</span> XDocument<br>    <span>Dim</span> wc <span>As</span> <span>New</span> WebClient()<br><br>    <span>' only authenticate if we have a password</span><br>    <span>If</span> (<span>Not</span> <span>String</span>.IsNullOrEmpty(Password)) <span>Then</span><br>        wc.Credentials = <span>New</span> NetworkCredential(Username, Password)<br>    <span>End</span> <span>If</span><br><br>    <span>Dim</span> s <span>As</span> Stream = wc.OpenRead(url)<br><br>    <span>' return an XDocument for LINQ</span><br>    <span>Dim</span> xmlReader <span>As</span> <span>New</span> XmlTextReader(s)<br>    <span>Dim</span> xdoc <span>As</span> XDocument = XDocument.Load(xmlReader)<br>    xmlReader.Close()<br>    <span>Return</span> xdoc<br><span>End</span> <span>Function</span><br><br><span>Private</span> <span>Function</span> PostTwitter(<span>ByVal</span> url <span>As</span> <span>String</span>, <span>ByVal</span> data <span>As</span> <span>String</span>) <span>As</span> XDocument<br>    <span>Dim</span> bytes() <span>As</span> <span>Byte</span> = Encoding.ASCII.GetBytes(data)<br><br>    <span>Dim</span> request <span>As</span> HttpWebRequest = <span>CType</span>(WebRequest.Create(url), HttpWebRequest)<br>    request.Method = <span>&quot;POST&quot;</span><br><br>    <span>' if we're writing, we need to authenticate</span><br>    request.Credentials = <span>New</span> NetworkCredential(Username, Password)<br><br>    <span>' if this is 'true', Twitter breaks</span><br>    request.ServicePoint.Expect100Continue = <span>False</span><br>    request.ContentType = <span>&quot;application/x-www-form-urlencoded&quot;</span><br>    request.ContentLength = bytes.Length<br><br>    <span>Dim</span> reqStream <span>As</span> Stream = request.GetRequestStream()<br>    reqStream.Write(bytes, 0, bytes.Length)<br><br>    <span>' turn the response into an XDocument for use with LINQ</span><br>    <span>Dim</span> resp <span>As</span> HttpWebResponse = <span>CType</span>(request.GetResponse(), HttpWebResponse)<br>    <span>Dim</span> xmlReader <span>As</span> XmlReader = XmlReader.Create(resp.GetResponseStream())<br>    <span>Dim</span> xdoc <span>As</span> XDocument = XDocument.Load(xmlReader)<br>    xmlReader.Close()<br>    <span>Return</span> xdoc<br><span>End</span> Function</pre>
<br>
</div>
<p>Each of these methods will use the <b>NetworkCredentials</b> object to authenticate to Twitter for reading or writing, as required.&nbsp; Twitter API methods return simple XML objects.&nbsp; Both
<b>GetTwitter</b> and <b>PostTwitter</b> take these XML documents and turn them into
<b>XDocument</b> objects that can be easily queried with LINQ to XML later.</p>
<p>We only need to call two Twitter “get” methods: <b>user_timeline </b>and <b>verify_credentials</b>.&nbsp; There are two overloaded methods which call the
<b>user_timeline</b> API:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> IList&lt;Status&gt; GetUserTimeline(<span>int</span> page, <span>int</span> count)<br>{<br>    XDocument xdoc = GetTwitter(<span>string</span>.Format(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?count=" href="http://twitter.com/statuses/user_timeline.xml?count=">http://twitter.com/statuses/user_timeline.xml?count=</a>{0}&amp;page={1}&amp;id={2}&quot;</span>, count, page, Username));<br>    IList&lt;Status&gt; statuses = ParseStatuses(xdoc);<br>    <span>return</span> statuses;<br>}<br><br><span>public</span> IList&lt;Status&gt; GetUserTimeline(<span>int</span> since_id, <span>int</span> max_id, <span>int</span> page, <span>int</span> count)<br>{<br>    XDocument xdoc = GetTwitter(<span>string</span>.Format(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?since_id=" href="http://twitter.com/statuses/user_timeline.xml?since_id=">http://twitter.com/statuses/user_timeline.xml?since_id=</a>{0}&amp;max_id={1}&amp;count={2}&amp;page={3}&amp;id={4}&quot;</span>, since_id, max_id, count, page, Username));<br>    IList&lt;Status&gt; statuses = ParseStatuses(xdoc);<br>    <span>return</span> statuses;<br>}</pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> GetUserTimeline(<span>ByVal</span> page <span>As</span> <span>Integer</span>, <span>ByVal</span> count <span>As</span> <span>Integer</span>) <span>As</span> IList(Of Status)<br>    <span>Dim</span> xdoc <span>As</span> XDocument = GetTwitter(<span>String</span>.Format(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?count=" href="http://twitter.com/statuses/user_timeline.xml?count=">http://twitter.com/statuses/user_timeline.xml?count=</a>{0}&amp;page={1}&amp;id={2}&quot;</span>, count, page, Username))<br>    <span>Dim</span> statuses <span>As</span> IList(Of Status) = ParseStatuses(xdoc)<br>    <span>Return</span> statuses<br><span>End</span> <span>Function</span><br><br><span>Public</span> <span>Function</span> GetUserTimeline(<span>ByVal</span> since_id <span>As</span> <span>Integer</span>, <span>ByVal</span> max_id <span>As</span> <span>Integer</span>, <span>ByVal</span> page <span>As</span> <span>Integer</span>, <span>ByVal</span> count <span>As</span> <span>Integer</span>) <span>As</span> IList(Of Status)<br>    <span>Dim</span> xdoc <span>As</span> XDocument = GetTwitter(<span>String</span>.Format(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?since_id=" href="http://twitter.com/statuses/user_timeline.xml?since_id=">http://twitter.com/statuses/user_timeline.xml?since_id=</a>{0}&amp;max_id={1}&amp;count={2}&amp;page={3}&amp;id={4}&quot;</span>, since_id, max_id, count, page, Username))<br>    <span>Dim</span> statuses <span>As</span> IList(Of Status) = ParseStatuses(xdoc)<br>    <span>Return</span> statuses<br><span>End</span> Function</pre>
<br>
</div>
<p>Each of these methods creates a URL with the appropriate query string arguments (see the Twitter API docs for the full list) and then calls our ParseStatuses method with the returned XDocument, which will give us a List of Status objects. The Twitter-returned
 status contains a variety of data, such as:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>status</span><span>&gt;</span><br><span>&lt;</span><span>created_at</span><span>&gt;</span>Mon Mar 30 07:20:57 &#43;0000 2009<span>&lt;/</span><span>created_at</span><span>&gt;</span><br><span>&lt;</span><span>id</span><span>&gt;</span>1234567123<span>&lt;/</span><span>id</span><span>&gt;</span><br><span>&lt;</span><span>text</span><span>&gt;</span>Status text<span>&lt;/</span><span>text</span><span>&gt;</span><br><span>&lt;</span><span>source</span><span>&gt;</span>web<span>&lt;/</span><span>source</span><span>&gt;</span><br><span>&lt;</span><span>truncated</span><span>&gt;</span>false<span>&lt;/</span><span>truncated</span><span>&gt;</span><br><span>&lt;</span><span>in_reply_to_status_id</span><span>/&gt;</span><br><span>&lt;</span><span>in_reply_to_user_id</span><span>/&gt;</span><br><span>&lt;</span><span>favorited</span><span>&gt;</span>false<span>&lt;/</span><span>favorited</span><span>&gt;</span><br><br><span>&lt;</span><span>user</span><span>&gt;</span><br><span>&lt;</span><span>id</span><span>&gt;</span>12345678<span>&lt;/</span><span>id</span><span>&gt;</span><br><span>&lt;</span><span>name</span><span>&gt;</span>Some Person<span>&lt;/</span><span>name</span><span>&gt;</span><br><span>&lt;</span><span>screen_name</span><span>&gt;</span>myscreenname<span>&lt;/</span><span>screen_name</span><span>&gt;</span><br><span>&lt;</span><span>description</span><span>/&gt;</span><br><span>&lt;</span><span>location</span><span>/&gt;</span><br><br><span>&lt;</span><span>profile_image_url</span><span>&gt;</span><br><a class="linkification-ext" title="Linkification: http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525376/default_profile_normal.png" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525376/default_profile_normal.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525376/default_profile_normal.png</a><br><span>&lt;/</span><span>profile_image_url</span><span>&gt;</span><br><span>&lt;</span><span>url</span><span>/&gt;</span><br><span>&lt;</span><span>protected</span><span>&gt;</span>false<span>&lt;/</span><span>protected</span><span>&gt;</span><br><span>&lt;</span><span>followers_count</span><span>&gt;</span>1<span>&lt;/</span><span>followers_count</span><span>&gt;</span><br><span>&lt;/</span><span>user</span><span>&gt;</span><br><span>&lt;/</span><span>status</span><span>&gt;</span></pre>
<br>
</div>
<p>We only care about a few elements and only parse those, namely id, text, user (which is in itself an XML chunk), and created_at.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> IList&lt;Status&gt; ParseStatuses(XContainer container)<br>{<br>    <span>// return a list of Status objects</span><br>    var query = from status <span>in</span> container.Descendants(<span>&quot;statuses&quot;</span>).Descendants(<span>&quot;status&quot;</span>)<br>                select ParseStatus(status);<br>    <span>return</span> query.ToList();<br>}<br><br><span>private</span> Status ParseStatus(XDocument xdoc)<br>{<br>    <span>// create a Status object from the returned XML</span><br>    var query = from status <span>in</span> xdoc.Descendants(<span>&quot;status&quot;</span>)<br>                select ParseStatus(status);<br><br>    <span>return</span> query.SingleOrDefault();<br>}<br><br><span>private</span> Status ParseStatus(XElement xelement)<br>{<br>    Status s = <span>new</span> Status()<br>                {<br>                    ID = (<span>int</span>)xelement.Element(<span>&quot;id&quot;</span>),<br>                    Text = (<span>string</span>)xelement.Element(<span>&quot;text&quot;</span>),<br>                    UserInformation = ParseUserInformation(xelement.Element(<span>&quot;user&quot;</span>)),<br>                    <span>// HTTP-formatted date</span><br>                    CreatedAt = DateTime.ParseExact(xelement.Element(<span>&quot;created_at&quot;</span>).Value,<br>                            <span>&quot;ddd MMM dd HH:mm:ss zzzz yyyy&quot;</span>,<br>                            CultureInfo.GetCultureInfoByIetfLanguageTag(<span>&quot;en-us&quot;</span>),<br>                            DateTimeStyles.AllowWhiteSpaces)<br>                };<br><br>    <span>return</span> s;<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Function</span> ParseStatuses(<span>ByVal</span> container <span>As</span> XContainer) <span>As</span> IList(Of Status)<br>    <span>' return a list of Status objects</span><br>    <span>Dim</span> query = _<br>        From status <span>In</span> container.Descendants(<span>&quot;statuses&quot;</span>).Descendants(<span>&quot;status&quot;</span>) _<br>        <span>Select</span> ParseStatus(status)<br>    <span>Return</span> query.ToList()<br><span>End</span> <span>Function</span><br><br><span>Private</span> <span>Function</span> ParseStatus(<span>ByVal</span> xdoc <span>As</span> XDocument) <span>As</span> Status<br>    <span>' create a Status object from the returned XML</span><br>    <span>Dim</span> query = _<br>        From status <span>In</span> xdoc.Descendants(<span>&quot;status&quot;</span>) _<br>        <span>Select</span> ParseStatus(status)<br><br>    <span>Return</span> query.SingleOrDefault()<br><span>End</span> <span>Function</span><br><br><span>Private</span> <span>Function</span> ParseStatus(<span>ByVal</span> xelement <span>As</span> XElement) <span>As</span> Status<br>    <span>Dim</span> s <span>As</span> <span>New</span> Status() <span>With</span> { _<br>        .ID = <span>CInt</span>(xelement.Element(<span>&quot;id&quot;</span>)), _<br>        .Text = <span>CStr</span>(xelement.Element(<span>&quot;text&quot;</span>)), _<br>        .UserInformation = ParseUserInformation(xelement.Element(<span>&quot;user&quot;</span>)), _<br>        .CreatedAt = DateTime.ParseExact(xelement.Element(<span>&quot;created_at&quot;</span>).Value, _<br>                    <span>&quot;ddd MMM dd HH:mm:ss zzzz yyyy&quot;</span>, CultureInfo.GetCultureInfoByIetfLanguageTag(<span>&quot;en-us&quot;</span>), DateTimeStyles.AllowWhiteSpaces) }<br>    <span>Return</span> s<br><span>End</span> Function</pre>
<br>
</div>
<p>These methods use LINQ to XML to drill down into the XML document to parse out individual status objects and return them as a list.&nbsp; You will notice the user element contains a
<strong>user_information</strong> XML chunk, and the <b>ParseUserInformation</b> method parses that data</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> UserInformation ParseUserInformation(XContainer container)<br>{<br>    <span>// parse and return a UserInformation object</span><br>    <span>return</span> <span>new</span> UserInformation<br>    {<br>        ID = (<span>int</span>)container.Element(<span>&quot;id&quot;</span>),<br>        Name = (<span>string</span>)container.Element(<span>&quot;name&quot;</span>),<br>        ScreenName = (<span>string</span>)container.Element(<span>&quot;screen_name&quot;</span>)<br>    };<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Function</span> ParseUserInformation(<span>ByVal</span> container <span>As</span> XContainer) <span>As</span> UserInformation<br>    <span>' parse and return a UserInformation object</span><br>    <span>Dim</span> ui <span>As</span> <span>New</span> UserInformation() <span>With</span> { _<br>        .ID = <span>CInt</span>(container.Element(<span>&quot;id&quot;</span>)), _<br>        .Name = <span>CStr</span>(container.Element(<span>&quot;name&quot;</span>)), _<br>        .ScreenName = <span>CStr</span>(container.Element(<span>&quot;screen_name&quot;</span>)) }<br><br>    <span>Return</span> ui<br><span>End</span> Function</pre>
<br>
</div>
<p>The <b>verify_credentials</b> API is called in a similar manner, but in this case we will “listen” for a 401 (Unauthorized) exception and return true or false appropriately:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>bool</span> VerifyTwitterCredentials(<span>string</span> username, <span>string</span> password)<br>{<br>    <span>try</span><br>    {<br>        WebClient wc = <span>new</span> WebClient();<br>        wc.Credentials = <span>new</span> NetworkCredential(username, password);<br>        Stream s = wc.OpenRead(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/account/verify_credentials.xml" href="http://twitter.com/account/verify_credentials.xml">http://twitter.com/account/verify_credentials.xml</a>&quot;</span>);<br>        s.Close();<br>    }<br>    <span>catch</span>(WebException we)<br>    {<br>        <span>if</span>((we.Response <span>as</span> HttpWebResponse).StatusCode == HttpStatusCode.Unauthorized)<br>            <span>return</span> <span>false</span>;<br>        <span>throw</span>;<br>    }<br><br>    <span>return</span> <span>true</span>;<br>}</pre>
<br>
</div>
<p>With the “get” methods out of the way, we can write our “post” methods.&nbsp; We only need two methods here as well:&nbsp;
<b>update</b> and <b>destroy</b>.&nbsp; Update is used to write a new tweet to Twitter, and destroy is used to remove an existing tweet.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> Status UpdateStatus(<span>string</span> status)<br>{<br>    XDocument doc = PostTwitter(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/update.xml" href="http://twitter.com/statuses/update.xml">http://twitter.com/statuses/update.xml</a>&quot;</span>, <span>&quot;status=&quot;</span> &#43; status);<br>    Status s =  ParseStatus(doc);<br><br>    <span>// if we don't get the text we sent, we hit the rate limit...</span><br>    <span>if</span>(s.Text != HttpUtility.UrlDecode(status))<br>        <span>throw</span> <span>new</span> TwitterRateLimitException(<span>&quot;Twitter upload limit reached.&quot;</span>);<br>    <span>return</span> s;<br>}<br><br><span>public</span> Status Destroy(<span>int</span> status)<br>{<br>    XDocument doc = PostTwitter(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/statuses/destroy/" href="http://twitter.com/statuses/destroy/">http://twitter.com/statuses/destroy/</a>&quot;</span> &#43; status &#43; <span>&quot;.xml&quot;</span>, <span>&quot;id=&quot;</span> &#43; status);<br>    <span>return</span> ParseStatus(doc);<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> VerifyTwitterCredentials(<span>ByVal</span> username <span>As</span> <span>String</span>, <span>ByVal</span> password <span>As</span> <span>String</span>) <span>As</span> <span>Boolean</span><br>    <span>Try</span><br>        <span>Dim</span> wc <span>As</span> <span>New</span> WebClient()<br>        wc.Credentials = <span>New</span> NetworkCredential(username, password)<br>        <span>Dim</span> s <span>As</span> Stream = wc.OpenRead(<span>&quot;<a class="linkification-ext" title="Linkification: http://twitter.com/account/verify_credentials.xml" href="http://twitter.com/account/verify_credentials.xml">http://twitter.com/account/verify_credentials.xml</a>&quot;</span>)<br>        s.Close()<br>    <span>Catch</span> we <span>As</span> WebException<br>        <span>If</span> (<span>TryCast</span>(we.Response, HttpWebResponse)).StatusCode = HttpStatusCode.Unauthorized <span>Then</span><br>            <span>Return</span> <span>False</span><br>        <span>End</span> <span>If</span><br>        <span>Throw</span><br>    <span>End</span> <span>Try</span><br><br>    <span>Return</span> <span>True</span><br><span>End</span> Function</pre>
<br>
</div>
<p>The <b>UpdateStatus</b> method has a bit of code to determine whether we hit Twitter's upload rate limit.&nbsp; Twitter will limit you to about 100 tweets per hour.&nbsp; The only way to determine if you've hit the upload limit (that I found at least) is to compare
 the text from <b>status</b> element returned from the update to the text that was sent.&nbsp; If the upload limit is hit, the last valid
<b>status</b> element will be returned, and therefore the text blocks will not match.&nbsp; If this happens, we throw our own custom
<b>TwitterRateLimitException</b> up the stack for the UI to handle.</p>
<h4>TwitterDrive</h4>
<p>Now that we can talk to Twitter, the next step is to write the code that uses these methods to store and retrieve our file data.&nbsp; This code is located in the
<b>TwitterDrive</b> class.</p>
<p>One of the goals I had was to make this application thread-happy to provide a responsive UI while files are uploaded and downloaded.&nbsp; Therefore, this class sets up three events which can be hooked by the UI to receive periodic status information:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>class</span> ChunkEventArgs : EventArgs<br>{<br>    <span>public</span> Status Status;<br>    <span>public</span> <span>int</span> ChunkLength;<br>    <span>public</span> <span>int</span> Total;<br><br>    <span>public</span> ChunkEventArgs(Status status, <span>int</span> length, <span>int</span> total)<br>    {<br>        Status = status;<br>        ChunkLength = length;<br>        Total = total;<br>    }<br>}<br><br>...<br><br><span>// event handlers for async file transfer</span><br><span>public</span> <span>event</span> EventHandler&lt;ChunkEventArgs&gt; ChunkUpload;<br><span>public</span> <span>event</span> EventHandler&lt;ChunkEventArgs&gt; ChunkDownload;<br><span>public</span> <span>event</span> EventHandler&lt;EventArgs&gt; TransferComplete;<br></pre>
<br>
</div>
<p>&nbsp;</p>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Class</span> ChunkEventArgs<br>    <span>Inherits</span> EventArgs<br>    <span>Public</span> Status <span>As</span> Status<br>    <span>Public</span> ChunkLength <span>As</span> <span>Integer</span><br>    <span>Public</span> Total <span>As</span> <span>Integer</span><br><br>    <span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> status <span>As</span> Status, <span>ByVal</span> length <span>As</span> <span>Integer</span>, <span>ByVal</span> total <span>As</span> <span>Integer</span>)<br>        Status = status<br>        ChunkLength = length<br>        <span>Me</span>.Total = total<br>    <span>End</span> <span>Sub</span><br><span>End</span> Class</pre>
<br>
</div>
<p>These events will be called at the appropriate times and provide information to allow the UI to draw a progress bar and other status information.</p>
<p>The <b>UploadFile</b> method does exactly what you think: it uploads the file specified.&nbsp; The file contents are loaded into memory, compressed, base64 encoded, and finally URL encoded.&nbsp; Then, this large string is cut into 140 character chunks and sent to
 Twitter, one chunk at a time.&nbsp; After each chunk is uploaded, the <b>ChunkUpload</b> event is called.&nbsp; Finally, when all chunks are uploaded, a new
<b>FileEntry</b> object is created, added to the in-memory file index, and that index is finally written to the top of the Twitter status list.</p>
<p><b>C#</b>&nbsp;<b> </b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>void</span> UploadFile(<span>string</span> path)<br>{<br>    Status s = <span>null</span>;<br>    <span>int</span> startID = 0;<br>    <span>int</span> length = 0;<br>    <span>int</span> chunkLength = 140;<br><br>    <span>// encode the file</span><br>    <span>string</span> file = EncodeFile(path);<br><br>    <span>// upload the chunks</span><br>    <span>for</span>(<span>int</span> i = 0; i &lt; file.Length; i&#43;= chunkLength)<br>    {<br>        <span>// get the proper length (i.e. don't get full 140 if we're at the end)</span><br>        <span>string</span> chunk = file.Substring(i, Math.Min(chunkLength, file.Length-i));<br><br>        <span>// handle the case where we chopped a chunk in the middle of an encoded character</span><br>        <span>// in this case, chop off the encoded data and reset the counter</span><br>        <span>if</span>(chunk.EndsWith(<span>&quot;%2&quot;</span>))<br>        {<br>            chunk = chunk.Substring(0, chunk.Length-2);<br>            i -= 2;<br>        }<br><br>        <span>if</span>(chunk.EndsWith(<span>&quot;%&quot;</span>))<br>        {<br>            chunk = chunk.Substring(0, chunk.Length-1);<br>            i -= 1;<br>        }<br><br>        <span>try</span><br>        {<br>            <span>// upload the chunk</span><br>            s = _twitter.UpdateStatus(chunk);<br><br>            <span>// notify listeners that we uploaded</span><br>            <span>if</span>(ChunkUpload != <span>null</span>)<br>                ChunkUpload(<span>this</span>, <span>new</span> ChunkEventArgs(s, chunk.Length, file.Length));<br>        }<br>        <span>catch</span>(TwitterRateLimitException)<br>        {<br>            <span>throw</span> <span>new</span> TwitterDriveException(<span>&quot;Twitter upload limit reached.  Please try again later.&quot;</span>);<br>        }<br><br>        <span>if</span>(i == 0)<br>            startID = s.ID;<br><br>        length&#43;&#43;;<br>    }<br><br>    <span>// create a new FileEntry for this file</span><br>    FileEntry fe = <span>new</span> FileEntry()<br>    {<br>        Filename = Path.GetFileName(path),<br>        StartStatus = startID,<br>        EndStatus = s.ID,<br>        Length = length,<br>        FileIndex = GetNextIndex()<br>    };<br><br>    <span>// update the index</span><br>    UpdateFileIndex(fe);<br><br>    <span>// notify we're done</span><br>    <span>if</span>(TransferComplete != <span>null</span>)<br>        TransferComplete(<span>this</span>, <span>null</span>);<br>}<br></pre>
<br>
</div>
<p></p>
<p></p>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> UploadFile(<span>ByVal</span> filepath <span>As</span> <span>String</span>)<br>    <span>Dim</span> s <span>As</span> Status = <span>Nothing</span><br>    <span>Dim</span> startID <span>As</span> <span>Integer</span> = 0<br>    <span>Dim</span> length <span>As</span> <span>Integer</span> = 0<br>    <span>Dim</span> chunkLength <span>As</span> <span>Integer</span> = 140<br><br>    <span>' encode the file</span><br>    <span>Dim</span> file <span>As</span> <span>String</span> = EncodeFile(filepath)<br><br>    <span>' upload the chunks</span><br>    <span>For</span> i <span>As</span> <span>Integer</span> = 0 <span>To</span> file.Length - 1 <span>Step</span> chunkLength<br>        <span>' get the proper length (i.e. don't get full 140 if we're at the end)</span><br>        <span>Dim</span> chunk <span>As</span> <span>String</span> = file.Substring(i, Math.Min(chunkLength, file.Length-i))<br><br>        <span>' handle the case where we chopped a chunk in the middle of an encoded character</span><br>        <span>' in this case, chop off the encoded data and reset the counter</span><br>        <span>If</span> chunk.EndsWith(<span>&quot;%2&quot;</span>) <span>Then</span><br>            chunk = chunk.Substring(0, chunk.Length-2)<br>            i -= 2<br>        <span>End</span> <span>If</span><br><br>        <span>If</span> chunk.EndsWith(<span>&quot;%&quot;</span>) <span>Then</span><br>            chunk = chunk.Substring(0, chunk.Length-1)<br>            i -= 1<br>        <span>End</span> <span>If</span><br><br>        <span>Try</span><br>            <span>' upload the chunk</span><br>            s = _twitter.UpdateStatus(chunk)<br><br>            <span>' notify listeners that we uploaded</span><br>            <span>RaiseEvent</span> ChunkUpload(<span>Me</span>, <span>New</span> ChunkEventArgs(s, chunk.Length, file.Length))<br>        <span>Catch</span> e1 <span>As</span> TwitterRateLimitException<br>            <span>Throw</span> <span>New</span> TwitterDriveException(<span>&quot;Twitter upload limit reached.  Please try again later.&quot;</span>)<br>        <span>End</span> <span>Try</span><br><br>        <span>If</span> i = 0 <span>Then</span><br>            startID = s.ID<br>        <span>End</span> <span>If</span><br><br>        length &#43;= 1<br>    <span>Next</span> i<br><br>    <span>' create a new FileEntry for this file</span><br>    <span>Dim</span> fe <span>As</span> <span>New</span> FileEntry() <span>With</span> {.Filename = Path.GetFileName(filepath), .StartStatus = startID, .EndStatus = s.ID, .Length = length, .FileIndex = GetNextIndex()}<br><br>    <span>' update the index</span><br>    UpdateFileIndex(fe)<br><br>    <span>' notify we're done</span><br>    <span>RaiseEvent</span> TransferComplete(<span>Me</span>, <span>Nothing</span>)<br><span>End</span> Function</pre>
<br>
</div>
<p>Let's take a closer look at the <b>EncodeFile</b> method:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>string</span> EncodeFile(<span>string</span> path)<br>{<br>    <span>// load the file</span><br>    <span>byte</span>[] buff = File.ReadAllBytes(path);<br><br>    <span>// compress</span><br>    MemoryStream ms = <span>new</span> MemoryStream();<br>    GZipStream gs = <span>new</span> GZipStream(ms, CompressionMode.Compress);<br>    gs.Write(buff, 0, buff.Length);<br>    gs.Close();<br><br>    <span>byte</span>[] buffCompressed = ms.ToArray();<br><br>    <span>// base64, urlencode</span><br>    <span>return</span> HttpUtility.UrlEncode(Convert.ToBase64String(buffCompressed));<br>}</pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Function</span> EncodeFile(<span>ByVal</span> path <span>As</span> <span>String</span>) <span>As</span> <span>String</span><br>    <span>' load the file</span><br>    <span>Dim</span> buff() <span>As</span> <span>Byte</span> = File.ReadAllBytes(path)<br><br>    <span>' compress</span><br>    <span>Dim</span> ms <span>As</span> <span>New</span> MemoryStream()<br>    <span>Dim</span> gs <span>As</span> <span>New</span> GZipStream(ms, CompressionMode.Compress)<br>    gs.Write(buff, 0, buff.Length)<br>    gs.Close()<br><br>    <span>Dim</span> buffCompressed() <span>As</span> <span>Byte</span> = ms.ToArray()<br><br>    <span>' base64, urlencode</span><br>    <span>Return</span> HttpUtility.UrlEncode(Convert.ToBase64String(buffCompressed))<br><span>End</span> Function</pre>
<br>
</div>
<p>The code here reads the bytes of a file into a byte array.&nbsp; Then, a <b>MemoryStream</b> object is created and tied to a
<b>GZipStream</b> (compression) object.&nbsp; Next, the byte array is written to the stream which will compress the data on the fly.&nbsp; Once the stream is closed, calling
<b>ToArray</b> on the <b>MemoryStream</b> will return a byte array of the compressed data.&nbsp; The byte array is base64 encoded (turned into text) and finally URL encoded so it can be sent to Twitter.</p>
<p>The file index is written at the end of each file upload.&nbsp; The index is comprised of a delimited string which contains the data in the
<b>FileEntry</b> object.&nbsp; Each file is uploaded as one tweet, with an end marker to denote where the file index ends.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> WriteFileEntries()<br>{<br>    <span>// write an end marker (write this first since they come out in reverse order later)</span><br>    _twitter.UpdateStatus(FileEntryEnd);<br><br>    <span>for</span>(<span>int</span> i = 0; i &lt; _fileEntries.Count; i&#43;&#43;)<br>        WriteFileEntry(_fileEntries[i]);<br>}<br><br><span>private</span> <span>void</span> WriteFileEntry(FileEntry fe)<br>{<br>    <span>// simple delimited list of data</span><br>    <span>string</span> entry = <span>string</span>.Format(FileEntryHeader &#43;<br>                                <span>&quot;{0}&quot;</span> &#43; FileEntrySeparator &#43; <br>                                <span>&quot;{1}&quot;</span> &#43; FileEntrySeparator &#43;<br>                                <span>&quot;{2}&quot;</span> &#43; FileEntrySeparator &#43;<br>                                <span>&quot;{3}&quot;</span> &#43; FileEntrySeparator &#43;<br>                                <span>&quot;{4}&quot;</span>, <br>                                fe.Filename, fe.StartStatus, fe.EndStatus, fe.Length, fe.FileIndex);<br>    _twitter.UpdateStatus(entry);<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> WriteFileEntries()<br>    <span>' write an end marker (write this first since they come out in reverse order later)</span><br>    _twitter.UpdateStatus(FileEntryEnd)<br><br>    <span>Dim</span> i <span>As</span> <span>Integer</span> = 0<br>    <span>Do</span> <span>While</span> i &lt; _fileEntries.Count<br>        WriteFileEntry(_fileEntries(i))<br>        i &#43;= 1<br>    <span>Loop</span><br><span>End</span> <span>Sub</span><br><br><span>Private</span> <span>Sub</span> WriteFileEntry(<span>ByVal</span> fe <span>As</span> FileEntry)<br>    <span>' simple delimited list of data</span><br>    <span>Dim</span> entry <span>As</span> <span>String</span> = <span>String</span>.Format(FileEntryHeader &amp; <span>&quot;{0}&quot;</span> &amp; FileEntrySeparator &amp; <span>&quot;{1}&quot;</span> &amp; FileEntrySeparator &amp; <span>&quot;{2}&quot;</span> &amp; FileEntrySeparator &amp; <span>&quot;{3}&quot;</span> &amp; FileEntrySeparator &amp; <span>&quot;{4}&quot;</span>, fe.Filename, fe.StartStatus, fe.EndStatus, fe.Length, fe.FileIndex)<br>    _twitter.UpdateStatus(entry)<br><span>End</span> Sub</pre>
<br>
</div>
<p>A file list can be retrieved and parsed out with the following code:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> IList&lt;FileEntry&gt; GetFileIndex()<br>{<br>    <span>bool</span> end = <span>false</span>;<br>    <span>int</span> page = 1;<br><br>    <span>// the index should be the last things tweeted, but if we have a failed upload, it may not be</span><br>    <span>while</span>(!end &amp;&amp; page &lt; 5)<br>    {<br>        IList&lt;Status&gt; indexes = _twitter.GetUserTimeline(page, 200);<br><br>        _fileEntries.Clear();<br><br>        <span>// parase out the file entries</span><br>        <span>foreach</span>(Status index <span>in</span> indexes)<br>        {<br>            FileEntry fe = ParseFileIndexString(index.Text);<br>            <span>if</span>(fe != <span>null</span>)<br>            {<br>                fe.IndexStatusId = index.ID;<br>                _fileEntries.Add(fe);<br>            }<br><br>            <span>if</span>(index.Text.StartsWith(FileEntryEnd))<br>            {<br>                end = <span>true</span>;<br>                <span>break</span>;<br>            }<br>        }<br>        page&#43;&#43;;<br>    }<br>    <span>return</span> _fileEntries;<br>}<br><br><span>private</span> FileEntry ParseFileIndexString(<span>string</span> index)<br>{<br>    <span>if</span>(!index.StartsWith(FileEntryHeader))<br>        <span>return</span> <span>null</span>;<br><br>    <span>string</span>[] fileEntry = index.Split(Convert.ToChar(FileEntrySeparator));<br>    FileEntry fe = <span>new</span> FileEntry()<br>                    {<br>                        Filename = fileEntry[0].Replace(FileEntryHeader, <span>string</span>.Empty),<br>                        StartStatus = <span>int</span>.Parse(fileEntry[1]),<br>                        EndStatus = <span>int</span>.Parse(fileEntry[2]),<br>                        Length = <span>int</span>.Parse(fileEntry[3]),<br>                        FileIndex = <span>int</span>.Parse(fileEntry[4])<br>                    };<br>    <span>return</span> fe;<br>}</pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> GetFileIndex() <span>As</span> IList(Of FileEntry)<br>    <span>Dim</span> [<span>end</span>] <span>As</span> <span>Boolean</span> = <span>False</span><br>    <span>Dim</span> page <span>As</span> <span>Integer</span> = 1<br><br>    <span>' the index should be the last things tweeted, but if we have a failed upload, it may not be</span><br>    <span>Do</span> <span>While</span> (<span>Not</span> [<span>end</span>]) <span>AndAlso</span> page &lt; 5<br>        <span>Dim</span> indexes <span>As</span> IList(Of Status) = _twitter.GetUserTimeline(page, 200)<br><br>        _fileEntries.Clear()<br><br>        <span>' parase out the file entries</span><br>        <span>For</span> <span>Each</span> index <span>As</span> Status <span>In</span> indexes<br>            <span>Dim</span> fe <span>As</span> FileEntry = ParseFileIndexString(index.Text)<br>            <span>If</span> fe IsNot <span>Nothing</span> <span>Then</span><br>                fe.IndexStatusId = index.ID<br>                _fileEntries.Add(fe)<br>            <span>End</span> <span>If</span><br><br>            <span>If</span> index.Text.StartsWith(FileEntryEnd) <span>Then</span><br>                [<span>end</span>] = <span>True</span><br>                <span>Exit</span> <span>For</span><br>            <span>End</span> <span>If</span><br>        <span>Next</span> index<br>        page &#43;= 1<br>    <span>Loop</span><br>    <span>Return</span> _fileEntries<br><span>End</span> <span>Function</span><br><br><span>Private</span> <span>Function</span> ParseFileIndexString(<span>ByVal</span> index <span>As</span> <span>String</span>) <span>As</span> FileEntry<br>    <span>If</span> (<span>Not</span> index.StartsWith(FileEntryHeader)) <span>Then</span><br>        <span>Return</span> <span>Nothing</span><br>    <span>End</span> <span>If</span><br><br>    <span>Dim</span> fileEntry() <span>As</span> <span>String</span> = index.Split(Convert.ToChar(FileEntrySeparator))<br>    <span>Dim</span> fe <span>As</span> <span>New</span> FileEntry() <span>With</span> {.Filename = fileEntry(0).Replace(FileEntryHeader, <span>String</span>.Empty), .StartStatus = <span>Integer</span>.Parse(fileEntry(1)), .EndStatus = <span>Integer</span>.Parse(fileEntry(2)), .Length = <span>Integer</span>.Parse(fileEntry(3)), .FileIndex = <span>Integer</span>.Parse(fileEntry(4))}<br>    <span>Return</span> fe<br><span>End</span> Function</pre>
<br>
</div>
<p>This code will retrieve the user's timeline, loop through the tweets, looking for file index entries (those that start with the proper delimiter).&nbsp; When one is found, the data is parsed back into a
<b>FileEntry</b> object and added to the in-memory cache.&nbsp; You will note that the
<b>GetFileIndex</b> method will read up to 1000 tweets looking for the end marker before giving up.</p>
<p>Now that we can upload files and build the index, we need to be able to download, decode and save a file.&nbsp; This is done in the obviously named
<b>DownloadFile </b>method:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>void</span> DownloadFile(FileEntry fe, <span>string</span> path)<br>{<br>    StringBuilder sb = <span>new</span> StringBuilder(fe.Length * 140);<br><br>    <span>// get statuses for this user starting/ending at the IDs for this file</span><br>    IList&lt;Status&gt; chunks = _twitter.GetUserTimeline(fe.StartStatus-1, fe.EndStatus, 1, 200);<br><br>    <span>// order them from oldest to newest</span><br>    var orderedChunks = from chunk <span>in</span> chunks<br>                        orderby chunk.ID ascending<br>                        select chunk;<br><br>    <span>foreach</span>(Status chunk <span>in</span> orderedChunks)<br>    {<br>        <span>// trim off any extra characters</span><br>        <span>string</span> newChunk = chunk.Text.TrimEnd(<span>'.'</span>).Trim();<br>        sb.Append(newChunk);<br><br>        <span>// notify listeners that we downloaded a chunk</span><br>        <span>if</span>(ChunkDownload != <span>null</span>)<br>            ChunkDownload(<span>this</span>, <span>new</span> ChunkEventArgs(chunk, newChunk.Length, fe.Length * 140));<br>    }<br><br>    <span>// decode and write the file</span><br>    <span>byte</span>[] buff = DecodeFile(sb.ToString());<br>    File.WriteAllBytes(Path.Combine(path, fe.Filename), buff);<br><br>    <span>// notify that we're done</span><br>    <span>if</span>(TransferComplete != <span>null</span>)<br>        TransferComplete(<span>this</span>, <span>null</span>);<br>}<br></pre>
<br>
</div>
<p>&nbsp;<b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> DownloadFile(<span>ByVal</span> fe <span>As</span> FileEntry, <span>ByVal</span> filepath <span>As</span> <span>String</span>)<br>    <span>Dim</span> sb <span>As</span> <span>New</span> StringBuilder(fe.Length * 140)<br><br>    <span>' get statuses for this user starting/ending at the IDs for this file</span><br>    <span>Dim</span> chunks <span>As</span> IList(Of Status) = _twitter.GetUserTimeline(fe.StartStatus-1, fe.EndStatus, 1, 200)<br><br>    <span>' order them from oldest to newest</span><br>    <span>Dim</span> orderedChunks = _<br>        From chunk <span>In</span> chunks _<br>        Order By chunk.ID Ascending _<br>        <span>Select</span> chunk<br><br>    <span>For</span> <span>Each</span> chunk <span>As</span> Status <span>In</span> orderedChunks<br>        <span>' trim off any extra characters</span><br>        <span>Dim</span> newChunk <span>As</span> <span>String</span> = chunk.Text.TrimEnd(<span>&quot;.&quot;</span>c).Trim()<br>        sb.Append(newChunk)<br><br>        <span>' notify listeners that we downloaded a chunk</span><br>        <span>RaiseEvent</span> ChunkDownload(<span>Me</span>, <span>New</span> ChunkEventArgs(chunk, newChunk.Length, fe.Length * 140))<br>    <span>Next</span> chunk<br><br>    <span>' decode and write the file</span><br>    <span>Dim</span> buff() <span>As</span> <span>Byte</span> = DecodeFile(sb.ToString())<br>    File.WriteAllBytes(Path.Combine(filepath, fe.Filename), buff)<br><br>    <span>' notify that we're done</span><br>    <span>RaiseEvent</span> TransferComplete(<span>Me</span>, <span>Nothing</span>)<br><span>End</span> Function</pre>
<br>
</div>
<p>This method returns the user's timeline starting and ending at the tweets specified in the
<b>FileEntry</b> object.&nbsp; The status list is ordered in ascending order (i.e. oldest to newest).&nbsp; Each status is appended to the previous using a
<b>StringBuilder</b> object.&nbsp; When all chunks are processed, the file is decoded and saved to the chosen location.</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>byte</span>[] DecodeFile(<span>string</span> data)<br>{<br>    <span>// base64 to binary</span><br>    <span>byte</span>[] buff = Convert.FromBase64String(data);<br><br>    <span>// decompress</span><br>    MemoryStream ms = <span>new</span> MemoryStream(buff);<br>    GZipStream gs = <span>new</span> GZipStream(ms, CompressionMode.Decompress, <span>false</span>);<br><br>    <span>// original</span><br>    <span>byte</span>[] decompressed = ReadAllBytes(gs);<br>    <span>return</span> decompressed;<br>}<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Function</span> DecodeFile(<span>ByVal</span> data <span>As</span> <span>String</span>) <span>As</span> <span>Byte</span>()<br>    <span>' base64 to binary</span><br>    <span>Dim</span> buff() <span>As</span> <span>Byte</span> = Convert.FromBase64String(data)<br><br>    <span>' decompress</span><br>    <span>Dim</span> ms <span>As</span> <span>New</span> MemoryStream(buff)<br>    <span>Dim</span> gs <span>As</span> <span>New</span> GZipStream(ms, CompressionMode.Decompress, <span>False</span>)<br><br>    <span>' original</span><br>    <span>Dim</span> decompressed() <span>As</span> <span>Byte</span> = ReadAllBytes(gs)<br>    <span>Return</span> decompressed<br><span>End</span> Function</pre>
<br>
</div>
<p>To decode the file, we do the opposite of what we did before: the file is converted to bytes from the base64 encoded string, a
<b>GZipStream</b> is used to decompress the data, and the final, uncompressed file contents are returned to the caller to be saved to the disk.</p>
<p>Be sure to look through the entire <b><a class="linkification-ext" title="Linkification: http://TwitterDrive.cs/vb" href="http://TwitterDrive.cs/vb">TwitterDrive.cs/vb</a></b> file for the full picture, but these are the important parts.</p>
<h4>User Interface</h4>
<p>The final piece is the user interface.</p>
<p><img title="4-1-2009 4-01-42 AM" border="0" alt="4-1-2009 4-01-42 AM" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9525376/4-1-2009_204-01-42_20AM_3.png" width="289" height="350">
</p>
<p>A very simple UI for uploading, downloading and deleting files.&nbsp; At the start of the application, the three TwitterDrive events are hooked:
<b>ChunkUpload</b>, <b>ChunkDownload</b>, and <b>TransferComplete</b>.&nbsp; These three event handlers are used to update the progress bar on a dialog box that pops up during the file transfer.</p>
<p>When upload or download is selected, the file is selected, and a new thread is created to start the actual process.&nbsp; Here is what the download process looks like:</p>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>// start a new thread to grab the file</span><br>Thread t = <span>new</span> Thread(() =&gt; _twitterDrive.DownloadFile(fe, fbd.SelectedPath));<br>t.Start();<br><br><span>if</span>(_progress.ShowDialog() == DialogResult.Cancel)<br>    t.Abort();<br><span>else</span><br>    MessageBox.Show(<span>&quot;File download complete.&quot;</span>, <span>&quot;TwitterDrive&quot;</span>, MessageBoxButtons.OK, MessageBoxIcon.Information);<br></pre>
<br>
</div>
<p><b>VB</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>' start a new thread to grab the file</span><br><span>Dim</span> t <span>As</span> <span>New</span> Thread(<span>CType</span>(<span>Function</span>() _twitterDrive.DownloadFile(fe, fbd.SelectedPath), ThreadStart))<br>t.Start()<br><br><span>If</span> _progress.ShowDialog() = System.Windows.Forms.DialogResult.Cancel <span>Then</span><br>    t.Abort()<br><span>Else</span><br>    MessageBox.Show(<span>&quot;File download complete.&quot;</span>, <span>&quot;TwitterDrive&quot;</span>, MessageBoxButtons.OK, MessageBoxIcon.Information)<br><span>End</span> <span>If</span><br></pre>
<br>
</div>
<p>A new thread is created, whose <b>ThreadStart</b> parameter is the <b>DownloadFile</b> method of the
<b>TwitterDrive</b> class.&nbsp; The thread is started, and the progress dialog box is shown.&nbsp; If the progress box is cancelled, the thread is aborted, otherwise the dialog box is closed in response to the
<b>TransferComplete</b> event sent by the <b>TwitterDrive</b> class.</p>
<h4>Using the Application</h4>
<ol>
<li>Create a new Twitter account for use in TwitterDrive. </li><li>Enter the credentials for this new account in the provided textboxes and click Refresh.&nbsp; Or, if you want to download files from someone else, enter just the username and click Refresh.
</li><li>Upload and download data at will. </li></ol>
<h4>Conclusion</h4>
<p>And there we have it.&nbsp; A functionally useless application that actually works.&nbsp; Give it a try and find out what the limitations are.&nbsp; Just be sure to use a Twitter account that isn't your main feed otherwise you'll have some pretty angry followers.</p>
<h4>Thanks</h4>
<p>A special thanks to <a href="http://www.markzaugg.com/" target="_blank">Mark Zaugg</a>,
<a href="http://blogs.msdn.com/danielfe" target="_blank">Dan Fernandez</a>, and <a href="http://www.gmontrone.com/" target="_blank">
Giovanni Montrone</a> for helping me test this application.&nbsp; Giovanni is also partly responsible for this horrible idea after joking that I should Twitter him a file.&nbsp; So blame him.</p>
<p>Also thanks to <a href="http://www.betterthaneveryone.com/" target="_blank">Clint Rutkas</a> for throwing together the icon (it's a combo of the SkyDrive icon &#43; the Twitter icon).</p>
<h4>Bio</h4>
<p>Brian is a <a href="https://mvp.support.microsoft.com/profile/Brian.Peek">Microsoft C# MVP</a> who has been actively developing in .NET since its early betas in 2000, and who has been developing solutions using Microsoft technologies and platforms for even
 longer. Along with .NET, Brian is particularly skilled in the languages of C, C&#43;&#43; and assembly language for a variety of CPUs. He is also well-versed in a wide variety of technologies including web development, document imaging, GIS, graphics, game development,
 and hardware interfacing. Brian has a strong background in developing applications for the health-care industry, as well as developing solutions for portable devices, such as tablet PCs and PDAs. Additionally, Brian has co-authored the book &quot;<a href="http://www.amazon.com/exec/obidos/ASIN/0596520743/brianpcom-20">Coding4Fun:
 10 .NET Programming Projects for Wiimote, YouTube, World of Warcraft, and More</a>&quot; published
<a href="http://www.oreilly.com/">O'Reilly</a>. He previously co-authored the book &quot;<a href="http://www.amazon.com/dp/0735711410/">Debugging ASP.NET</a>&quot; published by New Riders.&nbsp; Brian is also an author for MSDN's
<a href="http://blogs.msdn.com/coding4fun/">Coding4Fun</a> website.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e3cd532524cb4af88f7a9e7600cceaa1">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/TwitterDrive--The-Revolution-in-Cloud-Storage</comments>
      <itunes:summary>



&amp;nbsp;

In this article, Brian Peek will provide a technical overview of TwitterDrive, an application used to store and retrieve files via the Twitter messaging service.



Brian Peek
ASPSOFT, Inc.

Difficulty: Intermediate
Time Required: 2-3 hours
Cost: Free
Software: Visual C# Express 2008 SP1, Visual Basic Express 2008 SP1, or Visual Studio 2008 SP1, .NET Framework 3.5 SP1
Hardware: None
Download: Application,
Source Code
Discussion Forum: Forum




&amp;nbsp; 
Introduction
As you&#39;ve probably guessed by now, TwitterDrive is my April Fool&#39;s Day application for Coding4Fun this year.&amp;nbsp; While the application does actually work, the limitations of Twitter make it functionally useless.&amp;nbsp; That said, I&#39;ll still take you through
 the important parts as there is some value in the code with regard to the Twitter API, LINQ to XML, threading, and a couple other things. 
How It Works
Not very well, actually.&amp;nbsp; The concept is we take a file, compress it, uuencode/base64 encode it (that is, make a text representation of the binary contents), and then upload it 140 characters at a time to Twitter as status messages.&amp;nbsp; When the file upload
 is complete, an index is written of every file that is currently stored on Twitter with some information that can be used to later retrieve the file. 
Twitter
Let&#39;s start with the Twitter API.&amp;nbsp; Full documentation on this API can be found at: 
http://apiwiki.twitter.com/ 
TwitterDrive only requires a very small subset of this functionality to work.&amp;nbsp; We need the ability to post a new status message, download a user timeline, destroy a status, and verify the user&#39;s credentials.&amp;nbsp; All of these things are handled in the
TwitterService class. 
The heart of this class consists of two methods:&amp;nbsp; GetTwitter and PostTwitter.&amp;nbsp;
GetTwitter will make a GET request to Twitter of the specified URL, and 
PostTwitter will make a POST request to Twitter of the specified URL with the supplied data. 
C# 

private XDocument Get</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/TwitterDrive--The-Revolution-in-Cloud-Storage</link>
      <pubDate>Wed, 01 Apr 2009 04:05:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/TwitterDrive--The-Revolution-in-Cloud-Storage</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9525376_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9525376_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/TwitterDrive--The-Revolution-in-Cloud-Storage/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Web</category>
      <category>Windows</category>
      <category>Holiday</category>
      <category>april fools day</category>
    </item>
  <item>
      <title>Watch TV in Microsoft Office</title>
      <description><![CDATA[ <p><a href="http://www.godoublevision.com/">Double Vision</a> is the latest application designed with slacking office workers in mind. Built from Internet Explorer, this software lets you load up a web browser in your “productivity” applications like Microsoft Office for some stealthy web surfing and/or online video viewing on the sly. Once installed, you can configure the transparency levels of the software, which overlays the document you have open where it can be quickly hidden with the keyboard shortcut of CTRL &#43; ESC. Although in a tough economy where people are lucky just to <em>have</em> a job, it seems counterintuitive to suggest a software program that helps you avoid work. But then again, maybe you’ve already been laid off and are just waiting for your last day…in which case, a little Hulu might just do you some good.</p><p></p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:7fac25f62d954e4c8cd09e0e00ef66dc">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Watch-TV-in-Microsoft-Office</comments>
      <itunes:summary> Double Vision is the latest application designed with slacking office workers in mind. Built from Internet Explorer, this software lets you load up a web browser in your “productivity” applications like Microsoft Office for some stealthy web surfing and/or online video viewing on the sly. Once installed, you can configure the transparency levels of the software, which overlays the document you have open where it can be quickly hidden with the keyboard shortcut of CTRL &amp;#43; ESC. Although in a tough economy where people are lucky just to have a job, it seems counterintuitive to suggest a software program that helps you avoid work. But then again, maybe you’ve already been laid off and are just waiting for your last day…in which case, a little Hulu might just do you some good.  </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Watch-TV-in-Microsoft-Office</link>
      <pubDate>Fri, 20 Feb 2009 18:47:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Watch-TV-in-Microsoft-Office</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/on10_25141_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/on10_25141_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_23bdf888-1ee9-44bf-916a-749b484b98b0.jpg" height="261" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_83327aad-a463-4fd6-86f0-576804f985c0.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Watch-TV-in-Microsoft-Office/RSS</wfw:commentRss>
      <category>Internet Explorer</category>
      <category>Internet Explorer</category>
      <category>Microsoft Office</category>
      <category>Office</category>
      <category>Productivity</category>
      <category>Time wasters</category>
    </item>
  <item>
      <title>Stardock Fences Corral Your Desktop Clutter</title>
      <description><![CDATA[<a href="http://www.stardock.com">Stardock</a>, a company known for its UI enhancements, has just released their latest app; <a href="http://www.stardock.com/products/fences/">Fences</a>. Fences allows you to group together desktop icons, sometimes known as 'all that garbage on your desktop', into clean-looking folder containers known as fences. Simply drag select the icons on your desktop and a prompt asks you to name the fence. <br><br>So how is this system fundamentally&nbsp;different from arranging your icons into little piles and folders&nbsp;yourself? First, Fences will let you hide/show those icons with a simple double click on the background. That alone is worth the price (free, btw) of installation. Second, it will allow you to size your container and provide scrollbars if it isn't big enough to display all the icons. This is much cleaner than the average pile of web icons that I have good intentions of opening in the future, and gives you a little more control over display than using folders. <br><br>Fences will work on Windows XP, Vista, and even Windows 7. More information including a video <a href="http://www.stardock.com/products/fences/">here</a>.  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:c8866a7be3c0467f966d9e1000faf250">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/Stardock-Fences-Corral-Your-Desktop-Clutter</comments>
      <itunes:summary>Stardock, a company known for its UI enhancements, has just released their latest app; Fences. Fences allows you to group together desktop icons, sometimes known as &#39;all that garbage on your desktop&#39;, into clean-looking folder containers known as fences. Simply drag select the icons on your desktop and a prompt asks you to name the fence. So how is this system fundamentally&amp;nbsp;different from arranging your icons into little piles and folders&amp;nbsp;yourself? First, Fences will let you hide/show those icons with a simple double click on the background. That alone is worth the price (free, btw) of installation. Second, it will allow you to size your container and provide scrollbars if it isn&#39;t big enough to display all the icons. This is much cleaner than the average pile of web icons that I have good intentions of opening in the future, and gives you a little more control over display than using folders. Fences will work on Windows XP, Vista, and even Windows 7. More information including a video here. </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/Stardock-Fences-Corral-Your-Desktop-Clutter</link>
      <pubDate>Mon, 09 Feb 2009 18:01:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/Stardock-Fences-Corral-Your-Desktop-Clutter</guid>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/Stardock-Fences-Corral-Your-Desktop-Clutter/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>UI</category>
      <category>User Interface</category>
      <category>Utils</category>
    </item>
  <item>
      <title>Top 15 Essential Apps &amp; Codecs post Windows 7 Install</title>
      <description><![CDATA[So you've just installed the new Windows 7 Beta (build 7000). You've created your user profile, logged in for the first time and installed any missing drivers. What next?<br><br>Here's the list of apps and codecs I install within the first 30 minutes.<br><br><em>00. Windows Update</em> - technically not an install but I run it first. Everytime.<br><strong><br>01. <a shape="rect" href="http://download.live.com/" target="_blank" shape="rect">Windows Live Essentials suite</a></strong> - FREE<br>Includes Windows Live Messenger, Photo Gallery, Writer &amp; Mail. Also includes Silverlight<br><strong>02. <a shape="rect" href="https://www.mesh.com/Welcome/default.aspx" target="_blank" shape="rect">Live Mesh</a></strong> - FREE<br>All my files are synced across my various machines with Live Mesh. I also take full advantage of the 5GB of cloud storage<br><strong>03. <a shape="rect" href="http://www.rarlab.com/" target="_blank" shape="rect">WinRAR</a></strong> - Shareware (US$29)<br>My favorite compression and archiving tool. Supports basically any archive format you throw at it including ISO and Linux archives<br><strong>04. <a shape="rect" href="http://free.avg.com/" target="_blank" shape="rect">AVG Free Anti-Virus</a></strong> - FREE<br>Light weight, free anti-virus protection. Does require updates to be manually installed though<br><strong>05. <a shape="rect" href="http://www.mozilla.com/en-US/firefox/" target="_blank" shape="rect">Firefox</a></strong> (plus <a shape="rect" href="http://www.adobe.com/go/getflashplayer" target="_blank" shape="rect">Flash</a> &amp; <a shape="rect" href="https://addons.mozilla.org/en-US/firefox/addon/201" target="_blank" shape="rect">DownThemAll</a>) - FREE<br>IE8 is my default browser however it is still in beta and there are a few web sites out there that render better in Firefox. DownThemAll is an amazing download utility that dramatically speeds up download times<br><strong>06. <a shape="rect" href="http://www.videolan.org/vlc/" target="_blank" shape="rect">VLC Media Player</a></strong> - FREE<br>Basically a Quicktime replacement as VLC can playback most *.MOV files<br><strong>07. <a shape="rect" href="http://www.xvid.org/" target="_blank" shape="rect">Xvid Codec</a></strong> - FREE<br>*Update* Windows Media Player 12 (found in the Windows 7 beta) natively supports Xvid, Divx and MP4 codecs however if (like me) you have a couple of videos in your collection that don't&nbsp;play correctly try installing the Xvid codec.&nbsp;<br>For decoding Xvid, Divx and MP4 video files in Windows Media Player<br><strong>08. <a shape="rect" href="http://ac3filter.net/projects/ac3filter" target="_blank" shape="rect">AC3 Filter</a></strong> - FREE<br>*Update* As above - you may not need this codec but if you find you're not getting any sound when plating back a&nbsp;video file it might an AC3/DTS issue. <br>Audio filter that enables Windows Media Player to playback movies with AC3 and DTS audio tracks<br><strong>09. <a shape="rect" href="http://www.imgburn.com/" target="_blank" shape="rect">ImgBurn</a></strong> - FREE<br>*Update* Windows 7 burns ISO images&nbsp;natively so this tool is mainly&nbsp;used for&nbsp;creating ISO images.&nbsp;<br>Great CD/DVD burning and ISO creation utility<br><strong>10. <a shape="rect" href="http://www.poikosoft.com/" target="_blank" shape="rect">Easy CD-DA Extractor</a></strong> - 30 Day Free Trial (US$37)<br>*Update* I primarily use Easy CD-DA Extractor for converting from one file format to the other ie. lossless to MP3 and for the odd CD that WMP12 is unable to rip for me.<br>&quot;The Swiss Army Knife of Digital Audio&quot; pretty much sums up Easy CD-DA Extractor. I still buy physical CD's from real music stores,... how crazy is that!! Easy CD-DA Extractor allows me to back-up my discs and convert to MP3 for storage on my Windows Home Server<br><strong>11. <a shape="rect" href="http://www.getpaint.net/" target="_blank" shape="rect">Paint.NET</a></strong> - FREE<br>*Update* The new Paint application in Windows 7 is a great update but if you need to work with some basic layers or some more advanced features then Paint.NET is a great tool.<br>Simple yet powerful free Photoshop alternative. Not quite as comprehensive as GIMP but does the basics and does them well<br><strong>12. <a shape="rect" href="http://www.getsharepod.com/" target="_blank" shape="rect">SharePod</a></strong> - FREE<br>iTunes alternative for transferring tracks on (and off) ipods<br><strong>13. <a shape="rect" href="http://www.skype.com/download/skype/windows/beta/" target="_blank" shape="rect">Skype</a></strong> (version 4.0 Beta 3) - FREE<br>I think we all know what Skype is<br><strong>14. <a shape="rect" href="http://filezilla-project.org/" target="_blank" shape="rect">FileZilla</a></strong> - FREE<br>Light weight, free FTP Utility. Supports file resume<br><strong>15. <a shape="rect" href="http://office.microsoft.com" target="_blank" shape="rect">Microsoft Office 2007</a></strong> - 60 Day Free Trial (<a shape="rect" href="http://www.newegg.com/Product/Product.aspx?Item=N82E16832116135" target="_blank" shape="rect">from US$80</a>)<br>Outlook, Word, Excel and Powerpoint are my essentials although Windows Live Mail is a great alternative if you don't need the complexity of Outlook<br><br>What have I missed? What other apps &amp; codecs do you install during the first 30 minutes after an OS rebuild?<br><br>Check out Larry's <a shape="rect" href="http://on10.net/blogs/larry/Top-10-Fresh-Machine-Installs/" target="_blank" shape="rect">Top 10 Fresh Machine Installs</a> for more.<br> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:09402983c4de47fdbbb09e0f00eaada4">]]></description>
      <comments>http://channel9.msdn.com/Blogs/NicFill/Top-15-Essential-Apps--Codecs-post-Windows-7-Install</comments>
      <itunes:summary>So you&#39;ve just installed the new Windows 7 Beta (build 7000). You&#39;ve created your user profile, logged in for the first time and installed any missing drivers. What next?Here&#39;s the list of apps and codecs I install within the first 30 minutes.00. Windows Update - technically not an install but I run it first. Everytime.01. Windows Live Essentials suite - FREEIncludes Windows Live Messenger, Photo Gallery, Writer &amp;amp; Mail. Also includes Silverlight02. Live Mesh - FREEAll my files are synced across my various machines with Live Mesh. I also take full advantage of the 5GB of cloud storage03. WinRAR - Shareware (US$29)My favorite compression and archiving tool. Supports basically any archive format you throw at it including ISO and Linux archives04. AVG Free Anti-Virus - FREELight weight, free anti-virus protection. Does require updates to be manually installed though05. Firefox (plus Flash &amp;amp; DownThemAll) - FREEIE8 is my default browser however it is still in beta and there are a few web sites out there that render better in Firefox. DownThemAll is an amazing download utility that dramatically speeds up download times06. VLC Media Player - FREEBasically a Quicktime replacement as VLC can playback most *.MOV files07. Xvid Codec - FREE*Update* Windows Media Player 12 (found in the Windows 7 beta) natively supports Xvid, Divx and MP4 codecs however if (like me) you have a couple of videos in your collection that don&#39;t&amp;nbsp;play correctly try installing the Xvid codec.&amp;nbsp;For decoding Xvid, Divx and MP4 video files in Windows Media Player08. AC3 Filter - FREE*Update* As above - you may not need this codec but if you find you&#39;re not getting any sound when plating back a&amp;nbsp;video file it might an AC3/DTS issue. Audio filter that enables Windows Media Player to playback movies with AC3 and DTS audio tracks09. ImgBurn - FREE*Update* Windows 7 burns ISO images&amp;nbsp;natively so this tool is mainly&amp;nbsp;used for&amp;nbsp;creating ISO images.&amp;nbsp;Great CD/DVD burning and ISO</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/NicFill/Top-15-Essential-Apps--Codecs-post-Windows-7-Install</link>
      <pubDate>Thu, 15 Jan 2009 18:13:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/NicFill/Top-15-Essential-Apps--Codecs-post-Windows-7-Install</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_56d3a782-c9d9-40ef-b13a-84af0f6fde91.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_1080ca5c-08e2-4ab9-9d55-04552876239e.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Nic Fillingham</dc:creator>
      <itunes:author>Nic Fillingham</itunes:author>
      <slash:comments>20</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/NicFill/Top-15-Essential-Apps--Codecs-post-Windows-7-Install/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Windows 7</category>
    </item>
  <item>
      <title>30 Windows 7 Tips</title>
      <description><![CDATA[<a href="http://blogs.msdn.com/tims/about.aspx">Tim Sneath </a>put together a great list of &quot;<a href="http://blogs.msdn.com/tims/archive/2009/01/12/the-bumper-list-of-windows-7-secrets.aspx">30 Windows 7 Secrets</a>&quot;. If you're using the Windows 7 beta, this is a <em>must-read</em>. Some of the keyboard shortcuts include moving windows a half screen at a time with Windows&#43;Right (or Left) Arrow, or using&nbsp;Windows&#43;Up/Down to minimize/maximize. You can hit Windows&#43;Home to minimize all the windows except the current one. Windows&#43;T will give focus to your taskbar, allowing you to zip through the windows with the arrow keys. <br><br>The Problem Steps Recorder was news to me, capturing the screen while you recreate a problem with your computer. Designers will be interested in Gabriola, a beautiful new ornamental font that uses smart ligatures. Tim even tells you how to get back to the Vista Taskbar and Quick Launch toolbar if you really miss it.  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:acd6194b0ca44b4f837b9e1000fa7ca6">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/30-Windows-7-Tips</comments>
      <itunes:summary>Tim Sneath put together a great list of &amp;quot;30 Windows 7 Secrets&amp;quot;. If you&#39;re using the Windows 7 beta, this is a must-read. Some of the keyboard shortcuts include moving windows a half screen at a time with Windows&amp;#43;Right (or Left) Arrow, or using&amp;nbsp;Windows&amp;#43;Up/Down to minimize/maximize. You can hit Windows&amp;#43;Home to minimize all the windows except the current one. Windows&amp;#43;T will give focus to your taskbar, allowing you to zip through the windows with the arrow keys. The Problem Steps Recorder was news to me, capturing the screen while you recreate a problem with your computer. Designers will be interested in Gabriola, a beautiful new ornamental font that uses smart ligatures. Tim even tells you how to get back to the Vista Taskbar and Quick Launch toolbar if you really miss it. </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/30-Windows-7-Tips</link>
      <pubDate>Tue, 13 Jan 2009 06:36:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/30-Windows-7-Tips</guid>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/30-Windows-7-Tips/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Windows 7</category>
    </item>
  <item>
      <title>Taglocity Brings New Features To Outlook</title>
      <description><![CDATA[
<p>Do you live in Outlook but wish it had a few of the features that your webmail program has? Features like conversation threading and automatic tagging, for example? Well now the Outlook email plugin,
<a href="http://taglocity.com">Taglocity</a>, delivers those features and more. With the latest version, Taglocity 2.0, Outlook users can take advantage of enhanced search functionality, conversation threading, tagging, and automation. Instead of moving messages
 to folders, email can be tagged with any number of labels and, based on those labels, certain tasks and actions can then be automated. For example, Taglocity can automatically turn email into calendar appointments or move messages into different folders.
</p>
<p>Although some of the functions in Taglocity can already be done with crafty use of Outlook’s rules and views - not to mention Outlook 2007’s labels -the plugin aims to make that process easier. This is especially true for the conversation threading feature
 which displays emails in chronological order with all the related conversations grouped together. Some Outlook 2007 users won’t see the need for this addition, but for users of Outlook 2003, this plugin delivers some great additional features. You can check
 it out for yourself <a href="http://www.taglocity.com">here</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:24063faec92843a193159dec00488ea7">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Taglocity-Brings-New-Features-To-Outlook</comments>
      <itunes:summary>
Do you live in Outlook but wish it had a few of the features that your webmail program has? Features like conversation threading and automatic tagging, for example? Well now the Outlook email plugin,
Taglocity, delivers those features and more. With the latest version, Taglocity 2.0, Outlook users can take advantage of enhanced search functionality, conversation threading, tagging, and automation. Instead of moving messages
 to folders, email can be tagged with any number of labels and, based on those labels, certain tasks and actions can then be automated. For example, Taglocity can automatically turn email into calendar appointments or move messages into different folders.
 
Although some of the functions in Taglocity can already be done with crafty use of Outlook’s rules and views - not to mention Outlook 2007’s labels -the plugin aims to make that process easier. This is especially true for the conversation threading feature
 which displays emails in chronological order with all the related conversations grouped together. Some Outlook 2007 users won’t see the need for this addition, but for users of Outlook 2003, this plugin delivers some great additional features. You can check
 it out for yourself here. 
</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Taglocity-Brings-New-Features-To-Outlook</link>
      <pubDate>Fri, 14 Nov 2008 15:58:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Taglocity-Brings-New-Features-To-Outlook</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_825c51e7-bce0-4d4b-8f15-0b67361e515f.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_93641e4e-0fe3-4219-a46c-1c6607de1a50.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>12</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Taglocity-Brings-New-Features-To-Outlook/RSS</wfw:commentRss>
      <category>Outlook</category>
      <category>Productivity</category>
      <category>plugin</category>
      <category>add-in&#39;s</category>
      <category>tagging</category>
      <category>Outlook 2007</category>
      <category>Plugins</category>
      <category>Plug-in</category>
      <category>add-in</category>
    </item>
  <item>
      <title>Inherited Message Distributing</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td><span class="entry_description">Given a week off of school I found the time to start designing a system that had been thought up in a school class. The idea was simple, a webapp that lets a user reach the widest possible audience by distributing messages
 across many mediums. One message could be delivered to each recipient as an email, text message, instant message, or phone call to name a few possibilities. With this system, an already overworked teacher could take 30 seconds to send one message that was
 delivered to each student and parent instantly across multiple mediums. A sports coach could finally reach everyone on the team, without trying to post news on a site that was rarely checked and poorly maintained.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Robert Witoff</div>
<a title="http://www.chalk2me.com/" href="http://www.chalk2me.com/">http://www.chalk2me.com/</a>
<br>
<div class="entry_details"><b></b></div>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b><a href="http://codeplex.com/chalk2me">Download</a>
</div>
<div class="entry_details">&nbsp;</div>
<div class="entry_details"><strong>Disclaimer: </strong>Currently this article is C# only.&nbsp; If you want it in Visual Basic.Net, please comment and tell us so we can transcode it to VB.</div>
</td>
</tr>
</tbody>
</table>
</span>
<p><b>Starting Out:</b></p>
<p>We thought we had come up with a cool concept, and I knew it wouldn't be that difficult to build. After calling our dev-team into the office I started on it, by myself in my apartment. My goal was to have a single method to send any type of message that
 would then be picked up by an appropriate thread to deliver the message. As the whole idea here was to create and deliver messages, a logical place to start was a struct to hold our message fields. It's always good to keep other services in mind while you're
 building your own. I started off with the first 4 fields in any email. This covered message content and we only needed a bit more info to deliver the message. The medium type, along with an identifier field for your address (or screen name etc.), would cover
 this. Just in case a service we end up using needs a second identifier, I added one more. Check it out:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">struct</span> ctMessage
{
    <span class="kwrd">public</span> ctMessage(<span class="kwrd">string</span> sendToUser, <span class="kwrd">string</span> fromUser, <span class="kwrd">string</span> subj, <span class="kwrd">string</span> msg, <span class="kwrd">string</span>

    mediumType, <span class="kwrd">string</span> mediumArg1, <span class="kwrd">string</span> mediumArg)
    {
        <span class="kwrd">this</span>.toUser = sendToUser;
        <span class="kwrd">this</span>.fromUser = fromUser;
        <span class="kwrd">this</span>.subject = subj;
        <span class="kwrd">this</span>.message = msg;
        <span class="kwrd">this</span>.mediumType = mediumType;
        <span class="kwrd">this</span>.mediumArg1 = mediumArg1;
        <span class="kwrd">this</span>.mediumArg2 = mediumArg2;
    }

    <span class="kwrd">public</span> <span class="kwrd">string</span> toUser; <span class="rem">//name of recipient</span>
    <span class="kwrd">public</span> <span class="kwrd">string</span> fromUser; <span class="rem">//name of sender</span>
    <span class="kwrd">public</span> <span class="kwrd">string</span> subject;
    <span class="kwrd">public</span> <span class="kwrd">string</span> message;
    <span class="kwrd">public</span> <span class="kwrd">string</span> mediumType; <span class="rem">//which node should deliver this</span>
    <span class="kwrd">public</span> <span class="kwrd">string</span> mediumArg1; <span class="rem">//varies, to identify the recipient</span>
    <span class="kwrd">public</span> <span class="kwrd">string</span> mediumArg2; <span class="rem">//varies, to identify the recipient</span>
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Once we had a message designed I, of course, wanted to be able to send one! Eventually I wanted a bunch of different types of messages being sent, so a solid base class would save a ton of time later. Although all of the messaging services, or ‘nodes' would
 undoubtedly send the messages completely different, they would all need to run in a similar thread that sent messages coming from a single location. By doing a good job writing an abstract base class, we could add new services by only overriding the 'send'
 method later.</p>
<p>This abstract class would have a field identifying the type of messages it will handle, and call an external send method whenever messages of that type existed. A continuous loop to poll for messages, given a modest polling frequency would do the trick.
 Notice the protected methods and fields that we'll want to override.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> ctNode
{
    <span class="kwrd">public</span> ctNode()
    {
        <span class="kwrd">this</span>.maxQueueSize = 100; <span class="rem">//Set the size according to how long it will take to reach the Nth message</span>
        <span class="kwrd">this</span>.msgQueue = <span class="kwrd">new</span> Queue(maxQueueSize);
        <span class="kwrd">this</span>.msPauseAfterRun = 10000; <span class="rem">//If using a DB, polling it with no pause b/w queries is an unnecessary load</span>
        <span class="kwrd">this</span>.runnerThread = <span class="kwrd">new</span> Thread(<span class="kwrd">new</span> ThreadStart(<span class="kwrd">this</span>.run));
    }

    <span class="kwrd">private</span> Thread runnerThread;
    <span class="kwrd">protected</span> <span class="kwrd">int</span> msPauseAfterRun;
    <span class="kwrd">protected</span> Queue msgQueue;
    <span class="kwrd">public</span> <span class="kwrd">int</span> maxQueueSize;

    <span class="kwrd">void</span> run()
    {
        <span class="kwrd">while</span> (<span class="kwrd">true</span>)
        {
            <span class="kwrd">while</span> (<span class="kwrd">this</span>.msgQueue.Count &gt; 0)
            {
                <span class="rem">//pop a message and send it</span>
                ctMessage ctm = (ctMessage)msgQueue.Dequeue();

                <span class="kwrd">try</span>
                {
                    sendSingleMessage(ctm);
                }
                <span class="kwrd">catch</span> (Exception e)
                {
                    <span class="rem">//Write a more detailed error log here</span>
                    Console.writeLine(<span class="str">&quot;the message could not be sent!&quot;</span> &#43; e.toString());
                }
            }

            <span class="rem">//get new messages</span>
            ctNode ctn = <span class="kwrd">this</span>;
            ctMessage[] newMessages = messageSender.getMessages(<span class="kwrd">ref</span> ctn, getRoomInQueue());

            <span class="rem">//Wait some time before checking for more messages!</span>
            <span class="kwrd">if</span> (newMessages.Length == 0)
                Thread.Sleep(msPauseAfterRun);
            <span class="kwrd">else</span>
                <span class="kwrd">this</span>.EnqueueMessages(newMessages);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> EnqueueMessages(ctMessage[] messagesToSend)
    {
        <span class="kwrd">int</span> roomInQueue = maxQueueSize - msgQueue.Count;

        <span class="kwrd">if</span> (messagesToSend.Length &gt; roomInQueue)
            <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="str">&quot;Too many Messages have been inserted&quot;</span>);

        <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; messagesToSend.Length; i&#43;&#43;)
        {
            msgQueue.Enqueue(messagesToSend[i]);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> EnqueueMessages(ctMessage messageToSend)
    {
        ctMessage[] ctm = <span class="kwrd">new</span> ctMessage[1];
        ctm[0] = messageToSend;
        <span class="kwrd">this</span>.EnqueueMessages(ctm);
    }

    <span class="kwrd">protected</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> sendSingleMessage(ctMessage ctm)
    {
        <span class="rem">//code to send an individual message</span>
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> startThread()
    {
        runnerThread.Name = <span class="kwrd">this</span>.nodeType;
        runnerThread.Start();
    }

    <span class="kwrd">protected</span> <span class="kwrd">string</span> nodeType;

    <span class="kwrd">public</span> <span class="kwrd">string</span> getNodeType()
    {
        <span class="kwrd">return</span> <span class="kwrd">this</span>.nodeType;
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>You might have noticed the big thing missing from these classes, a place to store, and retrieve messages! I initially put our message storage into an external static class. This made them centralized, easily accessible from any other objects that might need
 to access them, simple to ensure thread safety, and gave us room to move to a smarter mechanism later (or database. Notice the simplicity:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> messageSender
{
    <span class="kwrd">private</span> <span class="kwrd">static</span> List&lt;ctMessage&gt; messagesToSend = <span class="kwrd">new</span> List&lt;ctMessage&gt;();

    <span class="kwrd">public</span> <span class="kwrd">static</span> ctMessage[] getMessages(<span class="kwrd">ref</span> ctNode nodeRef, <span class="kwrd">int</span> numberOfMessages)
    {
        <span class="rem">//We'll do this in a database later, but for now this works similarly</span>
        List&lt;ctMessage&gt; returnMessages = <span class="kwrd">new</span> List&lt;ctMessage&gt;();

        <span class="kwrd">lock</span> (messagesToSend)
            <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; messagesToSend.Count; i&#43;&#43;)
                <span class="kwrd">if</span> (messagesToSend[i].mediumArgs == nodeRef.getNodeType())
                {
                    returnMessages.Add(messagesToSend[i]);
                    messagesToSend.RemoveAt(i);
                    i--;
                }

        <span class="kwrd">return</span> returnMessages.ToArray();
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> sendMessage(ctMessage message)
    {
        <span class="kwrd">lock</span> (messagesToSend)
            messagesToSend.Add(message);
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now that the groundwork was done, I grabbed some eye drops and an energy drink to refresh for the best part, function! I started simple with an email node, and if you've played with email before in .net, you've definitely seen and loved the SmtpClient class
 in the System.Net.Mail Namespace. If you don't already have a local SMTP client set up, you can easily use a Gmail account as an SMTP server. Check out the following implementation, notice we only had to set the node type, initialize the SmtpClient and override
 the send method. Send a message through our message sender, and watch the node pick up the message and deliver it. Inheritance rocks!</p>
<pre class="csharpcode">ctMessage ctm = <span class="kwrd">new</span> ctMessge(<span class="str">&quot;Friend&quot;</span>, <span class="str">&quot;Developer&quot;</span>, <span class="str">&quot;testing&quot;</span>, <span class="str">&quot;My first message&quot;</span>, <span class="str">&quot;email&quot;</span>, <span class="str">&quot;yourEmail@yourDomain.com&quot;</span>, <span class="str">&quot;&quot;</span>);
messageSender.sendMessage(ctm);

<span class="kwrd">public</span> <span class="kwrd">class</span> ctNodeEmail : ctNode
{
    <span class="kwrd">public</span> ctNodeEmail() : <span class="kwrd">base</span>()
    {
        <span class="kwrd">this</span>.nodeType = <span class="str">&quot;email&quot;</span>;

        <span class="rem">//</span>
        <span class="rem">//SET UP SMTP CLIENT</span>
        <span class="rem">//</span>

        <span class="rem">//GMAIL SERVER</span>
        <span class="kwrd">this</span>.mSmtpClient = <span class="kwrd">new</span> SmtpClient(<span class="str">&quot;gmail.com/mail&quot;</span>, 25);
        <span class="kwrd">this</span>.mSmtpClient.Host = <span class="str">&quot;smtp.gmail.com&quot;</span>;
        <span class="kwrd">this</span>.mSmtpClient.Port = 25;
        <span class="kwrd">this</span>.mSmtpClient.EnableSsl = <span class="kwrd">true</span>;
        <span class="kwrd">this</span>.mSmtpClient.Credentials = <span class="kwrd">new</span> System.Net.NetworkCredential(<span class="str">&quot;YOURADDRESS@gmail.com&quot;</span>, <span class="str">&quot;YOUR_PASSWORD&quot;</span>);

        <span class="rem">//LOCAL SERVER</span>
        <span class="rem">//this.mSmtpClient = new SmtpClient(&quot;localhost&quot;, 25);</span>
    }

    SmtpClient mSmtpClient;

    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> sendSingleMessage(ctMessage ctm)
    {
        MailMessage msgMail = <span class="kwrd">new</span> MailMessage(<span class="kwrd">new</span> MailAddress(ctm.fromUser &#43; <span class="str">&quot;@ChalkTalkNow.com&quot;</span>), <span class="kwrd">new</span> MailAddress(ctm.mediumArgs));
        msgMail.Subject = ctm.subject;
        <span class="kwrd">string</span> msg = ctm.message;
        msgMail.Body = msg;

        <span class="rem">// Send the mail message</span>
        mSmtpClient.Send(msgMail);
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>After writing this so quickly I wanted something a bit more than email, and knew text messages were only a step away. It's no secret that all major cell companies give your phone an email address, you just need to append the proper domain to your number.
 Building off of our email node, we used the first mediumArg to hold a phone number, and put the carrier into the second mediumArg.
</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> ctNodeTextMessage : ctNode
{
    <span class="kwrd">public</span> ctNodeTextMessage() : <span class="kwrd">base</span>()
    {
        <span class="kwrd">this</span>.nodeType = <span class="str">&quot;textmessage&quot;</span>;

        <span class="rem">//</span>
        <span class="rem">//SET UP SMTP CLIENT</span>
        <span class="rem">//</span>
        <span class="kwrd">this</span>.mSmtpClient = <span class="kwrd">new</span> SmtpClient(<span class="str">&quot;gmail.com/mail&quot;</span>, 25);
        <span class="kwrd">this</span>.mSmtpClient.Host = <span class="str">&quot;smtp.gmail.com&quot;</span>;
        <span class="kwrd">this</span>.mSmtpClient.Port = 25;
        <span class="kwrd">this</span>.mSmtpClient.EnableSsl = <span class="kwrd">true</span>;
        <span class="kwrd">this</span>.mSmtpClient.Credentials = <span class="kwrd">new</span> System.Net.NetworkCredential(<span class="str">&quot;GMAIL@gmail.com&quot;</span>, <span class="str">&quot;PASSWORD&quot;</span>);

    }
    SmtpClient mSmtpClient;

    <span class="kwrd">private</span> <span class="kwrd">string</span> getEmailAddress(<span class="kwrd">string</span> phoneNumber, <span class="kwrd">string</span> provider)
    {
        <span class="kwrd">switch</span> (provider)
        {
            <span class="kwrd">case</span> <span class="str">&quot;t-mobile&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@tmomail.net&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;virginmobile&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@vmobl.com&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;cingular&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@cingularme.com&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;att&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@cingularme.com&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;sprint&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@messaging.sprintpcs.com&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;verizon&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@vtext.com&quot;</span>;
            <span class="kwrd">case</span> <span class="str">&quot;nextel&quot;</span>:
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@messaging.nextel.com&quot;</span>;
            <span class="kwrd">default</span>:
                <span class="rem">//assume cingular/att is the most popular</span>
                <span class="kwrd">return</span> phoneNumber &#43; <span class="str">&quot;@cingularme.com&quot;</span>;
        }
    }

    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> sendSingleMessage(ctMessage ctm)
    {
        <span class="rem">//send a single message</span>
        <span class="kwrd">string</span> emailAddress = getEmailAddress(ctm.mediumArg1, ctm.mediumArg2);

        MailMessage msgMail = <span class="kwrd">new</span> MailMessage(<span class="kwrd">new</span> MailAddress(ctm.fromUser &#43; <span class="str">&quot;@chalktalk.net&quot;</span>, ctm.fromUser), <span class="kwrd">new</span> MailAddress(emailAddress));
        msgMail.Subject = ctm.subject;
        msgMail.Body = ctm.message;
        sendEmail(msgMail);
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> sendEmail(MailMessage msgMail)
    {
        <span class="rem">// Send the mail message</span>
        <span class="kwrd">this</span>.mSmtpClient.Send(msgMail);
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now to test this out, just like we sent the email we'll send a text. Cool!</p>
<pre class="csharpcode">ctMessage ctm = <span class="kwrd">new</span> ctMessge(<span class="str">&quot;Friend&quot;</span>, <span class="str">&quot;Developer&quot;</span>, <span class="str">&quot;testing&quot;</span>, <span class="str">&quot;hello world via text&quot;</span>, <span class="str">&quot;textmessage&quot;</span>, <span class="str">&quot;#########&quot;</span>, <span class="str">&quot;verizon&quot;</span>);
messageSender.sendMessage(ctm);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3>Conclusion:</h3>
<p>When you're working on a project with a small team, it's especially important to build a good foundation like this so you can focus on easily added functionality without getting bogged down in complexity. This portion of the project was written over the
 course of a week and later on allowed us to focus almost exclusively on adding new services like Instant Messengers and interactive phone calling. Having functionality so quickly was crucial, along with a UI built by my brother, in getting the attention and
 support of others to build a business around this.</p>
<h3>Next Steps:</h3>
<ul>
<li>Build a UI to manage content and run your messaging! </li><li>Rewrite your messageSender class to store messages in a database. This will make your app much more extensible, and you can save a record of the messages sent in an ‘outbox'.
</li><li>Strongly type all textual identifiers in enumerations to avoid any frustrating mistakes.
</li><li>Find an SDK for your favorite messenger, and build a node for it </li><li>Join our team and continue to build with us! </li></ul>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:ac39f35957c84be1b0619e7600ce550e">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Inherited-Message-Distributing</comments>
      <itunes:summary>



&amp;nbsp;
Given a week off of school I found the time to start designing a system that had been thought up in a school class. The idea was simple, a webapp that lets a user reach the widest possible audience by distributing messages
 across many mediums. One message could be delivered to each recipient as an email, text message, instant message, or phone call to name a few possibilities. With this system, an already overworked teacher could take 30 seconds to send one message that was
 delivered to each student and parent instantly across multiple mediums. A sports coach could finally reach everyone on the team, without trying to post news on a site that was rarely checked and poorly maintained.



Robert Witoff
http://www.chalk2me.com/


Difficulty: Intermediate
Time Required: 
3-6 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: 
Download: Download

&amp;nbsp;
Disclaimer: Currently this article is C# only.&amp;nbsp; If you want it in Visual Basic.Net, please comment and tell us so we can transcode it to VB.





Starting Out: 
We thought we had come up with a cool concept, and I knew it wouldn&#39;t be that difficult to build. After calling our dev-team into the office I started on it, by myself in my apartment. My goal was to have a single method to send any type of message that
 would then be picked up by an appropriate thread to deliver the message. As the whole idea here was to create and deliver messages, a logical place to start was a struct to hold our message fields. It&#39;s always good to keep other services in mind while you&#39;re
 building your own. I started off with the first 4 fields in any email. This covered message content and we only needed a bit more info to deliver the message. The medium type, along with an identifier field for your address (or screen name etc.), would cover
 this. Just in case a service we end up using needs a second identifier, I added one more. Check it out: 
public struct ctMessage
{
    public ctMessage(stri</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Inherited-Message-Distributing</link>
      <pubDate>Thu, 11 Sep 2008 18:35:05 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Inherited-Message-Distributing</guid>      
      <dc:creator>Robert Witoff</dc:creator>
      <itunes:author>Robert Witoff</itunes:author>
      <slash:comments>14</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Inherited-Message-Distributing/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Web</category>
    </item>
  <item>
      <title>BlueBoss - Bluetooth Proximity Detection</title>
      <description><![CDATA[
<h3>Summary:</h3>
<p><strong></strong>Bluetooth is now found in a variety of devices and enable the user to use wireless accessories.&nbsp; The Bluetooth protocol allows a user to “discover” any device that is in proximity to your Bluetooth radio.&nbsp; Why not see who is in proximity
 to you?&nbsp; Why not have the presence of a device execute programs or alert you?</p>
<p>Andy Konkol – <u><a href="http://copyandwaste.com/">http://copyandwaste.com</a></u></p>
<p>&nbsp;</p>
<p><strong>Hardware:</strong></p>
<ul>
<li>
<p>Bluetooth radio (USB dongle)</p>
</li><li>
<p>SMA Female Jack</p>
</li><li>
<p>SMA male to N-male pigtail</p>
</li><li>
<p>2.4 GHz antenna (with N-female connector)</p>
</li></ul>
<p><strong>Software:</strong></p>
<ul>
<li>
<p><u><a href="http://www.microsoft.com/express/samples/c4fdevkit/default.aspx">Coding4fun Developer Kit</a></u></p>
</li><li>
<p><u><a href="http://www.codeproject.com/KB/miscctrl/RobMisNotifyWindow.aspx">Robert Misiak's Notify Window</a></u></p>
</li></ul>
<p><strong>Download:</strong> </p>
<ul>
<li>
<p><a href="http://www.codeplex.com/blueboss/Release/ProjectReleases.aspx?ReleaseId=14662">Source / Binary Download</a></p>
</li></ul>
<p><u></u></p>
<h3><strong>Bluetooth and Hardware:</strong></h3>
<br>
<p><strong></strong>Bluetooth was designed for devices to communicate wirelessly over short distances.&nbsp; However, with a very simple hardware modification you can extend the range of your Bluetooth radio with standard 2.4ghz antennas used in wireless networking
 (802.11 a/b/g). </p>
<p>Modifying Bluetooth dongles to accept external antennas is documented all over the Internet.&nbsp; In principle it is very easy: find the antenna lead and solder on a connector/antenna.&nbsp; I purchased a very cheap Bluetooth USB dongle on eBay and opened the casing.&nbsp;
 After finding the antenna trace on the circuit board I soldered on a SMA Female connector to it.&nbsp; After soldering the antenna jack in place I slipped a 3 inch chunk of heatshrink and heated it to cover the exposed circuit board.&nbsp; Now I had a Bluetooth radio
 that accepts external antennas. Adding an antenna simply increases the range of your radio, allowing you to “see” devices from a farther distance.
</p>
<p>To connect an external antenna to the dongle I needed to use a connector converter called a pigtail.&nbsp; I used a SMA male to N-male pigtail.&nbsp; I connected one end of the pigtail to my dongle and the other to an omni-directional 9dbi panel antenna that had an
 N-female connector.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/IMG_20701.jpg"><img title="IMG_2070[1]" height="180" alt="IMG_2070[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/IMG_20701_thumb.jpg" width="240" border="0"></a>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/IMG_20711.jpg"><img title="IMG_2071[1]" height="180" alt="IMG_2071[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/IMG_20711_thumb.jpg" width="240" border="0"></a>
</p>
<h3><strong>Software:</strong></h3>
<br>
<p><strong></strong>To take advantage of my newly modified hardware I needed to download the Coding4Fun Toolkit.&nbsp; Included in the toolkit is an API for Bluetooth devices.&nbsp; This API allows you to do a wide variety of things with your Bluetooth radio but I focused
 on two methods from the ServiceAndDeviceDiscovery library: DiscoverAllDevices and DiscoverDeviceByName.
</p>
<p>DiscoverAllDevices allows you to “scan” the airwaves on the 2.4 GHz band and report back what devices your radio sees.
</p>
<p>DiscoverDeviceByName allows you to scan for a particular device with a specified name and report back if it is present or not.</p>
<p><b><i></i></b></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">bool</span> DevicePresent()
{
    BluetoothDeviceServicesManager workerBTMgr = <span class="kwrd">new</span> BluetoothDeviceServicesManager();
    Device workerDevice = workerBTMgr.DiscoverDeviceByName(_watchItem.DeviceName);

    <span class="kwrd">return</span> (workerDevice != <span class="kwrd">null</span>);
}

<span class="kwrd">public</span> <span class="kwrd">void</span> Run(String Operation)
{
    <span class="kwrd">switch</span> (Operation)
    {
        <span class="kwrd">case</span> <span class="str">&quot;SingleDevice&quot;</span>:
            <span class="kwrd">if</span> (DevicePresent())
            {
                _parentForm.Invoke(_parentForm.AddToDeviceSeenList, <span class="kwrd">new</span> <span class="kwrd">object</span>[] { _watchItem });
            }
            <span class="kwrd">else</span>
            {
                _parentForm.Invoke(_parentForm.RemoveFromDeviceSeenList, <span class="kwrd">new</span> <span class="kwrd">object</span>[] { _watchItem });
            }
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> <span class="str">&quot;AllDevices&quot;</span>:
            BluetoothDeviceServicesManager workerBTMgr = <span class="kwrd">new</span> BluetoothDeviceServicesManager();
            List&lt;Device&gt; Devices = workerBTMgr.DiscoverAllDevices();
            _parentForm.Invoke(_parentForm.ThreadUpdateDiscoverBox, <span class="kwrd">new</span> <span class="kwrd">object</span>[] { Devices });
            <span class="kwrd">break</span>;
    }
}</pre>
<p>Both of these methods require that the device you are scanning for is in discoverable mode (which most manufacturers enable by default).&nbsp; Using the two methods described above I was able to tell if a device is in proximity. And ultimately enabling me create
 alerts and execute programs based on what device is present. </p>
<p>To perform device discovery and not have my UI lag I had to create two worker threads.&nbsp; One worker thread to discover all devices and display it under my devices listbox, and another to discover devices by name specified in the “watchlist.”&nbsp; I am not an
 expert at multi-threaded programs but I managed to implement them without any major headaches.</p>
<h3>User Interface:</h3>
<p>Since the “Add to watchlist” and “Edit” buttons essentially do the same thing, I decided to overload a windows form.&nbsp; I also wanted to keep track of the parent form and disable it when the WatchItemForm was shown.
</p>
<p>The second overload allows me to fill in the form control's text based on the data that is already set for the WatchItem that has been selected (the Edit button).&nbsp;
</p>
<pre class="csharpcode"><span class="kwrd">public</span> WatchItemForm(Form1 f, String DeviceName)
{
    InitializeComponent();
    <span class="kwrd">this</span>._parentForm = f;
    lblDeviceName.Text = DeviceName;
}

<span class="kwrd">public</span> WatchItemForm(Form1 f, WatchItem item)
{
    InitializeComponent();
    <span class="kwrd">this</span>._parentForm = f;

    lblDeviceName.Text = item.DeviceName;
    tbxPicturePath.Text = item.ImagePath;
    tbxProgramPath.Text = item.ProgramPath;
    <span class="kwrd">this</span>._parentForm.Enabled = <span class="kwrd">true</span>;
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>I wanted to have a pop up notify window similar to outlook and was able to find Robert Misiak's
<a href="http://www.codeproject.com/KB/miscctrl/RobMisNotifyWindow.aspx">NotifyWindow</a>. This is a very simple library which allows you to create pop up notify windows very easily. I edited
<strong>NotifyWindow</strong> to include a “picturepath” variable as well as picturebox on the form. As you can see creating a
<strong>NotifyWindow</strong> is quite easy:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> NotifyDeviceWindow(WatchItem x)
{
    NotifyWindow nw;
    nw = <span class="kwrd">new</span> NotifyWindow();
    <span class="rem">//validate Alert Message</span>
    <span class="kwrd">if</span> (x.AlertMessage == <span class="kwrd">null</span>)
    {
        nw.Text = x.DeviceName;
    }
    <span class="kwrd">else</span>
    {
        nw.Text = x.AlertMessage;
    }
    <span class="rem">//validate picture</span>
    <span class="kwrd">if</span> (x.ImagePath != <span class="kwrd">null</span>)
    {
        FileInfo imgfile = <span class="kwrd">new</span> FileInfo(x.ImagePath);
        <span class="kwrd">if</span> (imgfile.Exists)
        {
            nw.PicturePath = x.ImagePath;
        }
        <span class="kwrd">else</span>
        {
            MessageBox.Show(<span class="str">&quot;Image does not exist&quot;</span>);
        }
    }
    nw.Notify();

    <span class="kwrd">if</span> (x.ProgramPath != <span class="kwrd">null</span>)
    {
        RunProcess(x.ProgramPath);
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>Process Flow/Software Operation:</strong></p>
<ol>
<li>User clicks the “Discover” button, a thread is spawned which enumerates all Bluetooth devices in proximity
</li><li>Thread finishes and updates the Devices listbox </li><li>User selects a discovered device and clicks “Add to watchlist” A watch item form is spawned and asks you for an alert message, a picture path, and an executable path
</li><li>User clicks save , a WatchItem object is created and added to the watchList object
</li><li>A timer starts and every 10 seconds a thread is spawned to discover that device by name
</li><li>If the device is discovered, it is added to the “deviceSeenList” and a notify alert is sent and the executable is executed.
</li><li>If that device is still present after the next timer click, no notification is sent, If that device is not present it is removed from the “deviceSeenList”
</li></ol>
<h3>Screenshots:</h3>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbmain1.jpg"><img title="bb-main[1]" height="319" alt="bb-main[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbmain1_thumb.jpg" width="470" border="0"></a>&nbsp;&nbsp;
<br>
&nbsp;<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbwatchitem1.jpg"><img title="bb-watchitem[1]" height="210" alt="bb-watchitem[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbwatchitem1_thumb.jpg" width="257" border="0"></a>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbnotify_11.jpg"><img title="bb-notify_1[1]" height="173" alt="bb-notify_1[1]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8658548/bbnotify_11_thumb.jpg" width="226" border="0"></a>
</p>
<ol>
</ol>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:ae26329a3b09479683289e7600cf21c3">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/BlueBoss-Bluetooth-Proximity-Detection</comments>
      <itunes:summary>
Summary:
Bluetooth is now found in a variety of devices and enable the user to use wireless accessories.&amp;nbsp; The Bluetooth protocol allows a user to “discover” any device that is in proximity to your Bluetooth radio.&amp;nbsp; Why not see who is in proximity
 to you?&amp;nbsp; Why not have the presence of a device execute programs or alert you? 
Andy Konkol – http://copyandwaste.com 
&amp;nbsp; 
Hardware: 


Bluetooth radio (USB dongle) 

SMA Female Jack 

SMA male to N-male pigtail 

2.4 GHz antenna (with N-female connector) 

Software: 


Coding4fun Developer Kit 

Robert Misiak&#39;s Notify Window 

Download:  


Source / Binary Download 

 
Bluetooth and Hardware:

Bluetooth was designed for devices to communicate wirelessly over short distances.&amp;nbsp; However, with a very simple hardware modification you can extend the range of your Bluetooth radio with standard 2.4ghz antennas used in wireless networking
 (802.11 a/b/g).  
Modifying Bluetooth dongles to accept external antennas is documented all over the Internet.&amp;nbsp; In principle it is very easy: find the antenna lead and solder on a connector/antenna.&amp;nbsp; I purchased a very cheap Bluetooth USB dongle on eBay and opened the casing.&amp;nbsp;
 After finding the antenna trace on the circuit board I soldered on a SMA Female connector to it.&amp;nbsp; After soldering the antenna jack in place I slipped a 3 inch chunk of heatshrink and heated it to cover the exposed circuit board.&amp;nbsp; Now I had a Bluetooth radio
 that accepts external antennas. Adding an antenna simply increases the range of your radio, allowing you to “see” devices from a farther distance.
 
To connect an external antenna to the dongle I needed to use a connector converter called a pigtail.&amp;nbsp; I used a SMA male to N-male pigtail.&amp;nbsp; I connected one end of the pigtail to my dongle and the other to an omni-directional 9dbi panel antenna that had an
 N-female connector. 


 
Software:

To take advantage of my newly modified hardware I needed to download the </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/BlueBoss-Bluetooth-Proximity-Detection</link>
      <pubDate>Thu, 26 Jun 2008 19:09:42 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/BlueBoss-Bluetooth-Proximity-Detection</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8658548_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8658548_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Andy Konkol</dc:creator>
      <itunes:author>Andy Konkol</itunes:author>
      <slash:comments>12</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/BlueBoss-Bluetooth-Proximity-Detection/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Productivity</category>
      <category>utility</category>
      <category>Windows</category>
    </item>
  <item>
      <title>Microsoft Word Productivity Tips</title>
      <description><![CDATA[ <p>I love little productivity tips that help me do things faster and more efficiently, so I really enjoyed <a href="http://webworkerdaily.com/2008/03/25/quick-ways-to-be-more-efficient-in-ms-word/">this blog post over at Web Worker Daily</a>. Samuel gathered some of his favorite keyboard shortcuts for Microsoft Word, like <strong>Ctrl&#43;Shift&#43;C</strong> to copy and <strong>Ctrl&#43;Shift&#43;V</strong> to paste formatting and <strong>Ctrl &#43; Shift</strong> to select all text between the current location of your cursor and the end of the current paragraph. </p><p>His list was short and sweet, but it was no match for the super massive list of all shortcuts for Word 2002, Word 2003, and Word 2007 found <a href="http://support.microsoft.com/kb/290938">here</a>. Wow, you really don't even need a mouse, do you?</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:7f4fbf902f6649aa83ae9e0e0096548a">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Microsoft-Word-Productivity-Tips</comments>
      <itunes:summary> I love little productivity tips that help me do things faster and more efficiently, so I really enjoyed this blog post over at Web Worker Daily. Samuel gathered some of his favorite keyboard shortcuts for Microsoft Word, like Ctrl&amp;#43;Shift&amp;#43;C to copy and Ctrl&amp;#43;Shift&amp;#43;V to paste formatting and Ctrl &amp;#43; Shift to select all text between the current location of your cursor and the end of the current paragraph.  His list was short and sweet, but it was no match for the super massive list of all shortcuts for Word 2002, Word 2003, and Word 2007 found here. Wow, you really don&#39;t even need a mouse, do you? </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Microsoft-Word-Productivity-Tips</link>
      <pubDate>Mon, 07 Apr 2008 16:46:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Microsoft-Word-Productivity-Tips</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_40dcce7e-2814-4c5f-87a8-27dbca0d937e.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_b2c7bc5c-9907-4bab-b256-896755fb0fda.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Microsoft-Word-Productivity-Tips/RSS</wfw:commentRss>
      <category>Office</category>
      <category>Productivity</category>
      <category>Word</category>
    </item>
  <item>
      <title>Getting a List of Filenames in Vista is Easy!</title>
      <description><![CDATA[Remember what a challenge it was to generate a list of filenames of all the files in a folder on your PC? In XP, you had to go to the command prompt and type in something like <strong>DIR /B /ON *.* &gt; filelist.txt</strong>. (That command sorts them in order). In Vista, it's so much easier. Now, all you have to do is select the files, right-click, and choose &quot;Copy as Path.&quot; Paste the list anywhere. Of course, this does copy the entire path to the file, but Find-and-Replace can quickly take care of that. It's the little things like this that really make my day. (Thanks to <a href="http://www.appscout.com/2008/03/get_a_list_of_filenames.php">AppScout</a> for reminding me of this!) <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:4f428745f6424c5e88849e0e00964d37">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Getting-a-List-of-Filenames-in-Vista-is-Easy</comments>
      <itunes:summary>Remember what a challenge it was to generate a list of filenames of all the files in a folder on your PC? In XP, you had to go to the command prompt and type in something like DIR /B /ON *.* &amp;gt; filelist.txt. (That command sorts them in order). In Vista, it&#39;s so much easier. Now, all you have to do is select the files, right-click, and choose &amp;quot;Copy as Path.&amp;quot; Paste the list anywhere. Of course, this does copy the entire path to the file, but Find-and-Replace can quickly take care of that. It&#39;s the little things like this that really make my day. (Thanks to AppScout for reminding me of this!)</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Getting-a-List-of-Filenames-in-Vista-is-Easy</link>
      <pubDate>Fri, 28 Mar 2008 13:30:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Getting-a-List-of-Filenames-in-Vista-is-Easy</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_ff603640-8b3d-4fee-bd11-dab3e15ae7f8.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_ca1f535a-5394-4c51-9460-66771fa7b2ff.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Getting-a-List-of-Filenames-in-Vista-is-Easy/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Tips</category>
      <category>Windows Vista</category>
    </item>
  <item>
      <title>Vista Keyboard Shortcuts</title>
      <description><![CDATA[I'd play keyboard shortcut Jeopordy with anybody. As a long time shortcut user, I can get by without a mouse - dropdowns, checkboxes, tabs &nbsp;- no problem. Of course, I got to this point by working on computers with problems (and usually no working mouse). <br><br>Then Channel 8's&nbsp;<a href="http://channel8.msdn.com/People/Max/">Max Zuckerman</a> came into my office and minimized everything to desktop simply by laying hands on my keyboard. Turns out what Max was doing was hitting Windows&#43;3 on my keyboard, which launches the third item in your Quick Launch bar (just to the right of the start button), in this case - Show Desktop. <br><br>I realized I have shortcuts to learn yet, and set out to find all of them. There are two sites you should spend time with if you want to be a shortcut power user. The first is <a href="http://itsvista.com/windows-vista-keyboard-shortcuts/#kb3">this shortcut list at ItsVista.com</a>, the second is&nbsp;<a href="http://windowshelp.microsoft.com/Windows/en-US/Help/2503b91d-d780-4c80-8f08-2f48878dc5661033.mspx">this Windows Help</a> site.&nbsp;Knowing these can save you a lot of time in the course of a day, especially if you're out of batteries with your cordless mouse. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:c5b9d2aba2e049778d4e9e0f010429b6">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/All-your-Vista-keyboard-shortcut</comments>
      <itunes:summary>I&#39;d play keyboard shortcut Jeopordy with anybody. As a long time shortcut user, I can get by without a mouse - dropdowns, checkboxes, tabs &amp;nbsp;- no problem. Of course, I got to this point by working on computers with problems (and usually no working mouse). Then Channel 8&#39;s&amp;nbsp;Max Zuckerman came into my office and minimized everything to desktop simply by laying hands on my keyboard. Turns out what Max was doing was hitting Windows&amp;#43;3 on my keyboard, which launches the third item in your Quick Launch bar (just to the right of the start button), in this case - Show Desktop. I realized I have shortcuts to learn yet, and set out to find all of them. There are two sites you should spend time with if you want to be a shortcut power user. The first is this shortcut list at ItsVista.com, the second is&amp;nbsp;this Windows Help site.&amp;nbsp;Knowing these can save you a lot of time in the course of a day, especially if you&#39;re out of batteries with your cordless mouse.</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/All-your-Vista-keyboard-shortcut</link>
      <pubDate>Tue, 18 Mar 2008 19:52:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/All-your-Vista-keyboard-shortcut</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_e4197e44-3446-4e47-bc09-7c82213a03b4.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_b466d9d0-f774-41ae-b997-3e23465cd7e4.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/All-your-Vista-keyboard-shortcut/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Vista</category>
      <category>Windows Vista</category>
    </item>
  <item>
      <title>A Better Startup Experience</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/flag.png"><img height="52" alt="flag" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/flag_thumb.png" width="52" border="0"></a>
</td>
<td><span class="entry_description">Does Windows take too long starting up before you can get to work?&nbsp; Wouldn't it better if things could startup at a lower priority?&nbsp; Learn how to launch processes, use performance counters, monitor files, and run tasks in
 the background.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Arian Kulp</div>
<div class="entry_company"><a href="http://www.ariankulp.com">Arian's Blog</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><span class="entry_details_input"><b>Hardware: </b>None</span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=390525">C# Download</a>
</li><li><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=390526">VB Download</a>
</li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/surfacePuzzleDemoVB.zip"></a></p>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff;
	overflow:auto}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h2>Introduction</h2>
<p>Starting up Windows usually takes longer than I'd like it to.&nbsp; It seems like the system is churning away for ages.&nbsp; I've often thought that it would make more sense to wait as each item starts up before starting the next item.&nbsp; The problem is Windows has
 no idea how long an application takes to initialize itself.&nbsp; After launching it, it's just another running process.&nbsp; It would be nice to be able to configure a delay after each application so it can perform its potentially expensive startup before another
 application starts.&nbsp; I decided to put this idea into action.</p>
<p>This application requires Visual Studio 2005 Express Editions (C# or Visual Basic) or higher.&nbsp; This will be my last Coding 4 Fun article targeting Visual Studio 2005.&nbsp; If you haven't downloaded a Visual Studio 2008 Express Edition yet, definitely check them
 out.&nbsp; The upgrade is very much worth it!</p>
<h2>Starting Up</h2>
<p>The basic idea of the program is very simple: launch each startup item with a configurable delay between each one.&nbsp; Beyond a simple delay though, it might be good to see how active the system is.&nbsp; If the CPU is working hard, maybe it would be good to wait
 until it settles down before launching something else.</p>
<p>In case you've never looked closely, there are a few ways that Windows knows what to startup with the system.&nbsp; The three most common ways to start things are by using the Registry, the Startup folder, or by configuring services.&nbsp; The Registry and Startup
 folder methods are pretty similar.&nbsp; Of course Services are background processes that run even if a user isn't logged in.</p>
<p>Once a user logs in, the Registry and Startup folders take effect.&nbsp; The system Registry is a collection of keys, values, and data that applications (and Windows itself) use for configuration.&nbsp; One such use is to contain a list of programs to launch with
 Windows.&nbsp; There is a system-level and user-level list.&nbsp; System-level programs are started up for every user that logs in, while user-level programs are started only for the specific user.</p>
<p>The Startup folder works the same way.&nbsp; As part of each user's profile folder there is a Startup folder.&nbsp; There is also one at the Default User level.&nbsp; These folders contain shortcuts to applications.&nbsp; Whenever a user logs in, all of these shortcuts are
 launched.&nbsp; We just need to take over this process.&nbsp; To do this though, we'll need to take the shortcuts out of the system Startup folders.</p>
<h2>The Basics</h2>
<p>The Startup Optimizer works by scanning the user's <strong>Startup </strong>folder looking for shortcuts.&nbsp; As a new shortcut is found, a
<strong>StartupEntry </strong>object is created.&nbsp; This object holds the filename, a display name and a few flags.&nbsp; The key flag is
<strong>Managed</strong>.&nbsp; An object with <strong>Managed </strong>set to <strong>
True</strong> is launched by the application and moved to a new <strong>ManagedStartup
</strong>folder in the user's profile.</p>
<p>When a file or shortcut is detected in the <strong>Startup </strong>folder, a popup will occur to let a user decide if the program should manage it or not.&nbsp; If so, it moves the shortcut to its
<strong>ManagedStartup </strong>folder.&nbsp; If not, it leaves it alone but sets the <strong>
Managed </strong>flag to <strong>False</strong>.&nbsp; Next time it notices the same shortcut, it will just now to ignore it and let Windows handle it.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/image.png"><img height="160" alt="Startup Item Encountered" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/image_thumb.png" width="385" border="0"></a></p>
<p align="center"><em>Figure 1: The dialog shown when a startup item is found</em></p>
<p>If you click the button to show the advanced options, you can specify a display name, the low CPU flag, and how to long to wait before launching the next application.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/image_3.png"><img height="256" alt="Startup Item Encountered - Advanced Settings" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/image_thumb_3.png" width="385" border="0"></a></p>
<p align="center"><em>Figure 2: The dialog with advanced settings shown</em>&nbsp;</p>
<p>Notice the icon.&nbsp; There's no included support for extracting the icon from a file, but you can use the Win32
<strong>SHGetFileInfo</strong> function in the <strong>shell32.dll</strong> library like so:</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">&lt;DllImport(<span class="str">&quot;shell32.dll&quot;</span>)&gt; _
<span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> SHGetFileInfo(<span class="kwrd">ByVal</span> pszPath <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> dwFileAttributes <span class="kwrd">As</span> UInteger, <span class="kwrd">ByRef</span> psfi <span class="kwrd">As</span> SHFILEINFO, <span class="kwrd">ByVal</span> cbSizeFileInfo <span class="kwrd">As</span> UInteger, <span class="kwrd">ByVal</span> uFlags <span class="kwrd">As</span> UInteger) <span class="kwrd">As</span> IntPtr
<span class="kwrd">End</span> Function</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">[DllImport(<span class="str">&quot;shell32.dll&quot;</span>)] 
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">extern</span> IntPtr SHGetFileInfo(<span class="kwrd">string</span> pszPath, <span class="kwrd">uint</span> dwFileAttributes,
       <span class="kwrd">ref</span> SHFILEINFO psfi, <span class="kwrd">uint</span> cbSizeFileInfo, <span class="kwrd">uint</span> uFlags);</pre>
<p>All <strong>StartupEntry</strong> objects are added to the <strong>StartupEntryList</strong> collection which is a subclass of
<strong>List&lt;StartupEntry&gt;</strong>.&nbsp; Creating a subclass like this allows you to add helper methods for finding or removing objects or other useful functions.&nbsp; This collection is what is saved to disk to retain the properties of each item.&nbsp; The basic .NET
 binary serialization method is used due to its simplicity in code.&nbsp; Note that any class to be serialized must be decorated with the
<strong>Serializable </strong>attribute.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> FromDisk() <span class="kwrd">As</span> StartupEntryList
    <span class="kwrd">If</span> <span class="kwrd">Not</span> File.Exists(<span class="str">&quot;StartupEntryList.ser&quot;</span>) <span class="kwrd">Then</span>
        <span class="kwrd">Return</span> <span class="kwrd">New</span> StartupEntryList()
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">Dim</span> c <span class="kwrd">As</span> StartupEntryList
    <span class="kwrd">Dim</span> s <span class="kwrd">As</span> Stream = File.Open(<span class="str">&quot;StartupEntryList.ser&quot;</span>, FileMode.Open)
    <span class="kwrd">Dim</span> b <span class="kwrd">As</span> <span class="kwrd">New</span> BinaryFormatter()
    c = <span class="kwrd">DirectCast</span>(b.Deserialize(s), StartupEntryList)

    s.Close()

    <span class="kwrd">Return</span> c
<span class="kwrd">End</span> <span class="kwrd">Function</span>

<span class="kwrd">Public</span> <span class="kwrd">Sub</span> SaveToDisk()
    <span class="kwrd">Dim</span> s <span class="kwrd">As</span> Stream = File.Open(<span class="str">&quot;StartupEntryList.ser&quot;</span>, FileMode.Create)
    <span class="kwrd">Dim</span> b <span class="kwrd">As</span> <span class="kwrd">New</span> BinaryFormatter()
    b.Serialize(s, <span class="kwrd">Me</span>)
    s.Close()
<span class="kwrd">End</span> Sub</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> StartupEntryList FromDisk() 
{ 
    <span class="kwrd">if</span> (!File.Exists(<span class="str">&quot;StartupEntryList.ser&quot;</span>)) <span class="kwrd">return</span> <span class="kwrd">new</span> StartupEntryList(); 

    StartupEntryList c; 
    Stream s = File.Open(<span class="str">&quot;StartupEntryList.ser&quot;</span>, FileMode.Open); 
    BinaryFormatter b = <span class="kwrd">new</span> BinaryFormatter(); 
    c = (StartupEntryList)b.Deserialize(s); 

    s.Close(); 

    <span class="kwrd">return</span> c; 
} 

<span class="kwrd">public</span> <span class="kwrd">void</span> SaveToDisk() 
{ 
    Stream s = File.Open(<span class="str">&quot;StartupEntryList.ser&quot;</span>, FileMode.Create); 
    BinaryFormatter b = <span class="kwrd">new</span> BinaryFormatter(); 
    b.Serialize(s, <span class="kwrd">this</span>); 
    s.Close(); 
} </pre>
<p>Notice how the <strong>FromDisk()</strong> method is static.&nbsp; This works as a factory method on the
<strong>StartupEntryList </strong>class itself.&nbsp; Subclassing that simple generic list has made it easy to encapsulate all related functionality into the same place.</p>
<h2>Working in the Background</h2>
<h2></h2>
<h2></h2>
<p>Of course at some point the application needs to perform its startup magic.&nbsp; Obviously the main work is just launching each shortcut.&nbsp; This is done using the
<strong>Process.Start()</strong> method in the <strong>System.Diagnostics</strong> namespace.&nbsp; If we were just launching the shortcuts one after another, it would be over quickly, but it would defeat the purpose of the program!&nbsp; With delays and waiting for
 the CPU to go idle, this startup process could potentially take a few minutes.&nbsp; This is important because it means that we can't just start the sequence in the
<strong>Form_Load </strong>event handler on startup.&nbsp; The application would be unresponsive and there would be no way to abort.</p>
<p>Enter the <strong>BackgroundWorker </strong>class.&nbsp; I've used this in articles before and they make it really easy to run things in the background.&nbsp; It's much easier than creating threads -- especially if you need to update the user interface.&nbsp; You get to
 avoid the <strong>Invoke</strong> calls that are otherwise required and you even get Form Designer support.</p>
<p>Similar to the <strong>StartupEntryList</strong>, subclassing is a good idea in order to keep things nicely encapsulated.&nbsp; There's actually only one method that matters in this case: the event handler for the
<strong>DoWork </strong>event.&nbsp; This is where work is done.&nbsp; You never call it directly (it's marked
<strong>private</strong>) -- it's invoked when the <strong>RunWorkerAsync </strong>
method is called.&nbsp; Anything that happens in the event handler is automatically on a thread other than the UI thread.&nbsp; It couldn't be simpler!&nbsp; In order to cause the UI to be updated (you can't ever directly reference it due to cross-threading concerns) call
 the <strong>ReportProgress </strong>method.&nbsp; Periodically check the <strong>CancellationPending
</strong>flag to see if you need to exit.</p>
<p>The <strong>StartupBackgroundWorker_DoWork </strong>event handler method basically just iterates over the entries that have
<strong>Managed </strong>set to true, waits for an idle CPU if necessary, and waits the specified delay time if set before moving to the next one.&nbsp; At several points it checks to see if a cancellation has been requested.&nbsp; The best thing though, is regardless
 of how long the sequence takes the UI will run smoothly.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">    Private Sub StartupBackgroundWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim entries As List(Of StartupEntry) = TryCast(e.Argument, List(Of StartupEntry))

        If entries Is Nothing OrElse entries.Count = 0 Then
            e.Cancel = True
            Throw New Exception(<span class="str">&quot;No entries passed in&quot;</span>)
        End If

        Try
            <span class="str">' Don'</span>t bother <span class="kwrd">if</span> there aren<span class="str">'t any entries!
            If entries.Count &gt; 0 Then
                Me.ReportProgress(0, &quot;Startup Optimizer will begin in five seconds.  Click to cancel.&quot;)
                Dim i As Integer = 0
                While i &lt; 5 AndAlso Not Me.CancellationPending
                    Thread.Sleep(1000)
                    i &#43;= 1
                End While

                If Me.CancellationPending Then
                    e.Cancel = True
                    Return
                End If
            End If

            systemIdleComponent1.Enabled = True

            '</span> Process entries to perform startup
            For Each entry As StartupEntry In entries
                If entry.Managed Then
                    If entry.WaitForLowCPU Then
                        Me.ReportProgress(0, <span class="str">&quot;Waiting for idle CPU to launch: &quot;</span> &#43; entry.DisplayName)

                        <span class="str">' CPU wait routine...
                        '</span> TODO: Give up <span class="kwrd">if</span> we never go idle?  This would be the place..!
                        While Not systemIdleComponent1.WaitForIdle(1000)
                            If Me.CancellationPending Then
                                e.Cancel = True
                                Return
                            End If
                        End While
                    End If

                    Me.ReportProgress(0, <span class="str">&quot;Starting: &quot;</span> &#43; entry.DisplayName)

                    <span class="str">' Don'</span>t actually start <span class="kwrd">if</span> we are debugging
                    If Not Debugger.IsAttached Then
                        Process.Start(Path.Combine(My.Settings.ManagedStartupPath, entry.FileName))
                    Else
                        <span class="str">'SIMULATE STARTUP DELAY
                        Thread.Sleep(2000)
                    End If

                    Me.ReportProgress(0, &quot;Started: &quot; &#43; entry.DisplayName)

                    If entry.DelayTime &gt; 0 Then
                        Me.ReportProgress(0, &quot;Waiting: &quot; &#43; entry.DelayTime &#43; &quot; seconds until next item&quot;)
                        For x As Integer = 0 To entry.DelayTime - 1

                            '</span> Wait the number of seconds but check <span class="kwrd">for</span> cancel flag each second
                            If Me.CancellationPending Then
                                e.Cancel = True
                                Return
                            End If

                            Thread.Sleep(1000)
                        Next
                    End If
                End If
            Next
        Catch
            e.Cancel = True
        Finally
            systemIdleComponent1.Enabled = False
        End Try

    End Sub</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> StartupBackgroundWorker_DoWork(<span class="kwrd">object</span> sender, DoWorkEventArgs e)
{
    List&lt;StartupEntry&gt; entries = e.Argument <span class="kwrd">as</span> List&lt;StartupEntry&gt;;

    <span class="kwrd">if</span> (entries == <span class="kwrd">null</span> || entries.Count == 0 )
    {
        e.Cancel = <span class="kwrd">true</span>;
        <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="str">&quot;No entries passed in&quot;</span>);
    }

    <span class="kwrd">try</span>
    {
        <span class="rem">// Don't bother if there aren't any entries!</span>
        <span class="kwrd">if</span> (entries.Count &gt; 0)
        {
            <span class="kwrd">this</span>.ReportProgress(0, <span class="str">&quot;Startup Optimizer will begin in five seconds.  Click to cancel.&quot;</span>);
            <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; 5 &amp;&amp; !<span class="kwrd">this</span>.CancellationPending; i&#43;&#43;)
                Thread.Sleep(1000);

            <span class="kwrd">if</span> (<span class="kwrd">this</span>.CancellationPending)
            {
                e.Cancel = <span class="kwrd">true</span>;
                <span class="kwrd">return</span>;
            }
        }

        systemIdleComponent1.Enabled = <span class="kwrd">true</span>;

        <span class="rem">// Process entries to perform startup</span>
        <span class="kwrd">foreach</span> (StartupEntry entry <span class="kwrd">in</span> entries)
        {
            <span class="kwrd">if</span> (entry.Managed)
            {
                <span class="kwrd">if</span> (entry.WaitForLowCPU)
                {
                    <span class="kwrd">this</span>.ReportProgress(0, <span class="str">&quot;Waiting for idle CPU to launch: &quot;</span> &#43; entry.DisplayName);

                    <span class="rem">// CPU wait routine...</span>
                    <span class="rem">// TODO: Give up if we never go idle?  This would be the place..!</span>
                    <span class="kwrd">while</span>( !systemIdleComponent1.WaitForIdle(1000) )
                    {
                        <span class="kwrd">if</span> (<span class="kwrd">this</span>.CancellationPending)
                        {
                            e.Cancel = <span class="kwrd">true</span>;
                            <span class="kwrd">return</span>;
                        }
                    }
                }

                <span class="kwrd">this</span>.ReportProgress(0, <span class="str">&quot;Starting: &quot;</span> &#43; entry.DisplayName);

                <span class="rem">// Don't actually start if we are debugging</span>
                <span class="kwrd">if</span>( !Debugger.IsAttached)
                    Process.Start(Path.Combine(Properties.Settings.Default.ManagedStartupPath, entry.FileName));
                <span class="kwrd">else</span>
                    Thread.Sleep(2000); <span class="rem">//SIMULATE STARTUP DELAY</span>

                <span class="kwrd">this</span>.ReportProgress(0, <span class="str">&quot;Started: &quot;</span> &#43; entry.DisplayName);

                <span class="kwrd">if</span> (entry.DelayTime &gt; 0)
                {
                    <span class="kwrd">this</span>.ReportProgress(0, <span class="str">&quot;Waiting: &quot;</span> &#43; entry.DelayTime &#43; <span class="str">&quot; seconds until next item&quot;</span>);

                    <span class="rem">// Wait the number of seconds but check for cancel flag each second</span>
                    <span class="kwrd">for</span> (<span class="kwrd">int</span> x = 0; x &lt; entry.DelayTime; x&#43;&#43;)
                    {
                        <span class="kwrd">if</span> (<span class="kwrd">this</span>.CancellationPending)
                        {
                            e.Cancel = <span class="kwrd">true</span>;
                            <span class="kwrd">return</span>;
                        }

                        Thread.Sleep(1000);
                    }
                }
            }
        }
    }
    <span class="kwrd">catch</span>
    {
        e.Cancel = <span class="kwrd">true</span>;
    }
    <span class="kwrd">finally</span>
    {
        systemIdleComponent1.Enabled = <span class="kwrd">false</span>;
    }

}</pre>
<p>There are a few things to callout in this block.&nbsp; I have a few sanity checks in there to be sure that the list isn't NULL or empty.&nbsp; Defensive programming is always a good idea!&nbsp; Notice also that I have pauses built in with the
<strong>Thread.Sleep() </strong>command.&nbsp; Where it would be convenient to pause for several seconds, it would render the thread unresponsive if a cancellation was requested.&nbsp; Note that cancellation is completely passive.&nbsp; The framework doesn't ever abort your
<strong>BackgroundWorker</strong>.&nbsp; It's up to your code to catch it if cancellation is requested.&nbsp; So for pauses, I wait a second, check the flag, and repeat for the number of seconds.&nbsp; The code is slightly bulky but it works well.</p>
<p>Notice also how I don't launch the startup applications if <strong>System.Diagnostics.Debugger.IsAttached
</strong>is true.&nbsp; When I'm troubleshooting/testing, I don't really want the applications launching every time!&nbsp; It's a simple check to see if the application is currently being debugged (as in Visual Studio).</p>
<h2>Detecting Idleness</h2>
<p>In addition to the simple time-based delays, I also wanted the option to wait for the system to be idle before launching applications.&nbsp; There's no direct way to see this though, so I created the
<strong>SystemIdleComponent</strong>.&nbsp; This is completely modular and could be plugged into other applications easily.&nbsp; It all comes down to system Performance Counters.&nbsp; If you've never worked with these before, don't let them intimidate you.&nbsp; They're actually
 very easy to work with.&nbsp; From the Visual Studio Toolbox you can easily drag a counter and set its properties (category, counter,and instance), but unfortunately there's no support for events when the value changes.&nbsp; A pretty big deal I think!</p>
<p>My component builds on the <strong>PerformanceCounter </strong>object and creates a
<strong>System.Threading.Timer </strong>object behind the scenes to monitor the state of the counter periodically.&nbsp; If a change is measured and it falls outside of the tolerance limits, it raises an event.&nbsp; It also raises an event when it returns to the tolerance.&nbsp;
 This allows you to receive an event both when the system becomes idle and when it returns to non-idle.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">    <span class="kwrd">Private</span> <span class="kwrd">Sub</span> timerCpu_Tick(<span class="kwrd">ByVal</span> state <span class="kwrd">As</span> <span class="kwrd">Object</span>)
        <span class="kwrd">Dim</span> currentValue <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 100 - <span class="kwrd">CInt</span>(performanceCounterProcessorIdle.NextValue())

        <span class="rem">' If we are below the threshold, start counting...</span>
        <span class="kwrd">If</span> currentValue &lt;= _thresholdIdlePercent <span class="kwrd">Then</span>
            idleTimer.Start()
        <span class="kwrd">Else</span>
            idleTimer.[<span class="kwrd">Stop</span>]()
            idleTimer.Reset()
        <span class="kwrd">End</span> <span class="kwrd">If</span>


        <span class="rem">' See if we've been idle long enough</span>
        <span class="kwrd">If</span> idleTimer.ElapsedMilliseconds / 1000 &gt; _thresholdIdleTime <span class="kwrd">Then</span>
            <span class="rem">' We've just gone idle</span>
            RaiseIdleEvent()
        <span class="kwrd">Else</span>
            <span class="rem">' We are not idle</span>
            LowerIdleEvent()
        <span class="kwrd">End</span> <span class="kwrd">If</span>

        _lastCpuValue = <span class="kwrd">CInt</span>(currentValue)
    <span class="kwrd">End</span> Sub</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> timerCpu_Tick(<span class="kwrd">object</span> state)
{
    <span class="kwrd">int</span> currentValue = 100 - (<span class="kwrd">int</span>)performanceCounterProcessorIdle.NextValue();

    <span class="rem">// If we are below the threshold, start counting...</span>
    <span class="kwrd">if</span> (currentValue &lt;= _thresholdIdlePercent)
        idleTimer.Start();
    <span class="kwrd">else</span>
    {
        idleTimer.Stop();
        idleTimer.Reset();
    };

    <span class="rem">// See if we've been idle long enough</span>
    <span class="kwrd">if</span> (idleTimer.ElapsedMilliseconds / 1000 &gt; _thresholdIdleTime)
    {
        <span class="rem">// We've just gone idle</span>
        RaiseIdleEvent();
    }
    <span class="kwrd">else</span>
    {
        <span class="rem">// We are not idle</span>
        LowerIdleEvent();
    }

    _lastCpuValue = (<span class="kwrd">int</span>)currentValue;
}</pre>
<p>What is idle?&nbsp; This is defined by properties <strong>ThresholdIdlePercent </strong>
and <strong>ThresholdIdleTime</strong>.&nbsp; The statement is &quot;the system is idle when it has been at {ThresholdIdlePercent}% for {ThresholdIdleTime} seconds.&quot;&nbsp; A consuming application just sets the properties and subscribes to events.&nbsp; Alternately, you can check
 the <strong>SystemIdle </strong>property when you need to.&nbsp; A final way is to call
<strong>WaitForIdle </strong>with our without a timeout value.&nbsp; The call will not return until the system is idle.</p>
<p>This works by using an <strong>System.Threading.EventWaitHandle </strong>object.&nbsp; This very cool construct (system-based, not just .NET) lets two threads coordinate via a shared semaphore.&nbsp; The
<strong>BackgroundWorker </strong>thread goes to sleep until the <strong>SystemIdleComponent</strong>'s timer fires and detects an idle state.&nbsp; It can be dangerous to wait too long locked like this, so the worker will only call it for a second at a time in-between
 checking for a cancellation request.&nbsp; I've added additional attributes to this object to make it easier to reuse and for a good design-time experience.&nbsp; Drag it to your form and work with it like any other object.</p>
<h2>Usage</h2>
<p>It currently reads the user's <strong>Startup</strong> folder upon startup and shows the dialog to take action.&nbsp; There's no
<strong>Cancel </strong>button since it wouldn't make sense.&nbsp; If you want to cancel, chances are you really just don't want the application to manage that shortcut.&nbsp; It won't know that next time unless it creates an entry for it though.</p>
<p>Something to think about is that some applications are going to check the Startup folder every time they launch and add their shortcut if it isn't there.&nbsp; Once that
<strong>StartupEntry </strong>is in the <strong>StartupEntryList </strong>collection, the application will know what to do with it and you won't be prompted again.</p>
<p>A <strong>FileSystemWatcher </strong>object enables the application to see new shortcuts added.&nbsp; It then takes action only on shortcuts for which no
<strong>StartupEntry </strong>is found.&nbsp; You can modify the display name, delay, wait-for-idle flag, or the managed property at any time.&nbsp; Unless you're debugging, you won't have any way to execute the launch sequence except when it's initially started with
 the &quot;/startup&quot; command line flag.&nbsp; If you launch it without the flag it won't launch anything so it's safer that way.</p>
<p>There's not much else to worry about.&nbsp; Tell it which startup entries to manage, then let it do it's thing upon restarts.&nbsp; It could really exit after the list is complete, except that it wouldn't see new entries that way.</p>
<h2>Conclusion</h2>
<p>The application ended up taking considerably longer than I ever imagined it would!&nbsp; I tried to create a good experience while demonstrating some good concepts.&nbsp; I was surprised at some of the subtleties I ran into to make this work as well as it does.&nbsp; It's
 not perfect by any means, but it's a good start and it should be useable as-is.</p>
<p>I tried to keep things out of <strong>MainForm </strong>where it made sense, though there is still room for more encapsulation.&nbsp; Individual classes should always be fairly light-weight.&nbsp; It's the way that they interact with each other that provides their
 power.</p>
<h2>Next Steps</h2>
<p>For this article, you can use Visual Studio 2005 Express, or make the upgrade to Visual Studio 2008 Express.&nbsp; As I mentioned at the beginning, I'll be upgrading to VS2008 for future articles, and with the Express products being free, there's no reason not
 to upgrade today at <a title="http://www.microsoft.com/express/" href="http://www.microsoft.com/express/">
http://www.microsoft.com/express/</a>.</p>
<p>I left a number of <strong>TODO </strong>comments in the code.&nbsp; These were cool things that I just didn't have time to implement.&nbsp; For one thing, it would be good to be able to just drag an application to the main window to add it to the Managed Startup
 list.&nbsp; Even more useful would be scanning the Registry Current User (HKCU) Run list.&nbsp; Probably more entries end up there than the Startup folder.&nbsp; I'd also like to extend my
<strong>SystemIdleComponent </strong>to be a generalized <strong>PerformanceCounter</strong> event broker.&nbsp; That would make it easy to add code to wait for low disk I/O in addition to CPU load.&nbsp; Finally, I really wanted to add entry reordering to specify which
 applications should have the higher priority of starting first.&nbsp; Not difficult, so give it a try!&nbsp; If you end up adding any interesting features, let me know.&nbsp; I'd love to see where it goes!</p>
<hr>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/Avatar80.jpg"><img height="84" alt="Arian Kulp" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8290797/Avatar80_thumb.jpg" width="74" align="left" border="0"></a>
<br>
Arian Kulp is an independent software developer and writer working in the Midwest.&nbsp; He has been coding since the fifth grade on various platforms, and also enjoys photography, nature, and spending time with his family.&nbsp; Arian can be reached through his web
 site at <a href="http://www.ariankulp.com">http://www.ariankulp.com</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:b3797fd56560427d973d9e7600d006c4">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/A-Better-Startup-Experience</comments>
      <itunes:summary>





Does Windows take too long starting up before you can get to work?&amp;nbsp; Wouldn&#39;t it better if things could startup at a lower priority?&amp;nbsp; Learn how to launch processes, use performance counters, monitor files, and run tasks in
 the background.



Arian Kulp
Arian&#39;s Blog

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: None
Download: 

C# Download
VB Download







 



Introduction
Starting up Windows usually takes longer than I&#39;d like it to.&amp;nbsp; It seems like the system is churning away for ages.&amp;nbsp; I&#39;ve often thought that it would make more sense to wait as each item starts up before starting the next item.&amp;nbsp; The problem is Windows has
 no idea how long an application takes to initialize itself.&amp;nbsp; After launching it, it&#39;s just another running process.&amp;nbsp; It would be nice to be able to configure a delay after each application so it can perform its potentially expensive startup before another
 application starts.&amp;nbsp; I decided to put this idea into action. 
This application requires Visual Studio 2005 Express Editions (C# or Visual Basic) or higher.&amp;nbsp; This will be my last Coding 4 Fun article targeting Visual Studio 2005.&amp;nbsp; If you haven&#39;t downloaded a Visual Studio 2008 Express Edition yet, definitely check them
 out.&amp;nbsp; The upgrade is very much worth it! 
Starting Up
The basic idea of the program is very simple: launch each startup item with a configurable delay between each one.&amp;nbsp; Beyond a simple delay though, it might be good to see how active the system is.&amp;nbsp; If the CPU is working hard, maybe it would be good to wait
 until it settles down before launching something else. 
In case you&#39;ve never looked closely, there are a few ways that Windows knows what to startup with the system.&amp;nbsp; The three most common ways to start things are by using the Registry, the Startup folder, or by configuring services.&amp;nbsp; The Registry and Startup
 fold</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/A-Better-Startup-Experience</link>
      <pubDate>Mon, 17 Mar 2008 12:55:47 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/A-Better-Startup-Experience</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8290797_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8290797_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>ArianKulp</dc:creator>
      <itunes:author>ArianKulp</itunes:author>
      <slash:comments>16</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/A-Better-Startup-Experience/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Windows</category>
    </item>
  <item>
      <title>Belkin 3-outlet + 2-USB adaptor</title>
      <description><![CDATA[I've spent the last two weeks in hotel rooms and continually juggled between lamp, clock, laptop,&nbsp;phone, and MP3 player(s)&nbsp;in the power outlet that was available. Then there is the ruthless power outlet jockeying that goes on in airports... Well, Belkin has a great solution for this in a&nbsp;<a href="http://catalog.belkin.com/IWCatProductPage.process?Product_Id=400738#">three outlet power adaptor</a> that has two built-in USB chargers on the side. It features a 360-degree rotating plug with a surge protector. Well worth the money at $24.99. <br>(via <a href="http://www.uncrate.com/men/gear/travel-luggage/belkin-mini-surge-protector-with-usb-charger/">Uncrate</a>)  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:76851f9ac0e64b4cb5e79e1000f76d71">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LarryLarsen/Belkin-3-outlet--2-USB-adaptor</comments>
      <itunes:summary>I&#39;ve spent the last two weeks in hotel rooms and continually juggled between lamp, clock, laptop,&amp;nbsp;phone, and MP3 player(s)&amp;nbsp;in the power outlet that was available. Then there is the ruthless power outlet jockeying that goes on in airports... Well, Belkin has a great solution for this in a&amp;nbsp;three outlet power adaptor that has two built-in USB chargers on the side. It features a 360-degree rotating plug with a surge protector. Well worth the money at $24.99. (via Uncrate) </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/LarryLarsen/Belkin-3-outlet--2-USB-adaptor</link>
      <pubDate>Mon, 17 Mar 2008 05:10:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LarryLarsen/Belkin-3-outlet--2-USB-adaptor</guid>      
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LarryLarsen/Belkin-3-outlet--2-USB-adaptor/RSS</wfw:commentRss>
      <category>Hardware</category>
      <category>Productivity</category>
      <category>Clean Computing</category>
    </item>
  <item>
      <title>PCWorld&#39;s 7 Office Optimizers</title>
      <description><![CDATA[ <p>As part of a PCWorld article entitled, &quot;<a href="http://www.pcworld.com/article/id,142706/article.html">50 Add-Ins and Utilities That Can Improve Your PC Experience</a>,&quot; there was a section on Office optimizers that I thought was really useful. The list included some great extras and tricks to do more with Office. Here are some highlights:</p><ul><li>Open Office 2007 files with older office versions via the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=941b3470-3ae9-4aee-8f43-c6bb74cd1466&amp;displaylang=en">Office Compatibility Pack</a> </li><li>Use <a href="http://www.pcworld.com/downloads/file/fid,66421-page,1-c,wordprocessing/description.html">CenoPDF</a> to build PDFs without ever having to leave Word, PowerPoint, or Excel. </li><li>Become a meeting power user with <a href="http://www.meetingsense.com/go/trialhome.aspx">MeetingSense</a>, which provides an extensive dashboard for meetings, agendas, creating minutes, etc. </li><li>Organize your data with <a href="http://www.clearcontext.com/download_thanks.html">ClearContext</a> (See? <a href="http://on10.net/Blogs/sarahintampa/how-i-use-outlook-7-tips/">I told you so</a>!) </li></ul><p>For the full list, check out the article at <a href="http://www.pcworld.com/article/id,142706-page,5-c,software/article.html">PCWorld</a>.</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:ea523306a15545888bc69e0d00e33db6">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/PCWorlds-7-Office-Optimizers</comments>
      <itunes:summary> As part of a PCWorld article entitled, &amp;quot;50 Add-Ins and Utilities That Can Improve Your PC Experience,&amp;quot; there was a section on Office optimizers that I thought was really useful. The list included some great extras and tricks to do more with Office. Here are some highlights: Open Office 2007 files with older office versions via the Office Compatibility Pack Use CenoPDF to build PDFs without ever having to leave Word, PowerPoint, or Excel. Become a meeting power user with MeetingSense, which provides an extensive dashboard for meetings, agendas, creating minutes, etc. Organize your data with ClearContext (See? I told you so!) For the full list, check out the article at PCWorld. </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/PCWorlds-7-Office-Optimizers</link>
      <pubDate>Thu, 28 Feb 2008 17:50:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/PCWorlds-7-Office-Optimizers</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_fbeaac6c-8652-4ba0-8858-84dc16e830b2.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_d47837ca-c0a9-4e2a-b5df-b208c7d1ec47.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/PCWorlds-7-Office-Optimizers/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Utilities</category>
      <category>utility</category>
    </item>
  <item>
      <title>Track FedEx in Outlook</title>
      <description><![CDATA[FedEx has released an application's called <a href="http://fedex.com/quickship/">FedEx QuickShip</a>, which allows you to easily create and track U.S. shipments, get rates, schedule pickups, and find the nearest staffed FedEx location – all without leaving Outlook! The app installs a FedEx QuickShip toolbar along the top of your Office Outlook window. The toolbar has eight buttons: FedEx, Ship, Track, Rate, Pickup, Find Locations, View History and Edit Settings. QuickShip also lets you right-click on a contact and select &quot;ship&quot; on the menu that appears. Other features include logging, tracking, and email notifications. You can get more details on the <a href="http://blogs.msdn.com/johnmullinax/archive/2008/02/11/billg-keynote-at-odc-see-the-video-and-screenshots-from-the-fedex-demo.aspx">Beyond IT</a> blog.  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:178867201919472b961a9e0d00e275c9">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Track-FedEx-in-Outlook</comments>
      <itunes:summary>FedEx has released an application&#39;s called FedEx QuickShip, which allows you to easily create and track U.S. shipments, get rates, schedule pickups, and find the nearest staffed FedEx location – all without leaving Outlook! The app installs a FedEx QuickShip toolbar along the top of your Office Outlook window. The toolbar has eight buttons: FedEx, Ship, Track, Rate, Pickup, Find Locations, View History and Edit Settings. QuickShip also lets you right-click on a contact and select &amp;quot;ship&amp;quot; on the menu that appears. Other features include logging, tracking, and email notifications. You can get more details on the Beyond IT blog. </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Track-FedEx-in-Outlook</link>
      <pubDate>Mon, 18 Feb 2008 11:57:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Track-FedEx-in-Outlook</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_850d6718-c5e8-43ff-9901-fb07efd3e836.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_46c28a0c-32e8-4fb2-8f01-abddc91a92c4.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Track-FedEx-in-Outlook/RSS</wfw:commentRss>
      <category>Outlook</category>
      <category>Productivity</category>
      <category>FedEx</category>
    </item>
  <item>
      <title>Supercharge Windows Explorer</title>
      <description><![CDATA[<a href="http://www.simtel.net/product.php?url_fb_product_page=59298">DMEXBar</a> is an add-on to Windows Explorer that lets you add extra features to Explorer. When you install DMEXBar, it adds a new toolbar to Explorer with features like the following: Arrange explorer windows side by side, rename multiple files at once, quick change to favorite folders, quick create directory, split files, calculate directory size, and more. One of the program's best features is the new button it adds that lets you quickly open up another instance of Windows Explorer right next to your current window. You can also add buttons that make it easier to launch a command prompt, copy or paste files, or mark them as favorites. DMEXBar works with Windows 2000 and XP. <em>(via <a href="http://www.downloadsquad.com/2008/02/07/dmexbar-gives-windows-explorer-super-powers/">Download Squad</a>)</em>  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:226f98c5fa23411ab7349e0d00e20e7d">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Supercharge-Windows-Explorer</comments>
      <itunes:summary>DMEXBar is an add-on to Windows Explorer that lets you add extra features to Explorer. When you install DMEXBar, it adds a new toolbar to Explorer with features like the following: Arrange explorer windows side by side, rename multiple files at once, quick change to favorite folders, quick create directory, split files, calculate directory size, and more. One of the program&#39;s best features is the new button it adds that lets you quickly open up another instance of Windows Explorer right next to your current window. You can also add buttons that make it easier to launch a command prompt, copy or paste files, or mark them as favorites. DMEXBar works with Windows 2000 and XP. (via Download Squad) </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Supercharge-Windows-Explorer</link>
      <pubDate>Thu, 14 Feb 2008 23:21:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Supercharge-Windows-Explorer</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_ce87c902-6419-433a-9414-a20aa1b2b365.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_de572f9a-253c-4c42-a724-2e9194c19b68.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Supercharge-Windows-Explorer/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Utilities</category>
      <category>utility</category>
      <category>Windows Explorer</category>
    </item>
  <item>
      <title>Tabbed Browsing in Windows Explorer</title>
      <description><![CDATA[<a href="http://qttabbar.wikidot.com/qttabbar">QTTabBar</a> is Windows Explorer add-on that allows you to navigate files and folders in a tabbed browser, just like you do in IE7. The program, written in C#, works on any Windows XP or Vista (32-bit) machine with .NET 2.0&#43; installed. To get started, <a href="http://qttabbar.wikidot.com/download">download</a> the latest version and install the program. Reboot and logon to Windows again. Open a folder in Explorer and right-click on the toolbar. Check 'QT TabBar'. That's it! There's also a desktop toolbar available which you can access by right-clicking on the Task Bar and checking 'QT Tab Desktop Tool' in the 'Toolbar' menu. This is so convenient, I can't believe I hadn't heard of it before now! <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e6d2a40f68254e23b4529e0d00e1c5de">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Tabbed-Browsing-in-Windows-Explorer</comments>
      <itunes:summary>QTTabBar is Windows Explorer add-on that allows you to navigate files and folders in a tabbed browser, just like you do in IE7. The program, written in C#, works on any Windows XP or Vista (32-bit) machine with .NET 2.0&amp;#43; installed. To get started, download the latest version and install the program. Reboot and logon to Windows again. Open a folder in Explorer and right-click on the toolbar. Check &#39;QT TabBar&#39;. That&#39;s it! There&#39;s also a desktop toolbar available which you can access by right-clicking on the Task Bar and checking &#39;QT Tab Desktop Tool&#39; in the &#39;Toolbar&#39; menu. This is so convenient, I can&#39;t believe I hadn&#39;t heard of it before now!</itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Tabbed-Browsing-in-Windows-Explorer</link>
      <pubDate>Tue, 12 Feb 2008 08:28:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Tabbed-Browsing-in-Windows-Explorer</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_c602920b-57dd-4344-8a4b-475405892046.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_fb546d2d-0db2-47a0-8b5f-c909f45dc513.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Tabbed-Browsing-in-Windows-Explorer/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Utilities</category>
      <category>utility</category>
    </item>
  <item>
      <title>Rocker Mouse App</title>
      <description><![CDATA[From the programmers at Lifehacker, <a href="http://lifehacker.com/software/exclusive-lifehacker-download-for-windows/navigate-backward-and-forward-with-rocker-257609.php">Rocker</a> is cool utility that lets you perform common computing tasks just by rocking your fingers across you mouse. For example, you could go forward and backward in Internet Explorer just by &quot;rocking&quot; across the mouse. Rocker actually requires that you hold one mouse button down while you click the other in a rocking motion. You can rock right to left or left to right and each direction gives you a different results. It's kind of weird at first, but those that get used to it say it's more natural to them that the usual clicking and double-clicking.  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/productivity/RSS&WT.dl=0&WT.entryid=Entry:RSSView:91726c25dc564845954b9e0e009b930e">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Rocker-Mouse-App</comments>
      <itunes:summary>From the programmers at Lifehacker, Rocker is cool utility that lets you perform common computing tasks just by rocking your fingers across you mouse. For example, you could go forward and backward in Internet Explorer just by &amp;quot;rocking&amp;quot; across the mouse. Rocker actually requires that you hold one mouse button down while you click the other in a rocking motion. You can rock right to left or left to right and each direction gives you a different results. It&#39;s kind of weird at first, but those that get used to it say it&#39;s more natural to them that the usual clicking and double-clicking. </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Rocker-Mouse-App</link>
      <pubDate>Fri, 25 Jan 2008 04:37:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Rocker-Mouse-App</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_2ea44562-e9ae-4fa7-b037-f3d947003254.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/on10_68796e1f-65bb-41ec-a4d4-68bc0bbefff2.jpg" height="64" width="85"></media:thumbnail>      
      <dc:creator>Sarah Perez</dc:creator>
      <itunes:author>Sarah Perez</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Rocker-Mouse-App/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Utilities</category>
      <category>utility</category>
    </item>    
</channel>
</rss>