<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Coding4Fun : productivity</title><link>http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx</link><description>Tags: productivity</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Coding 4 Fun - Windows 7 Taskbar</title><link>http://blogs.msdn.com/coding4fun/archive/2009/08/25/9874533.aspx</link><pubDate>Tue, 25 Aug 2009 19:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9874533</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9874533.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9874533</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9874533</wfw:comment><description>&lt;p&gt;&lt;img title="image" border="0" alt="Windows 7" align="right" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image101.png" width="84" height="84" /&gt;Looking to take advantage of some new Windows 7 goodness?&amp;#160; Learn how to work with some of the great new taskbar features to create a more streamlined user interface.&lt;/p&gt;  &lt;p&gt;Arian T. Kulp    &lt;br /&gt;&lt;a href="http://www.ariankulp.com" target="_blank"&gt;http://www.ariankulp.com&lt;/a&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Project site:&lt;/strong&gt; &lt;a href="http://taskbarsample.codeplex.com/" target="_blank"&gt;Codeplex link&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Source code and precompiled: &lt;/b&gt;&lt;a href="http://taskbarsample.codeplex.com/Release/ProjectReleases.aspx"&gt;Downloads&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Difficulty:&lt;/b&gt; Intermediate &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Time Required:&lt;/b&gt;&amp;#160; 3 hours &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Cost:&lt;/b&gt; Free! &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Software Needed:&lt;/b&gt; &lt;a href="http://www.microsoft.com/express/download/"&gt;Visual Basic or Visual C# Express&lt;/a&gt;, &lt;a href="http://code.msdn.microsoft.com/WindowsAPICodePack" target="_blank"&gt;Windows API Code Pack&lt;/a&gt;, Windows 7 (RC or greater) &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Introduction&lt;/h3&gt;  &lt;p&gt;Windows 7 brings with it a large number of new features that will be available to developers from day one.&amp;#160; These are really nice additions that will make applications more natural to work with.&amp;#160; One of the new areas of enhancements is the taskbar.&amp;#160; The taskbar has always been a pretty simple way to see what's running and switch between tasks.&amp;#160; Moving from XP to Vista, we got cool previews, but that's about it.&amp;#160; 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).&amp;#160; You can also right-click the icons to restore or close the window.&amp;#160; Better still, many apps give you additional information upon right-click, such as Recent lists, or actions like changing your Live Messenger status:&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image1.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Jump list for Windows Live Messenger" border="0" alt="Jump list for Windows Live Messenger" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image1_thumb.png" width="126" height="240" /&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;Image 1: Jump list for Windows Live Messenger&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;In this article, I would like to dig into the following notable new features:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Customizable preview &lt;/li&gt;    &lt;li&gt;Icon overlays &lt;/li&gt;    &lt;li&gt;Progress indication &lt;/li&gt;    &lt;li&gt;Toolbar buttons &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;None of these features are very difficult to use due to the &lt;a href="http://code.msdn.microsoft.com/WindowsAPICodePack" target="_blank"&gt;Windows API Code Pack&lt;/a&gt;.&amp;#160; This download is a free (but unsupported) package from Microsoft on the &lt;a href="http://code.msdn.microsoft.com" target="_blank"&gt;MSDN Code Gallery&lt;/a&gt;.&amp;#160; Version 1.0 was released on August 6, after a number of earlier pre-releases.&amp;#160; Since many of the new features are specific to Windows 7, they are not in the .NET Base Class Libraries.&amp;#160; This package exposes them for .NET so you don't have to do any of your own interop.&lt;/p&gt;  &lt;p&gt;This sample is written for Windows Forms, but it works equally well with WPF.&amp;#160; These four features are easy to integrate into any application that you write.&lt;/p&gt;  &lt;h3&gt;Customizable Previews&lt;/h3&gt;  &lt;p&gt;To start with, we'll dig into customizable previews.&amp;#160; 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.&amp;#160; &lt;/p&gt;  &lt;p align="center"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Aero Peek preview for Windows Live Writer" border="0" alt="Aero Peek preview for Windows Live Writer" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image4_1.png" width="310" height="260" /&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;Image 2: Aero Peek preview for Windows Live Writer&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;If you create any basic application and launch it (F5), the taskbar preview will be an exact copy of the application's main window.&amp;#160; In fact, Windows gets this from the DWM, or Desktop Window Manager.&amp;#160; This is cached already so it makes sense to use it here.&amp;#160; Overriding it though is fairly easy.&amp;#160; 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.&amp;#160; 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.&lt;/p&gt;  &lt;p&gt;The &lt;strong&gt;TaskbarManager &lt;/strong&gt;class is responsible for exposing progress state, thumbnail, overlay icons, and other similar properties.&amp;#160; These functions would otherwise be scattered across various Win32 API calls, but the Windows API Code Pack simplifies this immensely.&amp;#160; The first step is to create a reference to it and obtain the static reference:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; windowsTaskbar &lt;span class="kwrd"&gt;As&lt;/span&gt; TaskbarManager = TaskbarManager.Instance&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; TaskbarManager windowsTaskbar = TaskbarManager.Instance;&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;You'll use this reference throughout your application for any taskbar manipulation.&amp;#160; In order to clip your preview, just specify the window handle and the region.&amp;#160; An easy way is to specify the &lt;strong&gt;Location&lt;/strong&gt; and &lt;strong&gt;Size &lt;/strong&gt;properties of a control.&amp;#160; In this sample, it's a &lt;strong&gt;GroupBox&lt;/strong&gt;, but in another application it might make more sense to clip to a &lt;strong&gt;PictureBox&lt;/strong&gt; or other control:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.TabbedThumbnail.SetThumbnailClip(&lt;span class="kwrd"&gt;Me&lt;/span&gt;.Handle, &lt;span class="kwrd"&gt;New&lt;/span&gt; Rectangle(groupBox2.Location, groupBox2.Size))&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.TabbedThumbnail.SetThumbnailClip(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Handle, &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(groupBox2.Location, groupBox2.Size));&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Icon Overlays&lt;/h3&gt;

&lt;p&gt;Icon overlays allow you to display a visual representation of your program's state.&amp;#160; 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.&amp;#160; 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.&amp;#160; This is used in Windows Live Messenger to show your login status (offline, busy, available, etc.):&lt;/p&gt;

&lt;p align="center"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Windows Live Messenger with overlay for offline status" border="0" alt="Windows Live Messenger with overlay for offline status" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image7_1.png" width="60" height="39" /&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;

&lt;p align="center"&gt;&lt;em&gt;Image 3: Windows Live Messenger with overlay for offline status&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is great for providing information at a glance.&amp;#160; Especially as more and more users are hiding their cluttered notification tray icons and wouldn't see the indicator otherwise.&lt;/p&gt;

&lt;p&gt;The beautiful thing is that the &lt;strong&gt;TaskbarManager &lt;/strong&gt;class allows you to set this with one line of code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetOverlayIcon(&lt;span class="kwrd"&gt;me&lt;/span&gt;.Handle, My.Resources.Green, &lt;span class="str"&gt;&amp;quot;Green&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetOverlayIcon(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Handle, TaskbarDemo.Properties.Resources.Green, &lt;span class="str"&gt;&amp;quot;Green&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The same API call can also lets you clear an overlay:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetOverlayIcon(&lt;span class="kwrd"&gt;Me&lt;/span&gt;.Handle, &lt;span class="kwrd"&gt;Nothing&lt;/span&gt;, &lt;span class="kwrd"&gt;Nothing&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetOverlayIcon(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Handle, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;

&lt;h3&gt;&amp;#160;&lt;/h3&gt;

&lt;h3&gt;Progress Indication&lt;/h3&gt;

&lt;p&gt;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.&amp;#160; If you're really diabolical you might even make this a modal dialog!&amp;#160; In our brave new world of Windows 7 though, we no longer need to subject our users to this.&amp;#160; 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:&lt;/p&gt;

&lt;p align="center"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Windows Explorer with file copy progress indication" border="0" alt="Windows Explorer with file copy progress indication" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image10.png" width="58" height="40" /&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;

&lt;p align="center"&gt;&lt;em&gt;Image 4: Windows Explorer with file copy progress indication&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's faint, but you should be able to see the bar at around the 15-20% point behind the folder.&amp;#160; There are actually a number of states that you can instruct the taskbar to display, then you just provide progress value updates as needed.&lt;/p&gt;

&lt;p&gt;In this sample application, we display the various &lt;strong&gt;TaskbarProgressBarState &lt;/strong&gt;enumerated values in a ComboBox:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;comboBoxProgressState.DataSource = System.&lt;span class="kwrd"&gt;Enum&lt;/span&gt;.GetNames(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(TaskbarProgressBarState))&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;comboBoxProgressState.DataSource = Enum.GetNames(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TaskbarProgressBarState));&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;When changes are made, we update the state using the &lt;strong&gt;SetProgressState &lt;/strong&gt;call:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetProgressState(&lt;span class="kwrd"&gt;CType&lt;/span&gt;(System.&lt;span class="kwrd"&gt;Enum&lt;/span&gt;.Parse(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(TaskbarProgressBarState), comboBoxProgressState.Text), TaskbarProgressBarState))&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetProgressState((TaskbarProgressBarState)Enum.Parse(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TaskbarProgressBarState), comboBoxProgressState.Text));&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Then, we use a TrackerBar to select the current value which gets posted using the &lt;strong&gt;SetProgressState &lt;/strong&gt;call:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetProgressValue(trackProgress.Value, 100)&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.SetProgressValue(trackProgress.Value, 100);&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;h3&gt;&amp;#160;&lt;/h3&gt;

&lt;h3&gt;Toolbar Buttons&lt;/h3&gt;

&lt;p&gt;One of the new features that really has me excited is the ability to add buttons to the preview image.&amp;#160; This is a very underutilized feature so far, though it's visible in Windows Media Player:&lt;/p&gt;

&lt;p align="center"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" 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://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/f40328fbce24_E1C8/image13_1.png" width="260" height="248" /&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;

&lt;p align="center"&gt;&lt;em&gt;Image 5: Windows Media Player preview with toolbar buttons for media control&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notice the Pause, Previous, and Next buttons under the Aero Peek.&amp;#160; Those are fully-functional.&amp;#160; The great thing is that you can add them to your application easily, and bind event handlers to them like any other buttons.&amp;#160; You don't get design-time support like for forms and menus, but you really don't need it.&lt;/p&gt;

&lt;p&gt;Start by decaring a &lt;strong&gt;ThumbnailToolbarButton:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;WithEvents&lt;/span&gt; buttonFirst &lt;span class="kwrd"&gt;As&lt;/span&gt; ThumbnailToolbarButton&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; ThumbnailToolbarButton buttonFirst; &lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;You can set the image, a label (shown on hover), enabled or not, and other common Button properties.&amp;#160; Here I will create the button and point it to an image stored as a resource, and a label:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;buttonFirst = &lt;span class="kwrd"&gt;New&lt;/span&gt; ThumbnailToolbarButton(My.Resources.search, &lt;span class="str"&gt;&amp;quot;Search&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;buttonFirst = &lt;span class="kwrd"&gt;new&lt;/span&gt; ThumbnailToolbarButton(Properties.Resources.first, &lt;span class="str"&gt;&amp;quot;First Image&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Next, I need to attach an event handler to it.&amp;#160; In Visual Basic, since &lt;strong&gt;buttonFirst &lt;/strong&gt;was declared using &lt;strong&gt;WithEvents&lt;/strong&gt;, you can use the &lt;strong&gt;Handles &lt;/strong&gt;keyword in the declaration of the event handler.&amp;#160; In C#, you can type &amp;quot;buttonFirst.Click +=&amp;quot; and then press the TAB key twice.&amp;#160; This will fill out the rest of the line *and* create an event handler stub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; buttonFirst_Click(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; sender &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt;, &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; e &lt;span class="kwrd"&gt;As&lt;/span&gt; ThumbnailButtonClickedEventArgs) &lt;span class="kwrd"&gt;Handles&lt;/span&gt; buttonFirst.Click&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;buttonFirst.Click += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;ThumbnailButtonClickedEventArgs&amp;gt;(buttonFirst_Click); &lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Finally, add the buttons using the &lt;strong&gt;TaskbarManager &lt;/strong&gt;instance.&amp;#160; The &lt;strong&gt;AddButtons &lt;/strong&gt;call takes a list of parameters, so you can just add other buttons by separating them with commas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.ThumbnailToolbars.AddButtons(&lt;span class="kwrd"&gt;Me&lt;/span&gt;.Handle, buttonFirst)&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;windowsTaskbar.ThumbnailToolbars.AddButtons(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Handle, buttonFirst);&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Just fill in something for your event handler to do (a simple MessageBox in the sample application), and you're done!&amp;#160; It's super-easy and it adds a new dimension of interactivity with your application.&amp;#160; This could replace menu commands in a notification icon, or simply present common actions.&amp;#160; It doesn't make sense in every application, but it's easy to add when you need it.&lt;/p&gt;

&lt;h3&gt;Next Steps&lt;/h3&gt;

&lt;p&gt;The next step is to evaluate your own applications to see what makes to add.&amp;#160; While custom previews and toolbar buttons don't make sense for every application, progress indication and custom overlays can often be a good fit.&amp;#160; Of course, remember that if you implement any of this, it won't be visible in Windows Vista or earlier.&amp;#160; Be sure to have a secondary way to access these same functions.&amp;#160; Toolbar buttons and overlays can be accomplished in the notification icon, and progress can always be displayed in a popup dialog as a fallback.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Windows 7 makes it easier to create very user-friendly applications.&amp;#160; 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.&amp;#160; Pretty quickly, these will be considered common place and you'll want your application to play well on the desktop.&lt;/p&gt;

&lt;p&gt;If you haven't yet, download &lt;a href="http://www.microsoft.com/express/" target="_blank"&gt;Visual Studio 2008 Express Edition&lt;/a&gt; (Visual Basic or Visual C#), and then download the &lt;a href="http://code.msdn.microsoft.com/WindowsAPICodePack" target="_blank"&gt;Windows API Code Pack&lt;/a&gt; so you can get started!&amp;#160; 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.&amp;#160; Get ready for it now!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9874533" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>TwitterDrive – Author Interview</title><link>http://blogs.msdn.com/coding4fun/archive/2009/04/01/9525555.aspx</link><pubDate>Wed, 01 Apr 2009 10:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9525555</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9525555.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9525555</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9525555</wfw:comment><description>&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="tDrive" border="0" alt="tDrive" align="left" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/tDrive_3.jpg" width="79" height="45" mce_src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/tDrive_3.jpg" /&gt; In case you haven’t heard, &lt;a href="http://www.brianpeek.com/media/p/3413.aspx" mce_href="http://www.brianpeek.com/media/p/3413.aspx"&gt;TwitterDrive&lt;/a&gt; is going to revolutionize the way files are stored and shared on the Internet.&amp;#160; Today, we had the rare privilege of sitting down and talking with &lt;a href="http://www.brianpeek.com/" mce_href="http://www.brianpeek.com/"&gt;Brian Peek&lt;/a&gt;, creator of this cutting edge product.&lt;/p&gt;  &lt;p&gt;&lt;b&gt; Q: Thanks for taking the time to speak with us today.&amp;#160; Why don’t you tell us a little bit about yourself?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;A: I’m surprised I even considered this.&amp;#160; I’m so above you people now.&amp;#160; 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;#160; Now, I’m on the cusp of owning people like you.&amp;#160; Once this takes off, I can finally pursue my life’s other passion:&amp;#160; hip-hop music.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/30872-480-360_2.png" mce_href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/30872-480-360_2.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="30872-480-360" border="0" alt="30872-480-360" align="left" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/30872-480-360_thumb.png" width="364" height="274" mce_src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/30872-480-360_thumb.png" /&gt;&lt;/a&gt; Q: I don’t doubt it.&amp;#160; So why don’t you tell us a little bit about TwitterDrive and how you came up with the idea?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;A: TwitterDrive is the next “big thing” in cloud storage.&amp;#160; There are a ton of cloud storage providers out there now, most of which cost money or have limited disk space available.&amp;#160; But why should we live with limitations like these?&amp;#160; Twitter provides their users with unlimited storage for sending and saving their “tweets”.&amp;#160; My amazingly brilliant idea was to take this service to the next level:&amp;#160; using it to store and share files.&amp;#160; That is, free cloud storage.&amp;#160; Bet you wish you thought of that. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;b&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="shatner" border="0" alt="shatner" align="left" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/shatner_3.png" width="185" height="250" /&gt;&lt;/b&gt;Q: I sure do.&amp;#160; So how does TwitterDrive work? &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;A: It works perfectly.&amp;#160; Simply run the TwitterDrive application, provide your Twitter user credentials, and then start uploading and downloading files.&amp;#160; Files are compressed, base64 encoded, and then uploaded to Twitter 140 bytes at a time, fully maximizing the amount of space allowed per tweet.&lt;/p&gt;  &lt;p&gt;Imagine…uploading 14 thousand bytes of data per hour!&amp;#160; Or downloading two megabytes per hour!&amp;#160; Match that, SkyDrive.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Q: That sounds amazing.&amp;#160; Unlimited storage for free.&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;It is amazing.&amp;#160; Which is why I thought of it and you didn’t.&amp;#160; Welcome to the future.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Q: So are there any limitations?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Only if you consider uploading 14 thousand &lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/mp_main_wide_EarlyComputerMarketing_2.png" mce_href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/mp_main_wide_EarlyComputerMarketing_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="mp_main_wide_EarlyComputerMarketing" border="0" alt="mp_main_wide_EarlyComputerMarketing" align="right" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/mp_main_wide_EarlyComputerMarketing_thumb.png" width="364" height="282" mce_src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDriveAuthorInterview_264E/mp_main_wide_EarlyComputerMarketing_thumb.png" /&gt;&lt;/a&gt;bytes per hour a limitation.&amp;#160; But really, who has that much data?&amp;#160; 14k should be enough for everybody.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Q: What about data protection?&amp;#160; Is the file data protected in any way?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;The data is compressed, encoded and chunked up into bits.&amp;#160; Who needs more security than that?&amp;#160; Besides, users would need to know your TwitterDrive account username to get at the data.&amp;#160; Security through obscurity is a win for everyone!&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Q: Do you have any new features planned for TwitterDrive?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;New features?&amp;#160; No.&amp;#160; It’s already the most complete, useful and bug free application ever developed.&amp;#160; It doesn’t require any additional features.&lt;/p&gt;  &lt;p&gt;Now if you’ll excuse me, I have to start planning which jet I want to buy.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Well there you have it, folks.&amp;#160; We are at the cusp of a revolution.&amp;#160; Are you ready?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.brianpeek.com/media/p/3413.aspx" mce_href="http://www.brianpeek.com/media/p/3413.aspx"&gt;Download TwitterDrive here&lt;/a&gt;.&amp;#160; Want to learn more?&amp;#160; Learn &lt;a href="http://blogs.msdn.com/coding4fun/archive/2009/04/01/9525376.aspx" mce_href="http://blogs.msdn.com/coding4fun/archive/2009/04/01/9525376.aspx"&gt;how it was made&lt;/a&gt;!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9525555" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web/default.aspx">web</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/april+fools+day/default.aspx">april fools day</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/holiday/default.aspx">holiday</category></item><item><title>TwitterDrive – The Revolution in Cloud Storage</title><link>http://blogs.msdn.com/coding4fun/archive/2009/04/01/9525376.aspx</link><pubDate>Wed, 01 Apr 2009 10:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9525376</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9525376.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9525376</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9525376</wfw:comment><description>&lt;table border="0" cellspacing="0" cellpadding="1" width="100%"&gt;&lt;tbody&gt;     &lt;tr class="entry_overview"&gt;       &lt;td width="50"&gt;&amp;#160;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="tDrive" border="0" alt="tDrive" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDrive_36DE/tDrive_3.jpg" width="75" height="41" /&gt; &lt;/td&gt;        &lt;td&gt;&lt;span class="entry_description"&gt;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.&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td colspan="2"&gt;         &lt;div class="entry_author"&gt;&lt;a href="http://www.brianpeek.com/" target="_blank" mce_href="http://www.brianpeek.com/"&gt;Brian Peek&lt;/a&gt;&lt;/div&gt;          &lt;div class="entry_company"&gt;&lt;a href="http://www.aspsoft.com/" mce_href="http://www.aspsoft.com/"&gt;ASPSOFT, Inc.&lt;/a&gt;&lt;/div&gt;          &lt;br /&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; 2&lt;span class="entry_details_input"&gt;-3 hours&lt;/span&gt;&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;Free&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual C# Express 2008 SP1, Visual Basic Express 2008 SP1, or Visual Studio 2008 SP1, .NET Framework 3.5 SP1&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;None&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://www.brianpeek.com/media/p/3413.aspx" target="_blank"&gt;Application&lt;/a&gt;, &lt;a href="http://www.brianpeek.com/media/p/3414.aspx" target="_blank"&gt;Source Code&lt;/a&gt;&lt;/div&gt;          &lt;div class="entry_details"&gt;&lt;b&gt;Discussion Forum: &lt;/b&gt;&lt;a href="http://www.brianpeek.com/forums/44.aspx" target="_blank"&gt;Forum&lt;/a&gt;&lt;/div&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Introduction&lt;/h3&gt;  &lt;p&gt;As you’ve probably guessed by now, &lt;b&gt;TwitterDrive&lt;/b&gt; is my April Fool’s Day application for Coding4Fun this year.&amp;#160; While the application does actually work, the limitations of Twitter make it functionally useless.&amp;#160; 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.&lt;/p&gt;  &lt;h4&gt;How It Works&lt;/h4&gt;  &lt;p&gt;Not very well, actually.&amp;#160; 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;#160; 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.&lt;/p&gt;  &lt;h4&gt;Twitter&lt;/h4&gt;  &lt;p&gt;Let’s start with the Twitter API.&amp;#160; Full documentation on this API can be found at:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://apiwiki.twitter.com/" href="http://apiwiki.twitter.com/"&gt;http://apiwiki.twitter.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;TwitterDrive only requires a very small subset of this functionality to work.&amp;#160; We need the ability to post a new status message, download a user timeline, destroy a status, and verify the user’s credentials.&amp;#160; All of these things are handled in the &lt;b&gt;TwitterService&lt;/b&gt; class.&lt;/p&gt;  &lt;p&gt;The heart of this class consists of two methods:&amp;#160; &lt;b&gt;GetTwitter &lt;/b&gt;and &lt;b&gt;PostTwitter&lt;/b&gt;.&amp;#160; &lt;b&gt;GetTwitter&lt;/b&gt; will make a GET request to Twitter of the specified URL, and &lt;b&gt;PostTwitter&lt;/b&gt; will make a POST request to Twitter of the specified URL with the supplied data.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; XDocument GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; url)&lt;br /&gt;{&lt;br /&gt;    WebClient wc = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; WebClient();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// only authenticate if we have a password&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(!&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;.IsNullOrEmpty(Password))&lt;br /&gt;        wc.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; NetworkCredential(Username, Password);&lt;br /&gt;&lt;br /&gt;    Stream s = wc.OpenRead(url);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// return an XDocument for LINQ&lt;/span&gt;&lt;br /&gt;    XmlTextReader xmlReader = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; XmlTextReader(s);&lt;br /&gt;    XDocument xdoc = XDocument.Load(xmlReader);&lt;br /&gt;    xmlReader.Close();&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; xdoc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; XDocument PostTwitter(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; url, &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; data)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] bytes = Encoding.ASCII.GetBytes(data);&lt;br /&gt;&lt;br /&gt;    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);&lt;br /&gt;    request.Method = &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// if we're writing, we need to authenticate&lt;/span&gt;&lt;br /&gt;    request.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; NetworkCredential(Username, Password);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// if this is 'true', Twitter breaks&lt;/span&gt;&lt;br /&gt;    request.ServicePoint.Expect100Continue = &lt;span style="color: rgb(0,0,255)"&gt;false&lt;/span&gt;;&lt;br /&gt;    request.ContentType = &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/span&gt;;&lt;br /&gt;    request.ContentLength = bytes.Length;&lt;br /&gt;&lt;br /&gt;    Stream reqStream = request.GetRequestStream();&lt;br /&gt;    reqStream.Write(bytes, 0, bytes.Length);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// turn the response into an XDocument for use with LINQ&lt;/span&gt;&lt;br /&gt;    HttpWebResponse resp = (HttpWebResponse)request.GetResponse();&lt;br /&gt;    XmlReader xmlReader = XmlReader.Create(resp.GetResponseStream());&lt;br /&gt;    XDocument xdoc = XDocument.Load(xmlReader);&lt;br /&gt;    xmlReader.Close();&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; xdoc;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; url &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; wc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; WebClient()&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' only authenticate if we have a password&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; (&lt;span style="color: rgb(0,0,255)"&gt;Not&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;.IsNullOrEmpty(Password)) &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;        wc.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; NetworkCredential(Username, Password)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; s &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Stream = wc.OpenRead(url)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' return an XDocument for LINQ&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xmlReader &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; XmlTextReader(s)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xdoc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument = XDocument.Load(xmlReader)&lt;br /&gt;    xmlReader.Close()&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; xdoc&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; PostTwitter(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; url &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; data &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; bytes() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = Encoding.ASCII.GetBytes(data)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; request &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; HttpWebRequest = &lt;span style="color: rgb(0,0,255)"&gt;CType&lt;/span&gt;(WebRequest.Create(url), HttpWebRequest)&lt;br /&gt;    request.Method = &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' if we're writing, we need to authenticate&lt;/span&gt;&lt;br /&gt;    request.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; NetworkCredential(Username, Password)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' if this is 'true', Twitter breaks&lt;/span&gt;&lt;br /&gt;    request.ServicePoint.Expect100Continue = &lt;span style="color: rgb(0,0,255)"&gt;False&lt;/span&gt;&lt;br /&gt;    request.ContentType = &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/span&gt;&lt;br /&gt;    request.ContentLength = bytes.Length&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; reqStream &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Stream = request.GetRequestStream()&lt;br /&gt;    reqStream.Write(bytes, 0, bytes.Length)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' turn the response into an XDocument for use with LINQ&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; resp &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; HttpWebResponse = &lt;span style="color: rgb(0,0,255)"&gt;CType&lt;/span&gt;(request.GetResponse(), HttpWebResponse)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xmlReader &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XmlReader = XmlReader.Create(resp.GetResponseStream())&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xdoc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument = XDocument.Load(xmlReader)&lt;br /&gt;    xmlReader.Close()&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; xdoc&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;Each of these methods will use the &lt;b&gt;NetworkCredentials&lt;/b&gt; object to authenticate to Twitter for reading or writing, as required.&amp;#160; Twitter API methods return simple XML objects.&amp;#160; Both &lt;b&gt;GetTwitter&lt;/b&gt; and &lt;b&gt;PostTwitter&lt;/b&gt; take these XML documents and turn them into &lt;b&gt;XDocument&lt;/b&gt; objects that can be easily queried with LINQ to XML later.&lt;/p&gt;

&lt;p&gt;We only need to call two Twitter “get” methods: &lt;b&gt;user_timeline &lt;/b&gt;and &lt;b&gt;verify_credentials&lt;/b&gt;.&amp;#160; There are two overloaded methods which call the &lt;b&gt;user_timeline&lt;/b&gt; API:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; IList&amp;lt;Status&amp;gt; GetUserTimeline(&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; page, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; count)&lt;br /&gt;{&lt;br /&gt;    XDocument xdoc = GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;.Format(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?count=" href="http://twitter.com/statuses/user_timeline.xml?count="&gt;http://twitter.com/statuses/user_timeline.xml?count=&lt;/a&gt;{0}&amp;amp;page={1}&amp;amp;id={2}&amp;quot;&lt;/span&gt;, count, page, Username));&lt;br /&gt;    IList&amp;lt;Status&amp;gt; statuses = ParseStatuses(xdoc);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; statuses;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; IList&amp;lt;Status&amp;gt; GetUserTimeline(&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; since_id, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; max_id, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; page, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; count)&lt;br /&gt;{&lt;br /&gt;    XDocument xdoc = GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;.Format(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;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="&gt;http://twitter.com/statuses/user_timeline.xml?since_id=&lt;/a&gt;{0}&amp;amp;max_id={1}&amp;amp;count={2}&amp;amp;page={3}&amp;amp;id={4}&amp;quot;&lt;/span&gt;, since_id, max_id, count, page, Username));&lt;br /&gt;    IList&amp;lt;Status&amp;gt; statuses = ParseStatuses(xdoc);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; statuses;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; GetUserTimeline(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; page &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; count &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xdoc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument = GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;.Format(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/statuses/user_timeline.xml?count=" href="http://twitter.com/statuses/user_timeline.xml?count="&gt;http://twitter.com/statuses/user_timeline.xml?count=&lt;/a&gt;{0}&amp;amp;page={1}&amp;amp;id={2}&amp;quot;&lt;/span&gt;, count, page, Username))&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; statuses &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status) = ParseStatuses(xdoc)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; statuses&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; GetUserTimeline(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; since_id &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; max_id &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; page &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; count &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; xdoc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument = GetTwitter(&lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;.Format(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;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="&gt;http://twitter.com/statuses/user_timeline.xml?since_id=&lt;/a&gt;{0}&amp;amp;max_id={1}&amp;amp;count={2}&amp;amp;page={3}&amp;amp;id={4}&amp;quot;&lt;/span&gt;, since_id, max_id, count, page, Username))&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; statuses &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status) = ParseStatuses(xdoc)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; statuses&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;status&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;created_at&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;Mon Mar 30 07:20:57 +0000 2009&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;created_at&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;1234567123&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;text&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;Status text&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;text&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;source&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;web&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;source&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;truncated&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;false&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;truncated&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;in_reply_to_status_id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;in_reply_to_user_id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;favorited&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;false&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;favorited&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;user&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;12345678&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;Some Person&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;screen_name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;myscreenname&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;screen_name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;description&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;location&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;profile_image_url&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;a class="linkification-ext" title="Linkification: http://static.twitter.com/images/default_profile_normal.png" href="http://static.twitter.com/images/default_profile_normal.png"&gt;http://static.twitter.com/images/default_profile_normal.png&lt;/a&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;profile_image_url&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;url&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;protected&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;false&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;protected&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;followers_count&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;followers_count&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;user&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128,0,0)"&gt;status&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; IList&amp;lt;Status&amp;gt; ParseStatuses(XContainer container)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// return a list of Status objects&lt;/span&gt;&lt;br /&gt;    var query = from status &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; container.Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;statuses&amp;quot;&lt;/span&gt;).Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;)&lt;br /&gt;                select ParseStatus(status);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; query.ToList();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; Status ParseStatus(XDocument xdoc)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// create a Status object from the returned XML&lt;/span&gt;&lt;br /&gt;    var query = from status &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; xdoc.Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;)&lt;br /&gt;                select ParseStatus(status);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; query.SingleOrDefault();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; Status ParseStatus(XElement xelement)&lt;br /&gt;{&lt;br /&gt;    Status s = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Status()&lt;br /&gt;                {&lt;br /&gt;                    ID = (&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;)xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;),&lt;br /&gt;                    Text = (&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;)xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;),&lt;br /&gt;                    UserInformation = ParseUserInformation(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;)),&lt;br /&gt;                    &lt;span style="color: rgb(0,128,0)"&gt;// HTTP-formatted date&lt;/span&gt;&lt;br /&gt;                    CreatedAt = DateTime.ParseExact(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;).Value,&lt;br /&gt;                            &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;ddd MMM dd HH:mm:ss zzzz yyyy&amp;quot;&lt;/span&gt;,&lt;br /&gt;                            CultureInfo.GetCultureInfoByIetfLanguageTag(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;en-us&amp;quot;&lt;/span&gt;),&lt;br /&gt;                            DateTimeStyles.AllowWhiteSpaces)&lt;br /&gt;                };&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; s;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; ParseStatuses(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; container &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XContainer) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status)&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' return a list of Status objects&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; query = _&lt;br /&gt;        From status &lt;span style="color: rgb(0,0,255)"&gt;In&lt;/span&gt; container.Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;statuses&amp;quot;&lt;/span&gt;).Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;) _&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Select&lt;/span&gt; ParseStatus(status)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; query.ToList()&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; ParseStatus(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; xdoc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XDocument) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' create a Status object from the returned XML&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; query = _&lt;br /&gt;        From status &lt;span style="color: rgb(0,0,255)"&gt;In&lt;/span&gt; xdoc.Descendants(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;) _&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Select&lt;/span&gt; ParseStatus(status)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; query.SingleOrDefault()&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; ParseStatus(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; xelement &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XElement) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; s &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; Status() &lt;span style="color: rgb(0,0,255)"&gt;With&lt;/span&gt; { _&lt;br /&gt;        .ID = &lt;span style="color: rgb(0,0,255)"&gt;CInt&lt;/span&gt;(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)), _&lt;br /&gt;        .Text = &lt;span style="color: rgb(0,0,255)"&gt;CStr&lt;/span&gt;(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;)), _&lt;br /&gt;        .UserInformation = ParseUserInformation(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;)), _&lt;br /&gt;        .CreatedAt = DateTime.ParseExact(xelement.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;).Value, _&lt;br /&gt;                    &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;ddd MMM dd HH:mm:ss zzzz yyyy&amp;quot;&lt;/span&gt;, CultureInfo.GetCultureInfoByIetfLanguageTag(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;en-us&amp;quot;&lt;/span&gt;), DateTimeStyles.AllowWhiteSpaces) }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; s&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;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.&amp;#160; You will notice the user element contains a &lt;strong&gt;user_information&lt;/strong&gt; XML chunk, and the &lt;b&gt;ParseUserInformation&lt;/b&gt; method parses that data&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; UserInformation ParseUserInformation(XContainer container)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// parse and return a UserInformation object&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; UserInformation&lt;br /&gt;    {&lt;br /&gt;        ID = (&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;)container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;),&lt;br /&gt;        Name = (&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;)container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;),&lt;br /&gt;        ScreenName = (&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;)container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;screen_name&amp;quot;&lt;/span&gt;)&lt;br /&gt;    };&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; ParseUserInformation(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; container &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; XContainer) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; UserInformation&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' parse and return a UserInformation object&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; ui &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; UserInformation() &lt;span style="color: rgb(0,0,255)"&gt;With&lt;/span&gt; { _&lt;br /&gt;        .ID = &lt;span style="color: rgb(0,0,255)"&gt;CInt&lt;/span&gt;(container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)), _&lt;br /&gt;        .Name = &lt;span style="color: rgb(0,0,255)"&gt;CStr&lt;/span&gt;(container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;)), _&lt;br /&gt;        .ScreenName = &lt;span style="color: rgb(0,0,255)"&gt;CStr&lt;/span&gt;(container.Element(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;screen_name&amp;quot;&lt;/span&gt;)) }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; ui&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;The &lt;b&gt;verify_credentials&lt;/b&gt; 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:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;bool&lt;/span&gt; VerifyTwitterCredentials(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; username, &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; password)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;try&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        WebClient wc = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; WebClient();&lt;br /&gt;        wc.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; NetworkCredential(username, password);&lt;br /&gt;        Stream s = wc.OpenRead(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/account/verify_credentials.xml" href="http://twitter.com/account/verify_credentials.xml"&gt;http://twitter.com/account/verify_credentials.xml&lt;/a&gt;&amp;quot;&lt;/span&gt;);&lt;br /&gt;        s.Close();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt;(WebException we)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;((we.Response &lt;span style="color: rgb(0,0,255)"&gt;as&lt;/span&gt; HttpWebResponse).StatusCode == HttpStatusCode.Unauthorized)&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;false&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;With the “get” methods out of the way, we can write our “post” methods.&amp;#160; We only need two methods here as well:&amp;#160; &lt;b&gt;update&lt;/b&gt; and &lt;b&gt;destroy&lt;/b&gt;.&amp;#160; Update is used to write a new tweet to Twitter, and destroy is used to remove an existing tweet.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; Status UpdateStatus(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; status)&lt;br /&gt;{&lt;br /&gt;    XDocument doc = PostTwitter(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/statuses/update.xml" href="http://twitter.com/statuses/update.xml"&gt;http://twitter.com/statuses/update.xml&lt;/a&gt;&amp;quot;&lt;/span&gt;, &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;status=&amp;quot;&lt;/span&gt; + status);&lt;br /&gt;    Status s =  ParseStatus(doc);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// if we don't get the text we sent, we hit the rate limit...&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(s.Text != HttpUtility.UrlDecode(status))&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; TwitterRateLimitException(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;Twitter upload limit reached.&amp;quot;&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; s;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; Status Destroy(&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; status)&lt;br /&gt;{&lt;br /&gt;    XDocument doc = PostTwitter(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/statuses/destroy/" href="http://twitter.com/statuses/destroy/"&gt;http://twitter.com/statuses/destroy/&lt;/a&gt;&amp;quot;&lt;/span&gt; + status + &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;.xml&amp;quot;&lt;/span&gt;, &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;id=&amp;quot;&lt;/span&gt; + status);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; ParseStatus(doc);&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; VerifyTwitterCredentials(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; username &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; password &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Boolean&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Try&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; wc &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; WebClient()&lt;br /&gt;        wc.Credentials = &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; NetworkCredential(username, password)&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; s &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Stream = wc.OpenRead(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;&lt;a class="linkification-ext" title="Linkification: http://twitter.com/account/verify_credentials.xml" href="http://twitter.com/account/verify_credentials.xml"&gt;http://twitter.com/account/verify_credentials.xml&lt;/a&gt;&amp;quot;&lt;/span&gt;)&lt;br /&gt;        s.Close()&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Catch&lt;/span&gt; we &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; WebException&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; (&lt;span style="color: rgb(0,0,255)"&gt;TryCast&lt;/span&gt;(we.Response, HttpWebResponse)).StatusCode = HttpStatusCode.Unauthorized &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;False&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Throw&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;The &lt;b&gt;UpdateStatus&lt;/b&gt; method has a bit of code to determine whether we hit Twitter’s upload rate limit.&amp;#160; Twitter will limit you to about 100 tweets per hour.&amp;#160; The only way to determine if you’ve hit the upload limit (that I found at least) is to compare the text from &lt;b&gt;status&lt;/b&gt; element returned from the update to the text that was sent.&amp;#160; If the upload limit is hit, the last valid &lt;b&gt;status&lt;/b&gt; element will be returned, and therefore the text blocks will not match.&amp;#160; If this happens, we throw our own custom &lt;b&gt;TwitterRateLimitException&lt;/b&gt; up the stack for the UI to handle.&lt;/p&gt;

&lt;h4&gt;TwitterDrive&lt;/h4&gt;

&lt;p&gt;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.&amp;#160; This code is located in the &lt;b&gt;TwitterDrive&lt;/b&gt; class.&lt;/p&gt;

&lt;p&gt;One of the goals I had was to make this application thread-happy to provide a responsive UI while files are uploaded and downloaded.&amp;#160; Therefore, this class sets up three events which can be hooked by the UI to receive periodic status information:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; ChunkEventArgs : EventArgs&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; Status Status;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; ChunkLength;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; Total;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; ChunkEventArgs(Status status, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; length, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; total)&lt;br /&gt;    {&lt;br /&gt;        Status = status;&lt;br /&gt;        ChunkLength = length;&lt;br /&gt;        Total = total;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,128,0)"&gt;// event handlers for async file transfer&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;event&lt;/span&gt; EventHandler&amp;lt;ChunkEventArgs&amp;gt; ChunkUpload;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;event&lt;/span&gt; EventHandler&amp;lt;ChunkEventArgs&amp;gt; ChunkDownload;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;event&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;gt; TransferComplete;&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Class&lt;/span&gt; ChunkEventArgs&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Inherits&lt;/span&gt; EventArgs&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; Status &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; ChunkLength &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; Total &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Sub&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; status &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; length &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; total &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;)&lt;br /&gt;        Status = status&lt;br /&gt;        ChunkLength = length&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Me&lt;/span&gt;.Total = total&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Class&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The &lt;b&gt;UploadFile&lt;/b&gt; method does exactly what you think: it uploads the file specified.&amp;#160; The file contents are loaded into memory, compressed, base64 encoded, and finally URL encoded.&amp;#160; Then, this large string is cut into 140 character chunks and sent to Twitter, one chunk at a time.&amp;#160; After each chunk is uploaded, the &lt;b&gt;ChunkUpload&lt;/b&gt; event is called.&amp;#160; Finally, when all chunks are uploaded, a new &lt;b&gt;FileEntry&lt;/b&gt; object is created, added to the in-memory file index, and that index is finally written to the top of the Twitter status list.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&amp;#160;&lt;b&gt; &lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; UploadFile(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; path)&lt;br /&gt;{&lt;br /&gt;    Status s = &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; startID = 0;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; length = 0;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; chunkLength = 140;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// encode the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; file = EncodeFile(path);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// upload the chunks&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;for&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; i = 0; i &amp;lt; file.Length; i+= chunkLength)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// get the proper length (i.e. don't get full 140 if we're at the end)&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; chunk = file.Substring(i, Math.Min(chunkLength, file.Length-i));&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// handle the case where we chopped a chunk in the middle of an encoded character&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// in this case, chop off the encoded data and reset the counter&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(chunk.EndsWith(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;%2&amp;quot;&lt;/span&gt;))&lt;br /&gt;        {&lt;br /&gt;            chunk = chunk.Substring(0, chunk.Length-2);&lt;br /&gt;            i -= 2;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(chunk.EndsWith(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;%&amp;quot;&lt;/span&gt;))&lt;br /&gt;        {&lt;br /&gt;            chunk = chunk.Substring(0, chunk.Length-1);&lt;br /&gt;            i -= 1;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: rgb(0,128,0)"&gt;// upload the chunk&lt;/span&gt;&lt;br /&gt;            s = _twitter.UpdateStatus(chunk);&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,128,0)"&gt;// notify listeners that we uploaded&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(ChunkUpload != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)&lt;br /&gt;                ChunkUpload(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; ChunkEventArgs(s, chunk.Length, file.Length));&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt;(TwitterRateLimitException)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; TwitterDriveException(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;Twitter upload limit reached.  Please try again later.&amp;quot;&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(i == 0)&lt;br /&gt;            startID = s.ID;&lt;br /&gt;&lt;br /&gt;        length++;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// create a new FileEntry for this file&lt;/span&gt;&lt;br /&gt;    FileEntry fe = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; FileEntry()&lt;br /&gt;    {&lt;br /&gt;        Filename = Path.GetFileName(path),&lt;br /&gt;        StartStatus = startID,&lt;br /&gt;        EndStatus = s.ID,&lt;br /&gt;        Length = length,&lt;br /&gt;        FileIndex = GetNextIndex()&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// update the index&lt;/span&gt;&lt;br /&gt;    UpdateFileIndex(fe);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// notify we're done&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(TransferComplete != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)&lt;br /&gt;        TransferComplete(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; UploadFile(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; filepath &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; s &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status = &lt;span style="color: rgb(0,0,255)"&gt;Nothing&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; startID &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 0&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; length &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 0&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; chunkLength &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 140&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' encode the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; file &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt; = EncodeFile(filepath)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' upload the chunks&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;For&lt;/span&gt; i &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 0 &lt;span style="color: rgb(0,0,255)"&gt;To&lt;/span&gt; file.Length - 1 &lt;span style="color: rgb(0,0,255)"&gt;Step&lt;/span&gt; chunkLength&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' get the proper length (i.e. don't get full 140 if we're at the end)&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; chunk &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt; = file.Substring(i, Math.Min(chunkLength, file.Length-i))&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' handle the case where we chopped a chunk in the middle of an encoded character&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' in this case, chop off the encoded data and reset the counter&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; chunk.EndsWith(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;%2&amp;quot;&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;            chunk = chunk.Substring(0, chunk.Length-2)&lt;br /&gt;            i -= 2&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; chunk.EndsWith(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;%&amp;quot;&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;            chunk = chunk.Substring(0, chunk.Length-1)&lt;br /&gt;            i -= 1&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Try&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,128,0)"&gt;' upload the chunk&lt;/span&gt;&lt;br /&gt;            s = _twitter.UpdateStatus(chunk)&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,128,0)"&gt;' notify listeners that we uploaded&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;RaiseEvent&lt;/span&gt; ChunkUpload(&lt;span style="color: rgb(0,0,255)"&gt;Me&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; ChunkEventArgs(s, chunk.Length, file.Length))&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Catch&lt;/span&gt; e1 &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; TwitterRateLimitException&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;Throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; TwitterDriveException(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;Twitter upload limit reached.  Please try again later.&amp;quot;&lt;/span&gt;)&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; i = 0 &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;            startID = s.ID&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        length += 1&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Next&lt;/span&gt; i&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' create a new FileEntry for this file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; fe &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; FileEntry() &lt;span style="color: rgb(0,0,255)"&gt;With&lt;/span&gt; {.Filename = Path.GetFileName(filepath), .StartStatus = startID, .EndStatus = s.ID, .Length = length, .FileIndex = GetNextIndex()}&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' update the index&lt;/span&gt;&lt;br /&gt;    UpdateFileIndex(fe)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' notify we're done&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;RaiseEvent&lt;/span&gt; TransferComplete(&lt;span style="color: rgb(0,0,255)"&gt;Me&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;Nothing&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;Let’s take a closer look at the &lt;b&gt;EncodeFile&lt;/b&gt; method:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; EncodeFile(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; path)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// load the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] buff = File.ReadAllBytes(path);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// compress&lt;/span&gt;&lt;br /&gt;    MemoryStream ms = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; MemoryStream();&lt;br /&gt;    GZipStream gs = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; GZipStream(ms, CompressionMode.Compress);&lt;br /&gt;    gs.Write(buff, 0, buff.Length);&lt;br /&gt;    gs.Close();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] buffCompressed = ms.ToArray();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// base64, urlencode&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; HttpUtility.UrlEncode(Convert.ToBase64String(buffCompressed));&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; EncodeFile(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; path &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' load the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; buff() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = File.ReadAllBytes(path)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' compress&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; ms &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; MemoryStream()&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; gs &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; GZipStream(ms, CompressionMode.Compress)&lt;br /&gt;    gs.Write(buff, 0, buff.Length)&lt;br /&gt;    gs.Close()&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; buffCompressed() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = ms.ToArray()&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' base64, urlencode&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; HttpUtility.UrlEncode(Convert.ToBase64String(buffCompressed))&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;The code here reads the bytes of a file into a byte array.&amp;#160; Then, a &lt;b&gt;MemoryStream&lt;/b&gt; object is created and tied to a &lt;b&gt;GZipStream&lt;/b&gt; (compression) object.&amp;#160; Next, the byte array is written to the stream which will compress the data on the fly.&amp;#160; Once the stream is closed, calling &lt;b&gt;ToArray&lt;/b&gt; on the &lt;b&gt;MemoryStream&lt;/b&gt; will return a byte array of the compressed data.&amp;#160; The byte array is base64 encoded (turned into text) and finally URL encoded so it can be sent to Twitter.&lt;/p&gt;

&lt;p&gt;The file index is written at the end of each file upload.&amp;#160; The index is comprised of a delimited string which contains the data in the &lt;b&gt;FileEntry&lt;/b&gt; object.&amp;#160; Each file is uploaded as one tweet, with an end marker to denote where the file index ends.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; WriteFileEntries()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// write an end marker (write this first since they come out in reverse order later)&lt;/span&gt;&lt;br /&gt;    _twitter.UpdateStatus(FileEntryEnd);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;for&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; i = 0; i &amp;lt; _fileEntries.Count; i++)&lt;br /&gt;        WriteFileEntry(_fileEntries[i]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; WriteFileEntry(FileEntry fe)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// simple delimited list of data&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; entry = &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;.Format(FileEntryHeader +&lt;br /&gt;                                &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{0}&amp;quot;&lt;/span&gt; + FileEntrySeparator + &lt;br /&gt;                                &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{1}&amp;quot;&lt;/span&gt; + FileEntrySeparator +&lt;br /&gt;                                &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{2}&amp;quot;&lt;/span&gt; + FileEntrySeparator +&lt;br /&gt;                                &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{3}&amp;quot;&lt;/span&gt; + FileEntrySeparator +&lt;br /&gt;                                &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{4}&amp;quot;&lt;/span&gt;, &lt;br /&gt;                                fe.Filename, fe.StartStatus, fe.EndStatus, fe.Length, fe.FileIndex);&lt;br /&gt;    _twitter.UpdateStatus(entry);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Sub&lt;/span&gt; WriteFileEntries()&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' write an end marker (write this first since they come out in reverse order later)&lt;/span&gt;&lt;br /&gt;    _twitter.UpdateStatus(FileEntryEnd)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; i &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 0&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Do&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;While&lt;/span&gt; i &amp;lt; _fileEntries.Count&lt;br /&gt;        WriteFileEntry(_fileEntries(i))&lt;br /&gt;        i += 1&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Sub&lt;/span&gt; WriteFileEntry(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; fe &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; FileEntry)&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' simple delimited list of data&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; entry &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt; = &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;.Format(FileEntryHeader &amp;amp; &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{0}&amp;quot;&lt;/span&gt; &amp;amp; FileEntrySeparator &amp;amp; &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{1}&amp;quot;&lt;/span&gt; &amp;amp; FileEntrySeparator &amp;amp; &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{2}&amp;quot;&lt;/span&gt; &amp;amp; FileEntrySeparator &amp;amp; &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{3}&amp;quot;&lt;/span&gt; &amp;amp; FileEntrySeparator &amp;amp; &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;{4}&amp;quot;&lt;/span&gt;, fe.Filename, fe.StartStatus, fe.EndStatus, fe.Length, fe.FileIndex)&lt;br /&gt;    _twitter.UpdateStatus(entry)&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;A file list can be retrieved and parsed out with the following code:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; IList&amp;lt;FileEntry&amp;gt; GetFileIndex()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;bool&lt;/span&gt; end = &lt;span style="color: rgb(0,0,255)"&gt;false&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; page = 1;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// the index should be the last things tweeted, but if we have a failed upload, it may not be&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;while&lt;/span&gt;(!end &amp;amp;&amp;amp; page &amp;lt; 5)&lt;br /&gt;    {&lt;br /&gt;        IList&amp;lt;Status&amp;gt; indexes = _twitter.GetUserTimeline(page, 200);&lt;br /&gt;&lt;br /&gt;        _fileEntries.Clear();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// parase out the file entries&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;foreach&lt;/span&gt;(Status index &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; indexes)&lt;br /&gt;        {&lt;br /&gt;            FileEntry fe = ParseFileIndexString(index.Text);&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(fe != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                fe.IndexStatusId = index.ID;&lt;br /&gt;                _fileEntries.Add(fe);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(index.Text.StartsWith(FileEntryEnd))&lt;br /&gt;            {&lt;br /&gt;                end = &lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;;&lt;br /&gt;                &lt;span style="color: rgb(0,0,255)"&gt;break&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        page++;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; _fileEntries;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; FileEntry ParseFileIndexString(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; index)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(!index.StartsWith(FileEntryHeader))&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;[] fileEntry = index.Split(Convert.ToChar(FileEntrySeparator));&lt;br /&gt;    FileEntry fe = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; FileEntry()&lt;br /&gt;                    {&lt;br /&gt;                        Filename = fileEntry[0].Replace(FileEntryHeader, &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;.Empty),&lt;br /&gt;                        StartStatus = &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.Parse(fileEntry[1]),&lt;br /&gt;                        EndStatus = &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.Parse(fileEntry[2]),&lt;br /&gt;                        Length = &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.Parse(fileEntry[3]),&lt;br /&gt;                        FileIndex = &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.Parse(fileEntry[4])&lt;br /&gt;                    };&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; fe;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; GetFileIndex() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of FileEntry)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; [&lt;span style="color: rgb(0,0,255)"&gt;end&lt;/span&gt;] &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Boolean&lt;/span&gt; = &lt;span style="color: rgb(0,0,255)"&gt;False&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; page &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt; = 1&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' the index should be the last things tweeted, but if we have a failed upload, it may not be&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Do&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;While&lt;/span&gt; (&lt;span style="color: rgb(0,0,255)"&gt;Not&lt;/span&gt; [&lt;span style="color: rgb(0,0,255)"&gt;end&lt;/span&gt;]) &lt;span style="color: rgb(0,0,255)"&gt;AndAlso&lt;/span&gt; page &amp;lt; 5&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; indexes &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status) = _twitter.GetUserTimeline(page, 200)&lt;br /&gt;&lt;br /&gt;        _fileEntries.Clear()&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' parase out the file entries&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;For&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Each&lt;/span&gt; index &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status &lt;span style="color: rgb(0,0,255)"&gt;In&lt;/span&gt; indexes&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; fe &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; FileEntry = ParseFileIndexString(index.Text)&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; fe IsNot &lt;span style="color: rgb(0,0,255)"&gt;Nothing&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;                fe.IndexStatusId = index.ID&lt;br /&gt;                _fileEntries.Add(fe)&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; index.Text.StartsWith(FileEntryEnd) &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;                [&lt;span style="color: rgb(0,0,255)"&gt;end&lt;/span&gt;] = &lt;span style="color: rgb(0,0,255)"&gt;True&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: rgb(0,0,255)"&gt;Exit&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;For&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Next&lt;/span&gt; index&lt;br /&gt;        page += 1&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Loop&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; _fileEntries&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Private&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; ParseFileIndexString(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; index &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; FileEntry&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; (&lt;span style="color: rgb(0,0,255)"&gt;Not&lt;/span&gt; index.StartsWith(FileEntryHeader)) &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Nothing&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; fileEntry() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt; = index.Split(Convert.ToChar(FileEntrySeparator))&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; fe &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; FileEntry() &lt;span style="color: rgb(0,0,255)"&gt;With&lt;/span&gt; {.Filename = fileEntry(0).Replace(FileEntryHeader, &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;.Empty), .StartStatus = &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;.Parse(fileEntry(1)), .EndStatus = &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;.Parse(fileEntry(2)), .Length = &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;.Parse(fileEntry(3)), .FileIndex = &lt;span style="color: rgb(0,0,255)"&gt;Integer&lt;/span&gt;.Parse(fileEntry(4))}&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; fe&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;This code will retrieve the user’s timeline, loop through the tweets, looking for file index entries (those that start with the proper delimiter).&amp;#160; When one is found, the data is parsed back into a &lt;b&gt;FileEntry&lt;/b&gt; object and added to the in-memory cache.&amp;#160; You will note that the &lt;b&gt;GetFileIndex&lt;/b&gt; method will read up to 1000 tweets looking for the end marker before giving up.&lt;/p&gt;

&lt;p&gt;Now that we can upload files and build the index, we need to be able to download, decode and save a file.&amp;#160; This is done in the obviously named &lt;b&gt;DownloadFile &lt;/b&gt;method:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; DownloadFile(FileEntry fe, &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; path)&lt;br /&gt;{&lt;br /&gt;    StringBuilder sb = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; StringBuilder(fe.Length * 140);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// get statuses for this user starting/ending at the IDs for this file&lt;/span&gt;&lt;br /&gt;    IList&amp;lt;Status&amp;gt; chunks = _twitter.GetUserTimeline(fe.StartStatus-1, fe.EndStatus, 1, 200);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// order them from oldest to newest&lt;/span&gt;&lt;br /&gt;    var orderedChunks = from chunk &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; chunks&lt;br /&gt;                        orderby chunk.ID ascending&lt;br /&gt;                        select chunk;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;foreach&lt;/span&gt;(Status chunk &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; orderedChunks)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// trim off any extra characters&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; newChunk = chunk.Text.TrimEnd(&lt;span style="color: rgb(0,96,128)"&gt;'.'&lt;/span&gt;).Trim();&lt;br /&gt;        sb.Append(newChunk);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// notify listeners that we downloaded a chunk&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(ChunkDownload != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)&lt;br /&gt;            ChunkDownload(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; ChunkEventArgs(chunk, newChunk.Length, fe.Length * 140));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// decode and write the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] buff = DecodeFile(sb.ToString());&lt;br /&gt;    File.WriteAllBytes(Path.Combine(path, fe.Filename), buff);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// notify that we're done&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(TransferComplete != &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;)&lt;br /&gt;        TransferComplete(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; DownloadFile(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; fe &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; FileEntry, &lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; filepath &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; sb &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; StringBuilder(fe.Length * 140)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' get statuses for this user starting/ending at the IDs for this file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; chunks &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; IList(Of Status) = _twitter.GetUserTimeline(fe.StartStatus-1, fe.EndStatus, 1, 200)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' order them from oldest to newest&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; orderedChunks = _&lt;br /&gt;        From chunk &lt;span style="color: rgb(0,0,255)"&gt;In&lt;/span&gt; chunks _&lt;br /&gt;        Order By chunk.ID Ascending _&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Select&lt;/span&gt; chunk&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;For&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Each&lt;/span&gt; chunk &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; Status &lt;span style="color: rgb(0,0,255)"&gt;In&lt;/span&gt; orderedChunks&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' trim off any extra characters&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; newChunk &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt; = chunk.Text.TrimEnd(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;c).Trim()&lt;br /&gt;        sb.Append(newChunk)&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;' notify listeners that we downloaded a chunk&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;RaiseEvent&lt;/span&gt; ChunkDownload(&lt;span style="color: rgb(0,0,255)"&gt;Me&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; ChunkEventArgs(chunk, newChunk.Length, fe.Length * 140))&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Next&lt;/span&gt; chunk&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' decode and write the file&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; buff() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = DecodeFile(sb.ToString())&lt;br /&gt;    File.WriteAllBytes(Path.Combine(filepath, fe.Filename), buff)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' notify that we're done&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;RaiseEvent&lt;/span&gt; TransferComplete(&lt;span style="color: rgb(0,0,255)"&gt;Me&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;Nothing&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;This method returns the user’s timeline starting and ending at the tweets specified in the &lt;b&gt;FileEntry&lt;/b&gt; object.&amp;#160; The status list is ordered in ascending order (i.e. oldest to newest).&amp;#160; Each status is appended to the previous using a &lt;b&gt;StringBuilder&lt;/b&gt; object.&amp;#160; When all chunks are processed, the file is decoded and saved to the chosen location.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] DecodeFile(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; data)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// base64 to binary&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] buff = Convert.FromBase64String(data);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// decompress&lt;/span&gt;&lt;br /&gt;    MemoryStream ms = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; MemoryStream(buff);&lt;br /&gt;    GZipStream gs = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; GZipStream(ms, CompressionMode.Decompress, &lt;span style="color: rgb(0,0,255)"&gt;false&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// original&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;byte&lt;/span&gt;[] decompressed = ReadAllBytes(gs);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; decompressed;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,0,255)"&gt;Public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt; DecodeFile(&lt;span style="color: rgb(0,0,255)"&gt;ByVal&lt;/span&gt; data &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;String&lt;/span&gt;) &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt;()&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' base64 to binary&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; buff() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = Convert.FromBase64String(data)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' decompress&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; ms &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; MemoryStream(buff)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; gs &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; GZipStream(ms, CompressionMode.Decompress, &lt;span style="color: rgb(0,0,255)"&gt;False&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;' original&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; decompressed() &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;Byte&lt;/span&gt; = ReadAllBytes(gs)&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;Return&lt;/span&gt; decompressed&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;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 &lt;b&gt;GZipStream&lt;/b&gt; is used to decompress the data, and the final, uncompressed file contents are returned to the caller to be saved to the disk.&lt;/p&gt;

&lt;p&gt;Be sure to look through the entire &lt;b&gt;&lt;a class="linkification-ext" title="Linkification: http://TwitterDrive.cs/vb" href="http://TwitterDrive.cs/vb"&gt;TwitterDrive.cs/vb&lt;/a&gt;&lt;/b&gt; file for the full picture, but these are the important parts.&lt;/p&gt;

&lt;h4&gt;User Interface&lt;/h4&gt;

&lt;p&gt;The final piece is the user interface.&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="4-1-2009 4-01-42 AM" border="0" alt="4-1-2009 4-01-42 AM" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/TwitterDrive_36DE/4-1-2009%204-01-42%20AM_3.png" width="289" height="350" /&gt; &lt;/p&gt;

&lt;p&gt;A very simple UI for uploading, downloading and deleting files.&amp;#160; At the start of the application, the three TwitterDrive events are hooked: &lt;b&gt;ChunkUpload&lt;/b&gt;, &lt;b&gt;ChunkDownload&lt;/b&gt;, and &lt;b&gt;TransferComplete&lt;/b&gt;.&amp;#160; These three event handlers are used to update the progress bar on a dialog box that pops up during the file transfer.&lt;/p&gt;

&lt;p&gt;When upload or download is selected, the file is selected, and a new thread is created to start the actual process.&amp;#160; Here is what the download process looks like:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,128,0)"&gt;// start a new thread to grab the file&lt;/span&gt;&lt;br /&gt;Thread t = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Thread(() =&amp;gt; _twitterDrive.DownloadFile(fe, fbd.SelectedPath));&lt;br /&gt;t.Start();&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(_progress.ShowDialog() == DialogResult.Cancel)&lt;br /&gt;    t.Abort();&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;else&lt;/span&gt;&lt;br /&gt;    MessageBox.Show(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;File download complete.&amp;quot;&lt;/span&gt;, &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;TwitterDrive&amp;quot;&lt;/span&gt;, MessageBoxButtons.OK, MessageBoxIcon.Information);&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;VB&lt;/b&gt;&lt;/p&gt;

&lt;div style="border-bottom: silver 1px solid; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: rgb(0,128,0)"&gt;' start a new thread to grab the file&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Dim&lt;/span&gt; t &lt;span style="color: rgb(0,0,255)"&gt;As&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;New&lt;/span&gt; Thread(&lt;span style="color: rgb(0,0,255)"&gt;CType&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;Function&lt;/span&gt;() _twitterDrive.DownloadFile(fe, fbd.SelectedPath), ThreadStart))&lt;br /&gt;t.Start()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt; _progress.ShowDialog() = System.Windows.Forms.DialogResult.Cancel &lt;span style="color: rgb(0,0,255)"&gt;Then&lt;/span&gt;&lt;br /&gt;    t.Abort()&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;Else&lt;/span&gt;&lt;br /&gt;    MessageBox.Show(&lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;File download complete.&amp;quot;&lt;/span&gt;, &lt;span style="color: rgb(0,96,128)"&gt;&amp;quot;TwitterDrive&amp;quot;&lt;/span&gt;, MessageBoxButtons.OK, MessageBoxIcon.Information)&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;End&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;A new thread is created, whose &lt;b&gt;ThreadStart&lt;/b&gt; parameter is the &lt;b&gt;DownloadFile&lt;/b&gt; method of the &lt;b&gt;TwitterDrive&lt;/b&gt; class.&amp;#160; The thread is started, and the progress dialog box is shown.&amp;#160; If the progress box is cancelled, the thread is aborted, otherwise the dialog box is closed in response to the &lt;b&gt;TransferComplete&lt;/b&gt; event sent by the &lt;b&gt;TwitterDrive&lt;/b&gt; class.&lt;/p&gt;

&lt;h4&gt;Using the Application&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Create a new Twitter account for use in TwitterDrive. &lt;/li&gt;

  &lt;li&gt;Enter the credentials for this new account in the provided textboxes and click Refresh.&amp;#160; Or, if you want to download files from someone else, enter just the username and click Refresh. &lt;/li&gt;

  &lt;li&gt;Upload and download data at will. &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;And there we have it.&amp;#160; A functionally useless application that actually works.&amp;#160; Give it a try and find out what the limitations are.&amp;#160; Just be sure to use a Twitter account that isn’t your main feed otherwise you’ll have some pretty angry followers.&lt;/p&gt;

&lt;h4&gt;Thanks&lt;/h4&gt;

&lt;p&gt;A special thanks to &lt;a href="http://www.markzaugg.com/" target="_blank"&gt;Mark Zaugg&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/danielfe" target="_blank"&gt;Dan Fernandez&lt;/a&gt;, and &lt;a href="http://www.gmontrone.com/" target="_blank"&gt;Giovanni Montrone&lt;/a&gt; for helping me test this application.&amp;#160; Giovanni is also partly responsible for this horrible idea after joking that I should Twitter him a file.&amp;#160; So blame him.&lt;/p&gt;

&lt;p&gt;Also thanks to &lt;a href="http://www.betterthaneveryone.com/" target="_blank"&gt;Clint Rutkas&lt;/a&gt; for throwing together the icon (it’s a combo of the SkyDrive icon + the Twitter icon).&lt;/p&gt;

&lt;h4&gt;Bio&lt;/h4&gt;

&lt;p&gt;Brian is a &lt;a href="https://mvp.support.microsoft.com/profile/Brian.Peek"&gt;Microsoft C# MVP&lt;/a&gt; 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++ 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 &amp;quot;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0596520743/brianpcom-20"&gt;Coding4Fun: 10 .NET Programming Projects for Wiimote, YouTube, World of Warcraft, and More&lt;/a&gt;&amp;quot; published &lt;a href="http://www.oreilly.com/"&gt;O'Reilly&lt;/a&gt;. He previously co-authored the book &amp;quot;&lt;a href="http://www.amazon.com/dp/0735711410/"&gt;Debugging ASP.NET&lt;/a&gt;&amp;quot; published by New Riders.&amp;#160; Brian is also an author for MSDN's &lt;a href="http://blogs.msdn.com/coding4fun/"&gt;Coding4Fun&lt;/a&gt; website.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9525376" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web/default.aspx">web</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/april+fools+day/default.aspx">april fools day</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/holiday/default.aspx">holiday</category></item><item><title>Inherited Message Distributing</title><link>http://blogs.msdn.com/coding4fun/archive/2008/09/11/8945561.aspx</link><pubDate>Fri, 12 Sep 2008 00:35:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8945561</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8945561.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8945561</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8945561</wfw:comment><description>&lt;span id="c4fmetadata"&gt;   &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;&lt;tbody&gt;       &lt;tr class="entry_overview"&gt;         &lt;td width="50"&gt;&amp;#160;&lt;/td&gt;          &lt;td&gt;&lt;span class="entry_description"&gt;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.&lt;/span&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td colspan="2"&gt;           &lt;div class="entry_author"&gt;Robert Witoff&lt;/div&gt;           &lt;a title="http://www.chalk2me.com/" href="http://www.chalk2me.com/"&gt;http://www.chalk2me.com/&lt;/a&gt;            &lt;br /&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;3-6 hours&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Free&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://codeplex.com/chalk2me"&gt;Download&lt;/a&gt; &lt;/div&gt;            &lt;div class="entry_details"&gt;&amp;#160;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;strong&gt;&lt;font color="#c40000"&gt;Disclaimer: &lt;/font&gt;&lt;/strong&gt;Currently this article is C# only.&amp;#160; If you want it in Visual Basic.Net, please comment and tell us so we can transcode it to VB.&lt;/div&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;p&gt;&lt;b&gt;Starting Out:&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;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:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;struct&lt;/span&gt; ctMessage
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ctMessage(&lt;span class="kwrd"&gt;string&lt;/span&gt; sendToUser, &lt;span class="kwrd"&gt;string&lt;/span&gt; fromUser, &lt;span class="kwrd"&gt;string&lt;/span&gt; subj, &lt;span class="kwrd"&gt;string&lt;/span&gt; msg, &lt;span class="kwrd"&gt;string&lt;/span&gt;

    mediumType, &lt;span class="kwrd"&gt;string&lt;/span&gt; mediumArg1, &lt;span class="kwrd"&gt;string&lt;/span&gt; mediumArg)
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.toUser = sendToUser;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.fromUser = fromUser;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.subject = subj;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.message = msg;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mediumType = mediumType;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mediumArg1 = mediumArg1;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mediumArg2 = mediumArg2;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; toUser; &lt;span class="rem"&gt;//name of recipient&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; fromUser; &lt;span class="rem"&gt;//name of sender&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; subject;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; message;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mediumType; &lt;span class="rem"&gt;//which node should deliver this&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mediumArg1; &lt;span class="rem"&gt;//varies, to identify the recipient&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mediumArg2; &lt;span class="rem"&gt;//varies, to identify the recipient&lt;/span&gt;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ctNode
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ctNode()
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.maxQueueSize = 100; &lt;span class="rem"&gt;//Set the size according to how long it will take to reach the Nth message&lt;/span&gt;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.msgQueue = &lt;span class="kwrd"&gt;new&lt;/span&gt; Queue(maxQueueSize);
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.msPauseAfterRun = 10000; &lt;span class="rem"&gt;//If using a DB, polling it with no pause b/w queries is an unnecessary load&lt;/span&gt;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.runnerThread = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(&lt;span class="kwrd"&gt;new&lt;/span&gt; ThreadStart(&lt;span class="kwrd"&gt;this&lt;/span&gt;.run));
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; Thread runnerThread;
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; msPauseAfterRun;
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; Queue msgQueue;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; maxQueueSize;

    &lt;span class="kwrd"&gt;void&lt;/span&gt; run()
    {
        &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
        {
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.msgQueue.Count &amp;gt; 0)
            {
                &lt;span class="rem"&gt;//pop a message and send it&lt;/span&gt;
                ctMessage ctm = (ctMessage)msgQueue.Dequeue();

                &lt;span class="kwrd"&gt;try&lt;/span&gt;
                {
                    sendSingleMessage(ctm);
                }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)
                {
                    &lt;span class="rem"&gt;//Write a more detailed error log here&lt;/span&gt;
                    Console.writeLine(&lt;span class="str"&gt;&amp;quot;the message could not be sent!&amp;quot;&lt;/span&gt; + e.toString());
                }
            }

            &lt;span class="rem"&gt;//get new messages&lt;/span&gt;
            ctNode ctn = &lt;span class="kwrd"&gt;this&lt;/span&gt;;
            ctMessage[] newMessages = messageSender.getMessages(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ctn, getRoomInQueue());

            &lt;span class="rem"&gt;//Wait some time before checking for more messages!&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (newMessages.Length == 0)
                Thread.Sleep(msPauseAfterRun);
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
                &lt;span class="kwrd"&gt;this&lt;/span&gt;.EnqueueMessages(newMessages);
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EnqueueMessages(ctMessage[] messagesToSend)
    {
        &lt;span class="kwrd"&gt;int&lt;/span&gt; roomInQueue = maxQueueSize - msgQueue.Count;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (messagesToSend.Length &amp;gt; roomInQueue)
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Too many Messages have been inserted&amp;quot;&lt;/span&gt;);

        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; messagesToSend.Length; i++)
        {
            msgQueue.Enqueue(messagesToSend[i]);
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EnqueueMessages(ctMessage messageToSend)
    {
        ctMessage[] ctm = &lt;span class="kwrd"&gt;new&lt;/span&gt; ctMessage[1];
        ctm[0] = messageToSend;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.EnqueueMessages(ctm);
    }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; sendSingleMessage(ctMessage ctm)
    {
        &lt;span class="rem"&gt;//code to send an individual message&lt;/span&gt;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; startThread()
    {
        runnerThread.Name = &lt;span class="kwrd"&gt;this&lt;/span&gt;.nodeType;
        runnerThread.Start();
    }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; nodeType;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; getNodeType()
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.nodeType;
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; messageSender
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;ctMessage&amp;gt; messagesToSend = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;ctMessage&amp;gt;();

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ctMessage[] getMessages(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ctNode nodeRef, &lt;span class="kwrd"&gt;int&lt;/span&gt; numberOfMessages)
    {
        &lt;span class="rem"&gt;//We'll do this in a database later, but for now this works similarly&lt;/span&gt;
        List&amp;lt;ctMessage&amp;gt; returnMessages = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;ctMessage&amp;gt;();

        &lt;span class="kwrd"&gt;lock&lt;/span&gt; (messagesToSend)
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; messagesToSend.Count; i++)
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (messagesToSend[i].mediumArgs == nodeRef.getNodeType())
                {
                    returnMessages.Add(messagesToSend[i]);
                    messagesToSend.RemoveAt(i);
                    i--;
                }

        &lt;span class="kwrd"&gt;return&lt;/span&gt; returnMessages.ToArray();
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; sendMessage(ctMessage message)
    {
        &lt;span class="kwrd"&gt;lock&lt;/span&gt; (messagesToSend)
            messagesToSend.Add(message);
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;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!&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ctMessage ctm = &lt;span class="kwrd"&gt;new&lt;/span&gt; ctMessge(&lt;span class="str"&gt;&amp;quot;Friend&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Developer&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;testing&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;My first message&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;yourEmail@yourDomain.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
messageSender.sendMessage(ctm);

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ctNodeEmail : ctNode
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ctNodeEmail() : &lt;span class="kwrd"&gt;base&lt;/span&gt;()
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.nodeType = &lt;span class="str"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;;

        &lt;span class="rem"&gt;//&lt;/span&gt;
        &lt;span class="rem"&gt;//SET UP SMTP CLIENT&lt;/span&gt;
        &lt;span class="rem"&gt;//&lt;/span&gt;

        &lt;span class="rem"&gt;//GMAIL SERVER&lt;/span&gt;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient = &lt;span class="kwrd"&gt;new&lt;/span&gt; SmtpClient(&lt;span class="str"&gt;&amp;quot;gmail.com/mail&amp;quot;&lt;/span&gt;, 25);
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Host = &lt;span class="str"&gt;&amp;quot;smtp.gmail.com&amp;quot;&lt;/span&gt;;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Port = 25;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.EnableSsl = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Credentials = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.NetworkCredential(&lt;span class="str"&gt;&amp;quot;YOURADDRESS@gmail.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;YOUR_PASSWORD&amp;quot;&lt;/span&gt;);

        &lt;span class="rem"&gt;//LOCAL SERVER&lt;/span&gt;
        &lt;span class="rem"&gt;//this.mSmtpClient = new SmtpClient(&amp;quot;localhost&amp;quot;, 25);&lt;/span&gt;
    }

    SmtpClient mSmtpClient;

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; sendSingleMessage(ctMessage ctm)
    {
        MailMessage msgMail = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailMessage(&lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(ctm.fromUser + &lt;span class="str"&gt;&amp;quot;@ChalkTalkNow.com&amp;quot;&lt;/span&gt;), &lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(ctm.mediumArgs));
        msgMail.Subject = ctm.subject;
        &lt;span class="kwrd"&gt;string&lt;/span&gt; msg = ctm.message;
        msgMail.Body = msg;

        &lt;span class="rem"&gt;// Send the mail message&lt;/span&gt;
        mSmtpClient.Send(msgMail);
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ctNodeTextMessage : ctNode
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ctNodeTextMessage() : &lt;span class="kwrd"&gt;base&lt;/span&gt;()
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.nodeType = &lt;span class="str"&gt;&amp;quot;textmessage&amp;quot;&lt;/span&gt;;

        &lt;span class="rem"&gt;//&lt;/span&gt;
        &lt;span class="rem"&gt;//SET UP SMTP CLIENT&lt;/span&gt;
        &lt;span class="rem"&gt;//&lt;/span&gt;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient = &lt;span class="kwrd"&gt;new&lt;/span&gt; SmtpClient(&lt;span class="str"&gt;&amp;quot;gmail.com/mail&amp;quot;&lt;/span&gt;, 25);
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Host = &lt;span class="str"&gt;&amp;quot;smtp.gmail.com&amp;quot;&lt;/span&gt;;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Port = 25;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.EnableSsl = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Credentials = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.NetworkCredential(&lt;span class="str"&gt;&amp;quot;GMAIL@gmail.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;PASSWORD&amp;quot;&lt;/span&gt;);

    }
    SmtpClient mSmtpClient;

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; getEmailAddress(&lt;span class="kwrd"&gt;string&lt;/span&gt; phoneNumber, &lt;span class="kwrd"&gt;string&lt;/span&gt; provider)
    {
        &lt;span class="kwrd"&gt;switch&lt;/span&gt; (provider)
        {
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;t-mobile&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@tmomail.net&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;virginmobile&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@vmobl.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;cingular&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@cingularme.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;att&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@cingularme.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;sprint&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@messaging.sprintpcs.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;verizon&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@vtext.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;nextel&amp;quot;&lt;/span&gt;:
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@messaging.nextel.com&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;default&lt;/span&gt;:
                &lt;span class="rem"&gt;//assume cingular/att is the most popular&lt;/span&gt;
                &lt;span class="kwrd"&gt;return&lt;/span&gt; phoneNumber + &lt;span class="str"&gt;&amp;quot;@cingularme.com&amp;quot;&lt;/span&gt;;
        }
    }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; sendSingleMessage(ctMessage ctm)
    {
        &lt;span class="rem"&gt;//send a single message&lt;/span&gt;
        &lt;span class="kwrd"&gt;string&lt;/span&gt; emailAddress = getEmailAddress(ctm.mediumArg1, ctm.mediumArg2);

        MailMessage msgMail = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailMessage(&lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(ctm.fromUser + &lt;span class="str"&gt;&amp;quot;@chalktalk.net&amp;quot;&lt;/span&gt;, ctm.fromUser), &lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(emailAddress));
        msgMail.Subject = ctm.subject;
        msgMail.Body = ctm.message;
        sendEmail(msgMail);
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; sendEmail(MailMessage msgMail)
    {
        &lt;span class="rem"&gt;// Send the mail message&lt;/span&gt;
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.mSmtpClient.Send(msgMail);
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;Now to test this out, just like we sent the email we’ll send a text. Cool!&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ctMessage ctm = &lt;span class="kwrd"&gt;new&lt;/span&gt; ctMessge(&lt;span class="str"&gt;&amp;quot;Friend&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Developer&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;testing&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;hello world via text&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;textmessage&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;#########&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;verizon&amp;quot;&lt;/span&gt;);
messageSender.sendMessage(ctm);&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;h3&gt;Conclusion:&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;Next Steps:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Build a UI to manage content and run your messaging! &lt;/li&gt;

  &lt;li&gt;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’. &lt;/li&gt;

  &lt;li&gt;Strongly type all textual identifiers in enumerations to avoid any frustrating mistakes. &lt;/li&gt;

  &lt;li&gt;Find an SDK for your favorite messenger, and build a node for it &lt;/li&gt;

  &lt;li&gt;Join our team and continue to build with us! &lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8945561" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web/default.aspx">web</category></item><item><title>BlueBoss - Bluetooth Proximity Detection</title><link>http://blogs.msdn.com/coding4fun/archive/2008/06/26/8658548.aspx</link><pubDate>Fri, 27 Jun 2008 01:09:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8658548</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8658548.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8658548</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8658548</wfw:comment><description>&lt;h3&gt;Summary:&lt;/h3&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt; Bluetooth is now found in a variety of devices and enable the user to use wireless accessories.&amp;#160; The Bluetooth protocol allows a user to “discover” any device that is in proximity to your Bluetooth radio.&amp;#160; Why not see who is in proximity to you?&amp;#160; Why not have the presence of a device execute programs or alert you?&lt;/p&gt;  &lt;p&gt;Andy Konkol – &lt;u&gt;&lt;a href="http://copyandwaste.com/"&gt;http://copyandwaste.com&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Hardware:&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;Bluetooth radio (USB dongle)&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;SMA Female Jack&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;SMA male to N-male pigtail&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;2.4 GHz antenna (with N-female connector)&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Software:&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;&lt;u&gt;&lt;a href="http://www.microsoft.com/express/samples/c4fdevkit/default.aspx"&gt;Coding4fun Developer Kit&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;u&gt;&lt;a href="http://www.codeproject.com/KB/miscctrl/RobMisNotifyWindow.aspx"&gt;Robert Misiak's Notify Window&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Download:&lt;/strong&gt; &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;&lt;a href="http://www.codeplex.com/blueboss/Release/ProjectReleases.aspx?ReleaseId=14662"&gt;Source / Binary Download&lt;/a&gt;&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;u&gt;&lt;/u&gt;&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Bluetooth and Hardware:&lt;/strong&gt;&lt;/h3&gt;  &lt;br /&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;Bluetooth was designed for devices to communicate wirelessly over short distances.&amp;#160; 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). &lt;/p&gt;  &lt;p&gt;Modifying Bluetooth dongles to accept external antennas is documented all over the Internet.&amp;#160; In principle it is very easy: find the antenna lead and solder on a connector/antenna.&amp;#160; I purchased a very cheap Bluetooth USB dongle on eBay and opened the casing.&amp;#160; After finding the antenna trace on the circuit board I soldered on a SMA Female connector to it.&amp;#160; 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;#160; 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. &lt;/p&gt;  &lt;p&gt;To connect an external antenna to the dongle I needed to use a connector converter called a pigtail.&amp;#160; I used a SMA male to N-male pigtail.&amp;#160; 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.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/BlueBoss_F144/IMG_20701.jpg"&gt;&lt;img title="IMG_2070[1]" height="180" alt="IMG_2070[1]" src="http://www.coding4fun.net/images/BlueBoss_F144/IMG_20701_thumb.jpg" width="240" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.coding4fun.net/images/BlueBoss_F144/IMG_20711.jpg"&gt;&lt;img title="IMG_2071[1]" height="180" alt="IMG_2071[1]" src="http://www.coding4fun.net/images/BlueBoss_F144/IMG_20711_thumb.jpg" width="240" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Software:&lt;/strong&gt;&lt;/h3&gt;  &lt;br /&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;To take advantage of my newly modified hardware I needed to download the Coding4Fun Toolkit.&amp;#160; Included in the toolkit is an API for Bluetooth devices.&amp;#160; 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. &lt;/p&gt;  &lt;p&gt;DiscoverAllDevices allows you to “scan” the airwaves on the 2.4 GHz band and report back what devices your radio sees. &lt;/p&gt;  &lt;p&gt;DiscoverDeviceByName allows you to scan for a particular device with a specified name and report back if it is present or not.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;i&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; DevicePresent()
{
    BluetoothDeviceServicesManager workerBTMgr = &lt;span class="kwrd"&gt;new&lt;/span&gt; BluetoothDeviceServicesManager();
    Device workerDevice = workerBTMgr.DiscoverDeviceByName(_watchItem.DeviceName);

    &lt;span class="kwrd"&gt;return&lt;/span&gt; (workerDevice != &lt;span class="kwrd"&gt;null&lt;/span&gt;);
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Run(String Operation)
{
    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (Operation)
    {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;SingleDevice&amp;quot;&lt;/span&gt;:
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (DevicePresent())
            {
                _parentForm.Invoke(_parentForm.AddToDeviceSeenList, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { _watchItem });
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                _parentForm.Invoke(_parentForm.RemoveFromDeviceSeenList, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { _watchItem });
            }
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;AllDevices&amp;quot;&lt;/span&gt;:
            BluetoothDeviceServicesManager workerBTMgr = &lt;span class="kwrd"&gt;new&lt;/span&gt; BluetoothDeviceServicesManager();
            List&amp;lt;Device&amp;gt; Devices = workerBTMgr.DiscoverAllDevices();
            _parentForm.Invoke(_parentForm.ThreadUpdateDiscoverBox, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { Devices });
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;Both of these methods require that the device you are scanning for is in discoverable mode (which most manufacturers enable by default).&amp;#160; 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. &lt;/p&gt;

&lt;p&gt;To perform device discovery and not have my UI lag I had to create two worker threads.&amp;#160; 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.”&amp;#160; I am not an expert at multi-threaded programs but I managed to implement them without any major headaches.&lt;/p&gt;

&lt;h3&gt;User Interface:&lt;/h3&gt;

&lt;p&gt;Since the “Add to watchlist” and “Edit” buttons essentially do the same thing, I decided to overload a windows form.&amp;#160; I also wanted to keep track of the parent form and disable it when the WatchItemForm was shown. &lt;/p&gt;

&lt;p&gt;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).&amp;#160; &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; WatchItemForm(Form1 f, String DeviceName)
{
    InitializeComponent();
    &lt;span class="kwrd"&gt;this&lt;/span&gt;._parentForm = f;
    lblDeviceName.Text = DeviceName;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; WatchItemForm(Form1 f, WatchItem item)
{
    InitializeComponent();
    &lt;span class="kwrd"&gt;this&lt;/span&gt;._parentForm = f;

    lblDeviceName.Text = item.DeviceName;
    tbxPicturePath.Text = item.ImagePath;
    tbxProgramPath.Text = item.ProgramPath;
    &lt;span class="kwrd"&gt;this&lt;/span&gt;._parentForm.Enabled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;I wanted to have a pop up notify window similar to outlook and was able to find Robert Misiak's &lt;a href="http://www.codeproject.com/KB/miscctrl/RobMisNotifyWindow.aspx"&gt;NotifyWindow&lt;/a&gt;. This is a very simple library which allows you to create pop up notify windows very easily. I edited &lt;strong&gt;NotifyWindow&lt;/strong&gt; to include a “picturepath” variable as well as picturebox on the form. As you can see creating a &lt;strong&gt;NotifyWindow&lt;/strong&gt; is quite easy:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; NotifyDeviceWindow(WatchItem x)
{
    NotifyWindow nw;
    nw = &lt;span class="kwrd"&gt;new&lt;/span&gt; NotifyWindow();
    &lt;span class="rem"&gt;//validate Alert Message&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (x.AlertMessage == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        nw.Text = x.DeviceName;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        nw.Text = x.AlertMessage;
    }
    &lt;span class="rem"&gt;//validate picture&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (x.ImagePath != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        FileInfo imgfile = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileInfo(x.ImagePath);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (imgfile.Exists)
        {
            nw.PicturePath = x.ImagePath;
        }
        &lt;span class="kwrd"&gt;else&lt;/span&gt;
        {
            MessageBox.Show(&lt;span class="str"&gt;&amp;quot;Image does not exist&amp;quot;&lt;/span&gt;);
        }
    }
    nw.Notify();

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (x.ProgramPath != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        RunProcess(x.ProgramPath);
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }&lt;/style&gt;

&lt;p&gt;&lt;strong&gt;Process Flow/Software Operation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;User clicks the “Discover” button, a thread is spawned which enumerates all Bluetooth devices in proximity &lt;/li&gt;

  &lt;li&gt;Thread finishes and updates the Devices listbox &lt;/li&gt;

  &lt;li&gt;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 &lt;/li&gt;

  &lt;li&gt;User clicks save , a WatchItem object is created and added to the watchList object &lt;/li&gt;

  &lt;li&gt;A timer starts and every 10 seconds a thread is spawned to discover that device by name &lt;/li&gt;

  &lt;li&gt;If the device is discovered, it is added to the “deviceSeenList” and a notify alert is sent and the executable is executed. &lt;/li&gt;

  &lt;li&gt;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” &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Screenshots:&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/BlueBoss_F144/bbmain1.jpg"&gt;&lt;img title="bb-main[1]" height="319" alt="bb-main[1]" src="http://www.coding4fun.net/images/BlueBoss_F144/bbmain1_thumb.jpg" width="470" border="0" /&gt;&lt;/a&gt;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&lt;a href="http://www.coding4fun.net/images/BlueBoss_F144/bbwatchitem1.jpg"&gt;&lt;img title="bb-watchitem[1]" height="210" alt="bb-watchitem[1]" src="http://www.coding4fun.net/images/BlueBoss_F144/bbwatchitem1_thumb.jpg" width="257" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.coding4fun.net/images/BlueBoss_F144/bbnotify_11.jpg"&gt;&lt;img title="bb-notify_1[1]" height="173" alt="bb-notify_1[1]" src="http://www.coding4fun.net/images/BlueBoss_F144/bbnotify_11_thumb.jpg" width="226" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ol&gt;&lt;/ol&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8658548" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category></item><item><title>A Better Startup Experience</title><link>http://blogs.msdn.com/coding4fun/archive/2008/03/17/8290797.aspx</link><pubDate>Mon, 17 Mar 2008 18:55:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8290797</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>16</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8290797.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8290797</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8290797</wfw:comment><description>&lt;span id="c4fmetadata"&gt;   &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;&lt;tbody&gt;       &lt;tr class="entry_overview"&gt;         &lt;td width="50"&gt;&lt;a href="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/flag.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="52" alt="flag" src="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/flag_thumb.png" width="52" border="0" /&gt;&lt;/a&gt; &lt;/td&gt;          &lt;td&gt;&lt;span class="entry_description"&gt;Does Windows take too long starting up before you can get to work?&amp;#160; Wouldn't it better if things could startup at a lower priority?&amp;#160; Learn how to launch processes, use performance counters, monitor files, and run tasks in the background.&lt;/span&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td colspan="2"&gt;           &lt;div class="entry_author"&gt;Arian Kulp&lt;/div&gt;            &lt;div class="entry_company"&gt;&lt;a href="http://www.ariankulp.com"&gt;Arian's Blog&lt;/a&gt;&lt;/div&gt;            &lt;br /&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;1-3 hours&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Free&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;span class="entry_details_input"&gt;&lt;b&gt;Hardware: &lt;/b&gt;None&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;              &lt;ul&gt;               &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=390525"&gt;C# Download&lt;/a&gt; &lt;/li&gt;                &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=390526"&gt;VB Download&lt;/a&gt; &lt;/li&gt;             &lt;/ul&gt;           &lt;/div&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;p&gt;&lt;a href="http://www.peacelovecode.com/code/silverlight/puzzle/1.0.0.0/surfacePuzzleDemoVB.zip"&gt;&lt;/a&gt;&lt;/p&gt; &lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
	overflow: auto;
}
.csharpcode pre { 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; }&lt;/style&gt;  &lt;h2&gt;Introduction&lt;/h2&gt;  &lt;p&gt;Starting up Windows usually takes longer than I'd like it to.&amp;#160; It seems like the system is churning away for ages.&amp;#160; I've often thought that it would make more sense to wait as each item starts up before starting the next item.&amp;#160; The problem is Windows has no idea how long an application takes to initialize itself.&amp;#160; After launching it, it's just another running process.&amp;#160; 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;#160; I decided to put this idea into action.&lt;/p&gt;  &lt;p&gt;This application requires Visual Studio 2005 Express Editions (C# or Visual Basic) or higher.&amp;#160; This will be my last Coding 4 Fun article targeting Visual Studio 2005.&amp;#160; If you haven't downloaded a Visual Studio 2008 Express Edition yet, definitely check them out.&amp;#160; The upgrade is very much worth it!&lt;/p&gt;  &lt;h2&gt;Starting Up&lt;/h2&gt;  &lt;p&gt;The basic idea of the program is very simple: launch each startup item with a configurable delay between each one.&amp;#160; Beyond a simple delay though, it might be good to see how active the system is.&amp;#160; If the CPU is working hard, maybe it would be good to wait until it settles down before launching something else.&lt;/p&gt;  &lt;p&gt;In case you've never looked closely, there are a few ways that Windows knows what to startup with the system.&amp;#160; The three most common ways to start things are by using the Registry, the Startup folder, or by configuring services.&amp;#160; The Registry and Startup folder methods are pretty similar.&amp;#160; Of course Services are background processes that run even if a user isn't logged in.&lt;/p&gt;  &lt;p&gt;Once a user logs in, the Registry and Startup folders take effect.&amp;#160; The system Registry is a collection of keys, values, and data that applications (and Windows itself) use for configuration.&amp;#160; One such use is to contain a list of programs to launch with Windows.&amp;#160; There is a system-level and user-level list.&amp;#160; System-level programs are started up for every user that logs in, while user-level programs are started only for the specific user.&lt;/p&gt;  &lt;p&gt;The Startup folder works the same way.&amp;#160; As part of each user's profile folder there is a Startup folder.&amp;#160; There is also one at the Default User level.&amp;#160; These folders contain shortcuts to applications.&amp;#160; Whenever a user logs in, all of these shortcuts are launched.&amp;#160; We just need to take over this process.&amp;#160; To do this though, we'll need to take the shortcuts out of the system Startup folders.&lt;/p&gt;  &lt;h2&gt;The Basics&lt;/h2&gt;  &lt;p&gt;The Startup Optimizer works by scanning the user's &lt;strong&gt;Startup &lt;/strong&gt;folder looking for shortcuts.&amp;#160; As a new shortcut is found, a &lt;strong&gt;StartupEntry &lt;/strong&gt;object is created.&amp;#160; This object holds the filename, a display name and a few flags.&amp;#160; The key flag is &lt;strong&gt;Managed&lt;/strong&gt;.&amp;#160; An object with &lt;strong&gt;Managed &lt;/strong&gt;set to &lt;strong&gt;True&lt;/strong&gt; is launched by the application and moved to a new &lt;strong&gt;ManagedStartup &lt;/strong&gt;folder in the user's profile.&lt;/p&gt;  &lt;p&gt;When a file or shortcut is detected in the &lt;strong&gt;Startup &lt;/strong&gt;folder, a popup will occur to let a user decide if the program should manage it or not.&amp;#160; If so, it moves the shortcut to its &lt;strong&gt;ManagedStartup &lt;/strong&gt;folder.&amp;#160; If not, it leaves it alone but sets the &lt;strong&gt;Managed &lt;/strong&gt;flag to &lt;strong&gt;False&lt;/strong&gt;.&amp;#160; Next time it notices the same shortcut, it will just now to ignore it and let Windows handle it.&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/image.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="160" alt="Startup Item Encountered" src="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/image_thumb.png" width="385" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;Figure 1: The dialog shown when a startup item is found&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/image_3.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="256" alt="Startup Item Encountered - Advanced Settings" src="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/image_thumb_3.png" width="385" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;em&gt;Figure 2: The dialog with advanced settings shown&lt;/em&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Notice the icon.&amp;#160; There's no included support for extracting the icon from a file, but you can use the Win32 &lt;strong&gt;SHGetFileInfo&lt;/strong&gt; function in the &lt;strong&gt;shell32.dll&lt;/strong&gt; library like so:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;shell32.dll&amp;quot;&lt;/span&gt;)&amp;gt; _
&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; SHGetFileInfo(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; pszPath &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;, &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; dwFileAttributes &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger, &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; psfi &lt;span class="kwrd"&gt;As&lt;/span&gt; SHFILEINFO, &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; cbSizeFileInfo &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger, &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; uFlags &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger) &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr
&lt;span class="kwrd"&gt;End&lt;/span&gt; Function&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[DllImport(&lt;span class="str"&gt;&amp;quot;shell32.dll&amp;quot;&lt;/span&gt;)] 
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; IntPtr SHGetFileInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt; pszPath, &lt;span class="kwrd"&gt;uint&lt;/span&gt; dwFileAttributes,
       &lt;span class="kwrd"&gt;ref&lt;/span&gt; SHFILEINFO psfi, &lt;span class="kwrd"&gt;uint&lt;/span&gt; cbSizeFileInfo, &lt;span class="kwrd"&gt;uint&lt;/span&gt; uFlags);&lt;/pre&gt;

&lt;p&gt;All &lt;strong&gt;StartupEntry&lt;/strong&gt; objects are added to the &lt;strong&gt;StartupEntryList&lt;/strong&gt; collection which is a subclass of &lt;strong&gt;List&amp;lt;StartupEntry&amp;gt;&lt;/strong&gt;.&amp;#160; Creating a subclass like this allows you to add helper methods for finding or removing objects or other useful functions.&amp;#160; This collection is what is saved to disk to retain the properties of each item.&amp;#160; The basic .NET binary serialization method is used due to its simplicity in code.&amp;#160; Note that any class to be serialized must be decorated with the &lt;strong&gt;Serializable &lt;/strong&gt;attribute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; FromDisk() &lt;span class="kwrd"&gt;As&lt;/span&gt; StartupEntryList
    &lt;span class="kwrd"&gt;If&lt;/span&gt; &lt;span class="kwrd"&gt;Not&lt;/span&gt; File.Exists(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;) &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        &lt;span class="kwrd"&gt;Return&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; StartupEntryList()
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; c &lt;span class="kwrd"&gt;As&lt;/span&gt; StartupEntryList
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; s &lt;span class="kwrd"&gt;As&lt;/span&gt; Stream = File.Open(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;, FileMode.Open)
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; b &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; BinaryFormatter()
    c = &lt;span class="kwrd"&gt;DirectCast&lt;/span&gt;(b.Deserialize(s), StartupEntryList)

    s.Close()

    &lt;span class="kwrd"&gt;Return&lt;/span&gt; c
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;

&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; SaveToDisk()
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; s &lt;span class="kwrd"&gt;As&lt;/span&gt; Stream = File.Open(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;, FileMode.Create)
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; b &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; BinaryFormatter()
    b.Serialize(s, &lt;span class="kwrd"&gt;Me&lt;/span&gt;)
    s.Close()
&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; StartupEntryList FromDisk() 
{ 
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!File.Exists(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;)) &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; StartupEntryList(); 

    StartupEntryList c; 
    Stream s = File.Open(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;, FileMode.Open); 
    BinaryFormatter b = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryFormatter(); 
    c = (StartupEntryList)b.Deserialize(s); 

    s.Close(); 

    &lt;span class="kwrd"&gt;return&lt;/span&gt; c; 
} 

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveToDisk() 
{ 
    Stream s = File.Open(&lt;span class="str"&gt;&amp;quot;StartupEntryList.ser&amp;quot;&lt;/span&gt;, FileMode.Create); 
    BinaryFormatter b = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryFormatter(); 
    b.Serialize(s, &lt;span class="kwrd"&gt;this&lt;/span&gt;); 
    s.Close(); 
} &lt;/pre&gt;

&lt;p&gt;Notice how the &lt;strong&gt;FromDisk()&lt;/strong&gt; method is static.&amp;#160; This works as a factory method on the &lt;strong&gt;StartupEntryList &lt;/strong&gt;class itself.&amp;#160; Subclassing that simple generic list has made it easy to encapsulate all related functionality into the same place.&lt;/p&gt;

&lt;h2&gt;Working in the Background&lt;/h2&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;p&gt;Of course at some point the application needs to perform its startup magic.&amp;#160; Obviously the main work is just launching each shortcut.&amp;#160; This is done using the &lt;strong&gt;Process.Start()&lt;/strong&gt; method in the &lt;strong&gt;System.Diagnostics&lt;/strong&gt; namespace.&amp;#160; If we were just launching the shortcuts one after another, it would be over quickly, but it would defeat the purpose of the program!&amp;#160; With delays and waiting for the CPU to go idle, this startup process could potentially take a few minutes.&amp;#160; This is important because it means that we can't just start the sequence in the &lt;strong&gt;Form_Load &lt;/strong&gt;event handler on startup.&amp;#160; The application would be unresponsive and there would be no way to abort.&lt;/p&gt;

&lt;p&gt;Enter the &lt;strong&gt;BackgroundWorker &lt;/strong&gt;class.&amp;#160; I've used this in articles before and they make it really easy to run things in the background.&amp;#160; It's much easier than creating threads -- especially if you need to update the user interface.&amp;#160; You get to avoid the &lt;strong&gt;Invoke&lt;/strong&gt; calls that are otherwise required and you even get Form Designer support.&lt;/p&gt;

&lt;p&gt;Similar to the &lt;strong&gt;StartupEntryList&lt;/strong&gt;, subclassing is a good idea in order to keep things nicely encapsulated.&amp;#160; There's actually only one method that matters in this case: the event handler for the &lt;strong&gt;DoWork &lt;/strong&gt;event.&amp;#160; This is where work is done.&amp;#160; You never call it directly (it's marked &lt;strong&gt;private&lt;/strong&gt;) -- it's invoked when the &lt;strong&gt;RunWorkerAsync &lt;/strong&gt;method is called.&amp;#160; Anything that happens in the event handler is automatically on a thread other than the UI thread.&amp;#160; It couldn't be simpler!&amp;#160; In order to cause the UI to be updated (you can't ever directly reference it due to cross-threading concerns) call the &lt;strong&gt;ReportProgress &lt;/strong&gt;method.&amp;#160; Periodically check the &lt;strong&gt;CancellationPending &lt;/strong&gt;flag to see if you need to exit.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;StartupBackgroundWorker_DoWork &lt;/strong&gt;event handler method basically just iterates over the entries that have &lt;strong&gt;Managed &lt;/strong&gt;set to true, waits for an idle CPU if necessary, and waits the specified delay time if set before moving to the next one.&amp;#160; At several points it checks to see if a cancellation has been requested.&amp;#160; The best thing though, is regardless of how long the sequence takes the UI will run smoothly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    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(&lt;span class="str"&gt;&amp;quot;No entries passed in&amp;quot;&lt;/span&gt;)
        End If

        Try
            &lt;span class="str"&gt;' Don'&lt;/span&gt;t bother &lt;span class="kwrd"&gt;if&lt;/span&gt; there aren&lt;span class="str"&gt;'t any entries!
            If entries.Count &amp;gt; 0 Then
                Me.ReportProgress(0, &amp;quot;Startup Optimizer will begin in five seconds.  Click to cancel.&amp;quot;)
                Dim i As Integer = 0
                While i &amp;lt; 5 AndAlso Not Me.CancellationPending
                    Thread.Sleep(1000)
                    i += 1
                End While

                If Me.CancellationPending Then
                    e.Cancel = True
                    Return
                End If
            End If

            systemIdleComponent1.Enabled = True

            '&lt;/span&gt; Process entries to perform startup
            For Each entry As StartupEntry In entries
                If entry.Managed Then
                    If entry.WaitForLowCPU Then
                        Me.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Waiting for idle CPU to launch: &amp;quot;&lt;/span&gt; + entry.DisplayName)

                        &lt;span class="str"&gt;' CPU wait routine...
                        '&lt;/span&gt; TODO: Give up &lt;span class="kwrd"&gt;if&lt;/span&gt; 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, &lt;span class="str"&gt;&amp;quot;Starting: &amp;quot;&lt;/span&gt; + entry.DisplayName)

                    &lt;span class="str"&gt;' Don'&lt;/span&gt;t actually start &lt;span class="kwrd"&gt;if&lt;/span&gt; we are debugging
                    If Not Debugger.IsAttached Then
                        Process.Start(Path.Combine(My.Settings.ManagedStartupPath, entry.FileName))
                    Else
                        &lt;span class="str"&gt;'SIMULATE STARTUP DELAY
                        Thread.Sleep(2000)
                    End If

                    Me.ReportProgress(0, &amp;quot;Started: &amp;quot; + entry.DisplayName)

                    If entry.DelayTime &amp;gt; 0 Then
                        Me.ReportProgress(0, &amp;quot;Waiting: &amp;quot; + entry.DelayTime + &amp;quot; seconds until next item&amp;quot;)
                        For x As Integer = 0 To entry.DelayTime - 1

                            '&lt;/span&gt; Wait the number of seconds but check &lt;span class="kwrd"&gt;for&lt;/span&gt; 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&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; StartupBackgroundWorker_DoWork(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DoWorkEventArgs e)
{
    List&amp;lt;StartupEntry&amp;gt; entries = e.Argument &lt;span class="kwrd"&gt;as&lt;/span&gt; List&amp;lt;StartupEntry&amp;gt;;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (entries == &lt;span class="kwrd"&gt;null&lt;/span&gt; || entries.Count == 0 )
    {
        e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;No entries passed in&amp;quot;&lt;/span&gt;);
    }

    &lt;span class="kwrd"&gt;try&lt;/span&gt;
    {
        &lt;span class="rem"&gt;// Don't bother if there aren't any entries!&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (entries.Count &amp;gt; 0)
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Startup Optimizer will begin in five seconds.  Click to cancel.&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 5 &amp;amp;&amp;amp; !&lt;span class="kwrd"&gt;this&lt;/span&gt;.CancellationPending; i++)
                Thread.Sleep(1000);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.CancellationPending)
            {
                e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                &lt;span class="kwrd"&gt;return&lt;/span&gt;;
            }
        }

        systemIdleComponent1.Enabled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;

        &lt;span class="rem"&gt;// Process entries to perform startup&lt;/span&gt;
        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (StartupEntry entry &lt;span class="kwrd"&gt;in&lt;/span&gt; entries)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (entry.Managed)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (entry.WaitForLowCPU)
                {
                    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Waiting for idle CPU to launch: &amp;quot;&lt;/span&gt; + entry.DisplayName);

                    &lt;span class="rem"&gt;// CPU wait routine...&lt;/span&gt;
                    &lt;span class="rem"&gt;// TODO: Give up if we never go idle?  This would be the place..!&lt;/span&gt;
                    &lt;span class="kwrd"&gt;while&lt;/span&gt;( !systemIdleComponent1.WaitForIdle(1000) )
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.CancellationPending)
                        {
                            e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
                        }
                    }
                }

                &lt;span class="kwrd"&gt;this&lt;/span&gt;.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Starting: &amp;quot;&lt;/span&gt; + entry.DisplayName);

                &lt;span class="rem"&gt;// Don't actually start if we are debugging&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt;( !Debugger.IsAttached)
                    Process.Start(Path.Combine(Properties.Settings.Default.ManagedStartupPath, entry.FileName));
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                    Thread.Sleep(2000); &lt;span class="rem"&gt;//SIMULATE STARTUP DELAY&lt;/span&gt;

                &lt;span class="kwrd"&gt;this&lt;/span&gt;.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Started: &amp;quot;&lt;/span&gt; + entry.DisplayName);

                &lt;span class="kwrd"&gt;if&lt;/span&gt; (entry.DelayTime &amp;gt; 0)
                {
                    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ReportProgress(0, &lt;span class="str"&gt;&amp;quot;Waiting: &amp;quot;&lt;/span&gt; + entry.DelayTime + &lt;span class="str"&gt;&amp;quot; seconds until next item&amp;quot;&lt;/span&gt;);

                    &lt;span class="rem"&gt;// Wait the number of seconds but check for cancel flag each second&lt;/span&gt;
                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x = 0; x &amp;lt; entry.DelayTime; x++)
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.CancellationPending)
                        {
                            e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
                        }

                        Thread.Sleep(1000);
                    }
                }
            }
        }
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt;
    {
        e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    }
    &lt;span class="kwrd"&gt;finally&lt;/span&gt;
    {
        systemIdleComponent1.Enabled = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
    }

}&lt;/pre&gt;

&lt;p&gt;There are a few things to callout in this block.&amp;#160; I have a few sanity checks in there to be sure that the list isn't NULL or empty.&amp;#160; Defensive programming is always a good idea!&amp;#160; Notice also that I have pauses built in with the &lt;strong&gt;Thread.Sleep() &lt;/strong&gt;command.&amp;#160; Where it would be convenient to pause for several seconds, it would render the thread unresponsive if a cancellation was requested.&amp;#160; Note that cancellation is completely passive.&amp;#160; The framework doesn't ever abort your &lt;strong&gt;BackgroundWorker&lt;/strong&gt;.&amp;#160; It's up to your code to catch it if cancellation is requested.&amp;#160; So for pauses, I wait a second, check the flag, and repeat for the number of seconds.&amp;#160; The code is slightly bulky but it works well.&lt;/p&gt;

&lt;p&gt;Notice also how I don't launch the startup applications if &lt;strong&gt;System.Diagnostics.Debugger.IsAttached &lt;/strong&gt;is true.&amp;#160; When I'm troubleshooting/testing, I don't really want the applications launching every time!&amp;#160; It's a simple check to see if the application is currently being debugged (as in Visual Studio).&lt;/p&gt;

&lt;h2&gt;Detecting Idleness&lt;/h2&gt;

&lt;p&gt;In addition to the simple time-based delays, I also wanted the option to wait for the system to be idle before launching applications.&amp;#160; There's no direct way to see this though, so I created the &lt;strong&gt;SystemIdleComponent&lt;/strong&gt;.&amp;#160; This is completely modular and could be plugged into other applications easily.&amp;#160; It all comes down to system Performance Counters.&amp;#160; If you've never worked with these before, don't let them intimidate you.&amp;#160; They're actually very easy to work with.&amp;#160; 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.&amp;#160; A pretty big deal I think!&lt;/p&gt;

&lt;p&gt;My component builds on the &lt;strong&gt;PerformanceCounter &lt;/strong&gt;object and creates a &lt;strong&gt;System.Threading.Timer &lt;/strong&gt;object behind the scenes to monitor the state of the counter periodically.&amp;#160; If a change is measured and it falls outside of the tolerance limits, it raises an event.&amp;#160; It also raises an event when it returns to the tolerance.&amp;#160; This allows you to receive an event both when the system becomes idle and when it returns to non-idle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; timerCpu_Tick(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; state &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt;)
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; currentValue &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 100 - &lt;span class="kwrd"&gt;CInt&lt;/span&gt;(performanceCounterProcessorIdle.NextValue())

        &lt;span class="rem"&gt;' If we are below the threshold, start counting...&lt;/span&gt;
        &lt;span class="kwrd"&gt;If&lt;/span&gt; currentValue &amp;lt;= _thresholdIdlePercent &lt;span class="kwrd"&gt;Then&lt;/span&gt;
            idleTimer.Start()
        &lt;span class="kwrd"&gt;Else&lt;/span&gt;
            idleTimer.[&lt;span class="kwrd"&gt;Stop&lt;/span&gt;]()
            idleTimer.Reset()
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;


        &lt;span class="rem"&gt;' See if we've been idle long enough&lt;/span&gt;
        &lt;span class="kwrd"&gt;If&lt;/span&gt; idleTimer.ElapsedMilliseconds / 1000 &amp;gt; _thresholdIdleTime &lt;span class="kwrd"&gt;Then&lt;/span&gt;
            &lt;span class="rem"&gt;' We've just gone idle&lt;/span&gt;
            RaiseIdleEvent()
        &lt;span class="kwrd"&gt;Else&lt;/span&gt;
            &lt;span class="rem"&gt;' We are not idle&lt;/span&gt;
            LowerIdleEvent()
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

        _lastCpuValue = &lt;span class="kwrd"&gt;CInt&lt;/span&gt;(currentValue)
    &lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; timerCpu_Tick(&lt;span class="kwrd"&gt;object&lt;/span&gt; state)
{
    &lt;span class="kwrd"&gt;int&lt;/span&gt; currentValue = 100 - (&lt;span class="kwrd"&gt;int&lt;/span&gt;)performanceCounterProcessorIdle.NextValue();

    &lt;span class="rem"&gt;// If we are below the threshold, start counting...&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (currentValue &amp;lt;= _thresholdIdlePercent)
        idleTimer.Start();
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        idleTimer.Stop();
        idleTimer.Reset();
    };

    &lt;span class="rem"&gt;// See if we've been idle long enough&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (idleTimer.ElapsedMilliseconds / 1000 &amp;gt; _thresholdIdleTime)
    {
        &lt;span class="rem"&gt;// We've just gone idle&lt;/span&gt;
        RaiseIdleEvent();
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        &lt;span class="rem"&gt;// We are not idle&lt;/span&gt;
        LowerIdleEvent();
    }

    _lastCpuValue = (&lt;span class="kwrd"&gt;int&lt;/span&gt;)currentValue;
}&lt;/pre&gt;

&lt;p&gt;What is idle?&amp;#160; This is defined by properties &lt;strong&gt;ThresholdIdlePercent &lt;/strong&gt;and &lt;strong&gt;ThresholdIdleTime&lt;/strong&gt;.&amp;#160; The statement is &amp;quot;the system is idle when it has been at {ThresholdIdlePercent}% for {ThresholdIdleTime} seconds.&amp;quot;&amp;#160; A consuming application just sets the properties and subscribes to events.&amp;#160; Alternately, you can check the &lt;strong&gt;SystemIdle &lt;/strong&gt;property when you need to.&amp;#160; A final way is to call &lt;strong&gt;WaitForIdle &lt;/strong&gt;with our without a timeout value.&amp;#160; The call will not return until the system is idle.&lt;/p&gt;

&lt;p&gt;This works by using an &lt;strong&gt;System.Threading.EventWaitHandle &lt;/strong&gt;object.&amp;#160; This very cool construct (system-based, not just .NET) lets two threads coordinate via a shared semaphore.&amp;#160; The &lt;strong&gt;BackgroundWorker &lt;/strong&gt;thread goes to sleep until the &lt;strong&gt;SystemIdleComponent&lt;/strong&gt;'s timer fires and detects an idle state.&amp;#160; 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.&amp;#160; I've added additional attributes to this object to make it easier to reuse and for a good design-time experience.&amp;#160; Drag it to your form and work with it like any other object.&lt;/p&gt;

&lt;h2&gt;Usage&lt;/h2&gt;

&lt;p&gt;It currently reads the user's &lt;strong&gt;Startup&lt;/strong&gt; folder upon startup and shows the dialog to take action.&amp;#160; There's no &lt;strong&gt;Cancel &lt;/strong&gt;button since it wouldn't make sense.&amp;#160; If you want to cancel, chances are you really just don't want the application to manage that shortcut.&amp;#160; It won't know that next time unless it creates an entry for it though.&lt;/p&gt;

&lt;p&gt;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.&amp;#160; Once that &lt;strong&gt;StartupEntry &lt;/strong&gt;is in the &lt;strong&gt;StartupEntryList &lt;/strong&gt;collection, the application will know what to do with it and you won't be prompted again.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;FileSystemWatcher &lt;/strong&gt;object enables the application to see new shortcuts added.&amp;#160; It then takes action only on shortcuts for which no &lt;strong&gt;StartupEntry &lt;/strong&gt;is found.&amp;#160; You can modify the display name, delay, wait-for-idle flag, or the managed property at any time.&amp;#160; Unless you're debugging, you won't have any way to execute the launch sequence except when it's initially started with the &amp;quot;/startup&amp;quot; command line flag.&amp;#160; If you launch it without the flag it won't launch anything so it's safer that way.&lt;/p&gt;

&lt;p&gt;There's not much else to worry about.&amp;#160; Tell it which startup entries to manage, then let it do it's thing upon restarts.&amp;#160; It could really exit after the list is complete, except that it wouldn't see new entries that way.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The application ended up taking considerably longer than I ever imagined it would!&amp;#160; I tried to create a good experience while demonstrating some good concepts.&amp;#160; I was surprised at some of the subtleties I ran into to make this work as well as it does.&amp;#160; It's not perfect by any means, but it's a good start and it should be useable as-is.&lt;/p&gt;

&lt;p&gt;I tried to keep things out of &lt;strong&gt;MainForm &lt;/strong&gt;where it made sense, though there is still room for more encapsulation.&amp;#160; Individual classes should always be fairly light-weight.&amp;#160; It's the way that they interact with each other that provides their power.&lt;/p&gt;

&lt;h2&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;For this article, you can use Visual Studio 2005 Express, or make the upgrade to Visual Studio 2008 Express.&amp;#160; 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 &lt;a title="http://www.microsoft.com/express/" href="http://www.microsoft.com/express/"&gt;http://www.microsoft.com/express/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I left a number of &lt;strong&gt;TODO &lt;/strong&gt;comments in the code.&amp;#160; These were cool things that I just didn't have time to implement.&amp;#160; 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.&amp;#160; Even more useful would be scanning the Registry Current User (HKCU) Run list.&amp;#160; Probably more entries end up there than the Startup folder.&amp;#160; I'd also like to extend my &lt;strong&gt;SystemIdleComponent &lt;/strong&gt;to be a generalized &lt;strong&gt;PerformanceCounter&lt;/strong&gt; event broker.&amp;#160; That would make it easy to add code to wait for low disk I/O in addition to CPU load.&amp;#160; Finally, I really wanted to add entry reordering to specify which applications should have the higher priority of starting first.&amp;#160; Not difficult, so give it a try!&amp;#160; If you end up adding any interesting features, let me know.&amp;#160; I'd love to see where it goes!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/Avatar80.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="84" alt="Arian Kulp" src="http://www.coding4fun.net/images/ABetterStartupExperience_D7BC/Avatar80_thumb.jpg" width="74" align="left" border="0" /&gt;&lt;/a&gt; 

  &lt;br /&gt;Arian Kulp is an independent software developer and writer working in the Midwest.&amp;#160; He has been coding since the fifth grade on various platforms, and also enjoys photography, nature, and spending time with his family.&amp;#160; Arian can be reached through his web site at &lt;a href="http://www.ariankulp.com"&gt;http://www.ariankulp.com&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8290797" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category></item><item><title>Going Paperless</title><link>http://blogs.msdn.com/coding4fun/archive/2007/09/25/5121856.aspx</link><pubDate>Tue, 25 Sep 2007 17:42:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5121856</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/5121856.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=5121856</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=5121856</wfw:comment><description>&lt;p&gt;&lt;/p&gt;&lt;span id="c4fmetadata"&gt; &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt; &lt;tbody&gt; &lt;tr class="entry_overview"&gt; &lt;td width="50"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/paperless.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="36" alt="paperless" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/paperless_thumb.jpg" width="36" border="0"&gt;&lt;/a&gt; &lt;/td&gt; &lt;td&gt;&lt;span class="entry_description"&gt;Are you tired of battling piles of papers at home?&amp;nbsp; From work, to your kid's school, to old bills and receipts, it can be too much to keep up with!&amp;nbsp; In this article, learn about how to scan, crop, and set metadata for your documents.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td colspan="2"&gt; &lt;div class="entry_author"&gt;Arian Kulp&lt;/div&gt; &lt;div class="entry_company"&gt;&lt;a href="http://www.ariankulp.com"&gt;Arian's Blog&lt;/a&gt;&lt;/div&gt;&lt;br&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;1-3 hours&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;$50 and up (depending on hardware choice)&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/a&gt;, DSOFile: &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=9BA6FAC6-520B-4A0A-878A-53EC8300C4C2" target="_blank"&gt;Developer Support OLE File Property Reader 2.1 Sample (KB 224351)&lt;/a&gt;&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;span class="entry_details_input"&gt;&lt;strong&gt;Hardware: &lt;/strong&gt;Any WIA-compliant document scanner&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;/div&gt; &lt;div class="entry_details"&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=343934"&gt;C# Download&lt;/a&gt;  &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=343937"&gt;VB Download&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/span&gt; &lt;h2&gt;Introduction&lt;/h2&gt; &lt;p&gt;In my last article, I worked with GPS.&amp;nbsp; I decided to try another device, so this time I'm working with an image scanner.&amp;nbsp; For a long time, I've been wanting to try to go (more) paperless around the house.&amp;nbsp; Too many piles of papers, and no way to really find them later when I need to.&amp;nbsp; Scanning is the way to go, though it's time-consuming enough just feeding documents in, but then home scanners are rarely full-duplex (two-sided), and then the tools aren't so great.&lt;/p&gt; &lt;p&gt;The simple things that I wanted were: easy-scan, metadata, and auto-cropping of the images.&amp;nbsp; More than that, I wanted standard image formats with standard metadata.&amp;nbsp; Too many document scanning solutions use proprietary ways to get around limitations such as using database instead of files, or using sidecar files for metadata.&amp;nbsp; This sample will create plain ol' image files with metadata.&amp;nbsp; Use any application (such as Windows Desktop Search or Picasa) to manage and search for documents.&lt;/p&gt; &lt;p&gt;I've included source code for Visual Basic and C#.&amp;nbsp; Both versions are identical.&amp;nbsp; You'll need to download the appropriate version of &lt;a href="http://msdn.microsoft.com/vstudio/express"&gt;Visual Studio 2005 Express Edition&lt;/a&gt; to open the source code, and you will need to download the DSOFile MSDN sample referenced in the article header.&amp;nbsp; The dsofile.dll must be registered before the project will startup.&amp;nbsp; Presumably the application will work on any supported operating system for DSOFile (2000/XP/Vista).&lt;/p&gt; &lt;h2&gt;A User Interface You Can Live With&lt;/h2&gt; &lt;p&gt;User interfaces are always challenging.&amp;nbsp; You want to capture all of your functionality, yet make everything accessible without being overwhelming or confusing.&amp;nbsp;&amp;nbsp; One design goal of mine is to always create windows that will resize well.&amp;nbsp; This interface consists of two splitters.&amp;nbsp; A vertical splitter separates the commands and options on the left from the properties and image on the right.&amp;nbsp; A horizontal splitter then separates the properties from the image region.&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="Image 1 - The user interface" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_thumb.png" width="528" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p align="center"&gt;&lt;em&gt;Image 1: The user interface&lt;/em&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;The &lt;strong&gt;Scan New Document &lt;/strong&gt;button initiates the scan, using standard Windows scanning dialogs.&amp;nbsp; Once the image is transferred to the application, it appears in the &lt;strong&gt;Source &lt;/strong&gt;tab.&amp;nbsp; You can crop away any borders automatically by clicking &lt;strong&gt;Crop&lt;/strong&gt;.&amp;nbsp; It will look for the color in &lt;strong&gt;Crop Color&lt;/strong&gt;, based on the specified &lt;strong&gt;Threshold.&amp;nbsp; &lt;/strong&gt;You can click on the image to choose the crop color, or use the value that it auto-selects from the bottom of the image.&amp;nbsp; Use the &lt;strong&gt;Properties &lt;/strong&gt;region to enter metadata.&amp;nbsp; The &lt;strong&gt;From &lt;/strong&gt;field becomes the &lt;strong&gt;Author &lt;/strong&gt;field in metadata, and &lt;strong&gt;Type &lt;/strong&gt;becomes &lt;strong&gt;Subject&lt;/strong&gt;.&amp;nbsp; The rest are direct mappings.&amp;nbsp; Finally, select the image format (codec), destination folder, and compression level and click &lt;strong&gt;Save&lt;/strong&gt;.&amp;nbsp; Not that not all formats can hold metadata (such as BMP).&lt;/p&gt; &lt;h2&gt;Talking to the Scanner &lt;/h2&gt; &lt;p&gt;Working with scanners with .NET isn't as smooth as it could be, but the COM-interop works well enough.&amp;nbsp; It would be nice to be able to use &lt;strong&gt;Image.FromScanner&lt;/strong&gt;, but it's not an option!&lt;/p&gt; &lt;p&gt;The first step is to create a reference to &lt;strong&gt;Microsoft Windows Image Acquisition 1.01 Type Library&lt;/strong&gt;.&amp;nbsp; This creates wrappers in the &lt;strong&gt;WiaLib &lt;/strong&gt;namespace.&amp;nbsp; Then, you need to create a &lt;strong&gt;WiaClass&lt;/strong&gt; instance.&amp;nbsp; With that object, you can enumerate the scanners using the &lt;strong&gt;Devices &lt;/strong&gt;property, or create an instance of a particular scanner.&amp;nbsp; If you call the &lt;strong&gt;Create &lt;/strong&gt;method without a scanner &lt;strong&gt;DeviceInfoClass &lt;/strong&gt;object and there are more than one scanner attached, the standard "Select Device" dialog is shown.&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image11.png"&gt;&lt;em&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image9_thumb.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="306" alt="Image 2 - The Select Device dialog" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image9_thumb_thumb.png" width="463" border="0"&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt; &lt;p align="center"&gt;&lt;em&gt;Image 2: The Select Device dialog&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Once this returns, you have a &lt;strong&gt;ItemClass &lt;/strong&gt;object.&amp;nbsp; You might think that this would allow you to easily determine the selected scanner, but in fact, none of the properties are definitive. The best option if you wanted to retain the choice of scanner would be to present your own "Select Device" dialog from the &lt;strong&gt;DeviceInfoClass &lt;/strong&gt;collection, the remember the selection.&lt;/p&gt; &lt;p&gt;Now you can invoke the &lt;strong&gt;GetItemsFromUI &lt;/strong&gt;method.&amp;nbsp; This isn't required for unattended scanning, but if you want to present the scanner dialog (to choose Color, Greyscale, etc), this is a good choice.&amp;nbsp; From there, enumerate the scans (plural if multiple pages were scanned) and call &lt;strong&gt;Transfer &lt;/strong&gt;on each one to save them to file.&amp;nbsp; I originally used &lt;strong&gt;Image.FromFile &lt;/strong&gt;to load from that file, but it turns out there's a bug that leaves files open when you do that.&amp;nbsp; The simple solution was to create a &lt;strong&gt;FileStream&lt;/strong&gt;, call &lt;strong&gt;Image.FromStream&lt;/strong&gt;, then close the stream.&amp;nbsp; This allowed me to delete the temporary file afterwards.&amp;nbsp; I should note, that for some strange reason, I had to wrap the &lt;strong&gt;Image.FromStream &lt;/strong&gt;call with creating a new &lt;strong&gt;Bitmap&lt;/strong&gt;.&amp;nbsp; This should &lt;em&gt;not&lt;/em&gt; be necessary, but if I don't, I get an unexplained &lt;strong&gt;OutOfMemoryException &lt;/strong&gt;later when I convert it to black-and-white.&amp;nbsp; I hate kludges!&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; ScanDocument() &lt;span class="kwrd"&gt;As&lt;/span&gt; List(Of Bitmap)
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; docs &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; List(Of Bitmap)()
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; currFilename &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;

    &lt;span class="rem"&gt;' Create a scanner instance (the user can select if more than one)&lt;/span&gt;
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; scanner &lt;span class="kwrd"&gt;As&lt;/span&gt; ItemClass = &lt;span class="kwrd"&gt;DirectCast&lt;/span&gt;(wiaManager.Create(missing), ItemClass)

    &lt;span class="rem"&gt;' Show the standard scanning dialog (this is not a required step...)&lt;/span&gt;
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; scans &lt;span class="kwrd"&gt;As&lt;/span&gt; CollectionClass = &lt;span class="kwrd"&gt;TryCast&lt;/span&gt;( _
        scanner.GetItemsFromUI(WiaFlag.SingleImage, WiaIntent.ImageTypeText), _
        CollectionClass)

    &lt;span class="rem"&gt;' If the user clicks Cancel, collection is Nothing&lt;/span&gt;
    &lt;span class="kwrd"&gt;If&lt;/span&gt; scans IsNot &lt;span class="kwrd"&gt;Nothing&lt;/span&gt; &lt;span class="kwrd"&gt;AndAlso&lt;/span&gt; scans.Count &amp;gt; 0 &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        &lt;span class="rem"&gt;' Transfer any scanned pictures to disk&lt;/span&gt;
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; scan &lt;span class="kwrd"&gt;As&lt;/span&gt; ItemClass
        &lt;span class="kwrd"&gt;For&lt;/span&gt; &lt;span class="kwrd"&gt;Each&lt;/span&gt; wiaObj &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt; &lt;span class="kwrd"&gt;In&lt;/span&gt; scans
            scan = &lt;span class="kwrd"&gt;DirectCast&lt;/span&gt;( _
                Marshal.CreateWrapperOfType(wiaObj, &lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ItemClass)), _ 
                ItemClass)

            &lt;span class="rem"&gt;' create temporary file for image&lt;/span&gt;
            currFilename = Path.GetTempFileName()

            &lt;span class="rem"&gt;' transfer picture to our temporary file&lt;/span&gt;
            scan.Transfer(currFilename, &lt;span class="kwrd"&gt;False&lt;/span&gt;)

            &lt;span class="rem"&gt;' Create a Bitmap from the loaded file (Image/Bitmap.FromFile locks the file...)&lt;/span&gt;
            &lt;span class="kwrd"&gt;Using&lt;/span&gt; fs &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; FileStream( _
                currFilename, FileMode.Open, FileAccess.Read)&lt;/pre&gt;&lt;pre class="csharpcode"&gt;                docs.Add(&lt;span class="kwrd"&gt;New &lt;/span&gt;Bitmap(Bitmap.FromStream(fs)))
                fs.Close()&lt;/pre&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;End Using&lt;/span&gt;

            &lt;span class="rem"&gt;' Don't leave junk behind!&lt;/span&gt;
            File.Delete(currFilename)
        &lt;span class="kwrd"&gt;Next&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

    &lt;span class="kwrd"&gt;Return&lt;/span&gt; docs
&lt;span class="kwrd"&gt;End&lt;/span&gt; Function&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;Bitmap&amp;gt; ScanDocument()
{
    List&amp;lt;Bitmap&amp;gt; docs = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Bitmap&amp;gt;();
    &lt;span class="kwrd"&gt;string&lt;/span&gt; currFilename;
    
    &lt;span class="rem"&gt;// Create a scanner instance (the user can select if more than one)&lt;/span&gt;
    ItemClass scanner = (ItemClass)wiaManager.Create(&lt;span class="kwrd"&gt;ref&lt;/span&gt; missing);

    &lt;span class="rem"&gt;// Show the standard scanning dialog (this is not a required step...)&lt;/span&gt;
    CollectionClass scans = scanner.GetItemsFromUI(
        WiaFlag.SingleImage, WiaIntent.ImageTypeText)
        &lt;span class="kwrd"&gt;as&lt;/span&gt; CollectionClass;

    &lt;span class="rem"&gt;// If the user clicks Cancel, collection is NULL&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (scans != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; scans.Count &amp;gt; 0)
    {
        &lt;span class="rem"&gt;// Transfer any scanned pictures to disk&lt;/span&gt;
        ItemClass scan;
        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; wiaObj &lt;span class="kwrd"&gt;in&lt;/span&gt; scans)
        {
            scan = (ItemClass)Marshal.CreateWrapperOfType(wiaObj, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ItemClass));

            &lt;span class="rem"&gt;// create temporary file for image&lt;/span&gt;
            currFilename = Path.GetTempFileName();

            &lt;span class="rem"&gt;// transfer picture to our temporary file&lt;/span&gt;
            scan.Transfer(currFilename, &lt;span class="kwrd"&gt;false&lt;/span&gt;);

            &lt;span class="rem"&gt;// Create a Bitmap from the loaded file (Image/Bitmap.FromFile locks the file...)&lt;/span&gt;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (FileStream fs = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileStream(currFilename, FileMode.Open, FileAccess.Read))
            {           &lt;/pre&gt;&lt;pre class="csharpcode"&gt;                docs.Add(&lt;span class="kwrd"&gt;new &lt;/span&gt;Bitmap(Bitmap.FromStream(fs)));
                fs.Close();
            } 
            &lt;span class="rem"&gt;// Don't leave junk behind!&lt;/span&gt;
            File.Delete(currFilename);
        }
    }

    &lt;span class="kwrd"&gt;return&lt;/span&gt; docs;
}&lt;/pre&gt;
&lt;p&gt;Once the new image is scanned, it's displayed in the &lt;strong&gt;Source &lt;/strong&gt;tab in the user interface.&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_3.png"&gt;&lt;em&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="Image 3 - Displaying a scanned image" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_thumb_3.png" width="559" border="0"&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;
&lt;p align="center"&gt;&lt;em&gt;Image 3: Displaying a scanned image&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;h2&gt;Cropping Your Way to Success&lt;/h2&gt;
&lt;p&gt;The standard scanning dialog lets you crop an image using the handles, but only in preview mode (you need to scan it a second time after selecting the crop region).&amp;nbsp; I own two scanners.&amp;nbsp; One is a standard flatbed, but the other is a compact travel scanner that pulls the sheet through (the Ambir TravelScan 600).&amp;nbsp; The TravelScan doesn't work so well in that mode since scanning a second time will always be slightly different due to the feed mechanism.&amp;nbsp; I'd love to know why I can't just crop final my image in the scanner dialog, but, oh well!&lt;/p&gt;
&lt;p&gt;My solution was to add cropping to the application after it's scanned.&amp;nbsp; It takes longer to do a low-quality preview along with a full-quality scan on a full sheet of paper than just doing one full-quality scan.&amp;nbsp; Since my primary design goal was to be able to scan and catalog sheets of paper (not business cards, photos, etc), this made sense.&lt;/p&gt;
&lt;p&gt;Once the image is scanned, it automatically grabs a pixel from the bottom row.&amp;nbsp; It assumes that this is an unimportant edge.&amp;nbsp; You can choose a different edge color by clicking in the picture.&amp;nbsp; Then, use the &lt;strong&gt;LockBits &lt;/strong&gt;method of the &lt;strong&gt;Bitmap &lt;/strong&gt;object to get access to the raw bits.&amp;nbsp; These bits are then cycled through row-by-row to the bottom.&amp;nbsp; Each pixel is compared to the crop color based on the supplied threshold.&amp;nbsp; Border matches are compared to the known top/left/right/bottom border locations and moved as necessary.&amp;nbsp; If a crop doesn't come out right, you can just change the threshold value and try again.&lt;/p&gt;
&lt;p&gt;Think of it as starting on the four edges with straight-edges.&amp;nbsp; Drag those straight-edges toward the middle until you encounter a color that's more than the defined threshold different from the specified "border color."&amp;nbsp; Note that this won't work so well for you if your scanner adds a little band around the edges of the images.&amp;nbsp; One of my scanners is a little bit extra bright around the edges.&amp;nbsp; If the border is overall black, that throws it off.&amp;nbsp; I found that just dragging the crop region slightly in the scanning dialog helped.&amp;nbsp; If it's not a full sheet document, you won't lose anything.&amp;nbsp; It's a fairly simple and brute force way of cropping.&amp;nbsp; A real imaging application would have some super-slick way to do it in a millisecond or two with more accuracy I'm sure!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;For&lt;/span&gt; y &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 0 &lt;span class="kwrd"&gt;To&lt;/span&gt; img.Image.Height - 1

    &lt;span class="rem"&gt;'loop through pixels on Y axis until end of image height&lt;/span&gt;
    &lt;span class="kwrd"&gt;For&lt;/span&gt; x &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 0 &lt;span class="kwrd"&gt;To&lt;/span&gt; img.Image.Width - 1
        &lt;span class="rem"&gt;'loop through pixels on X axis until end of image width&lt;/span&gt;
        &lt;span class="rem"&gt;' Scans won't have perfect background... (only need one channel if b&amp;amp;w)&lt;/span&gt;
        &lt;span class="kwrd"&gt;If&lt;/span&gt; Math.Abs(img.RawBits(bufferLoc + 0) - cropColor.B) &amp;gt; threshold &lt;span class="kwrd"&gt;Then&lt;/span&gt;
            &lt;span class="rem"&gt;'Determine if pixel is further left than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;If&lt;/span&gt; leftEdge = -1 &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; x &amp;lt; leftEdge &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                leftEdge = x
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

            &lt;span class="rem"&gt;'Determine if pixel is further to the top than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;If&lt;/span&gt; topEdge = -1 &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                topEdge = y
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

            &lt;span class="rem"&gt;'Determine if pixel is further right than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;If&lt;/span&gt; (rightEdge = -1) &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; x &amp;gt; rightEdge &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                rightEdge = x
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

            &lt;span class="rem"&gt;'Determine if pixel is further to the bottom than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;If&lt;/span&gt; (bottomEdge = -1) &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; y &amp;gt; bottomEdge &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                bottomEdge = y
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

        &lt;span class="rem"&gt;' LEARNED: Could be 32-bit, 24-bit, 16-bit, etc.&lt;/span&gt;
        bufferLoc += img.PixelWidth
    &lt;span class="kwrd"&gt;Next&lt;/span&gt;

    &lt;span class="rem"&gt;' LEARNED: Extra byte(s) per line for 4-byte boundary...&lt;/span&gt;
    bufferLoc += img.RowPadding
Next&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//loop through pixels on Y axis until end of image height&lt;/span&gt;
&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; y = 0; y &amp;lt; img.Image.Height; y++)
{
    &lt;span class="rem"&gt;//loop through pixels on X axis until end of image width&lt;/span&gt;
    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x = 0; x &amp;lt; img.Image.Width; x++)
    {
        &lt;span class="rem"&gt;// Scans won't have perfect background... (only need one channel if b&amp;amp;w)&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (Math.Abs(img.RawBits[bufferLoc + 0] - cropColor.B) &amp;gt; threshold)
        {
            &lt;span class="rem"&gt;//Determine if pixel is further left than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (leftEdge == -1 || x &amp;lt; leftEdge) leftEdge = x;

            &lt;span class="rem"&gt;//Determine if pixel is further to the top than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (topEdge == -1) topEdge = y;

            &lt;span class="rem"&gt;//Determine if pixel is further right than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; ((rightEdge == -1) || x &amp;gt; rightEdge) rightEdge = x;

            &lt;span class="rem"&gt;//Determine if pixel is further to the bottom than the value we already have&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; ((bottomEdge == -1) || y &amp;gt; bottomEdge)
            {
                bottomEdge = y;
            }
        }

        &lt;span class="rem"&gt;// LEARNED: Could be 32-bit, 24-bit, 16-bit, etc.&lt;/span&gt;
        bufferLoc += img.PixelWidth;
    }

    &lt;span class="rem"&gt;// LEARNED: Extra byte(s) per line for 4-byte boundary...&lt;/span&gt;
    bufferLoc += img.RowPadding;
}&lt;/pre&gt;
&lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="Image 4 - The same image, auto-cropped (threshold=82)" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_thumb_4.png" width="390" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p align="center"&gt;&lt;em&gt;Image 4 : The same image, auto-cropped (threshold=82)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I learned a few things in all of this.&amp;nbsp; Bitmaps have many ways that they can be stored.&amp;nbsp; Pixels can be anywhere from 1-bit up to 12-bit, with and without an additional alpha component (for transparency).&amp;nbsp; This makes it impossible to just copy the bitmap to a byte array and just look at each byte as a pixel.&amp;nbsp; To make it worse, in some pixel formats, the RGB order may not be the same, and some index the colors rather than using RGB at all.&amp;nbsp; Phew!&lt;/p&gt;
&lt;p&gt;Even once you know the pixel width, you can't assume that [pixel width * width] is equal to size of a row.&amp;nbsp; This is due to the fact that bytes are packed for optimum efficiency based on maintaining a 4-byte boundary.&amp;nbsp; In other words, the actual width of bytes in a row will always be divisible by four.&amp;nbsp; The actual width of bytes is called the "stride."&lt;/p&gt;
&lt;p&gt;You can obtain all of the numbers when you grab the bitmap's bits, but it still complicates things when you cycle through the pixels.&amp;nbsp; My solution (*ahem* cheat) was to convert the image to a fixed 32-bit RGB structure (no Alpha component).&amp;nbsp; That way I always knew the pixel width and row padding.&lt;/p&gt;
&lt;p&gt;I did two more things to simplify my routine.&amp;nbsp; Before grabbing the bits, I converted the image to black-and-white and shrunk to 1/4th its size.&amp;nbsp; This gave me significantly fewer bytes to compare, and being black-and-white, I didn't need to compare all three channels for detecting the border.&amp;nbsp; In order to perform the black-and-white conversion, I used a ColorMatrix object to transform the color values.&amp;nbsp; I used code from &lt;a href="http://blog.paranoidferret.com/index.php/2007/08/31/csharp-tutorial-convert-a-color-image-to-greyscale/" target="_blank"&gt;this blog entry&lt;/a&gt; to figure out the values to use.&lt;/p&gt;
&lt;p&gt;Now you might be wondering why I didn't go with a simple 8-bit greyscale image format.&amp;nbsp; The bottom line is I'm probably not smart enough!&amp;nbsp; The 8-bit formats were indexed (you'd expect a simple intensity value for each byte...), and if you try to grab the &lt;strong&gt;Graphics &lt;/strong&gt;object for drawing a cropped image, you get a GDI+ exception every time.&amp;nbsp; Maybe with more effort I could have figured it out (and maybe I still will!), but it works well enough for now.&amp;nbsp; My speed tests from cropping the original versus the shrunken black-and-white are pretty conclusive so I stuck with it.&lt;/p&gt;
&lt;h2&gt;Will Someone Save Me&lt;/h2&gt;
&lt;p&gt;With the image scanned and (optionally) cropped, the final step is to key in the metadata and save the file.&amp;nbsp; I've been searching for a way to work with metadata from .NET for too long.&amp;nbsp; The &lt;strong&gt;Image &lt;/strong&gt;class has methods (&lt;strong&gt;Get&lt;/strong&gt;/&lt;strong&gt;SetPropertyItem&lt;/strong&gt;) for dealing with metadata properties, but they are mostly suited for reading the fields, and if you use them on an existing file you end up re-encoding the bitmap (recompressing...).&lt;/p&gt;
&lt;p&gt;The best solution turned out to be the Microsoft DSO OLE Document Properties Reader 2.1 (often referred to as simply DSOFile).&amp;nbsp; This wraps the IPropertyStrorage COM class which is typically used for reading properties in OLE-based Office documents, and also adds the ability to read from the new XML-based Office formats, and many other files.&amp;nbsp; Using this sample object, you can access the Title, Subject, Author, Category, Keywords, and Comments field that you see in the &lt;strong&gt;Summary &lt;/strong&gt;tab of all files in Windows.&amp;nbsp; This does vary a bit depending on file type, but it's very easy to use.&lt;/p&gt;
&lt;p&gt;Once a scan has taken place, the user can choose to crop it.&amp;nbsp; When &lt;strong&gt;Save &lt;/strong&gt;is clicked, the method saves the file (choosing the cropped version, if present).&amp;nbsp; This happens by setting the compression level and codec, and calling &lt;strong&gt;Save&lt;/strong&gt;.&amp;nbsp; The drop-down box for choosing codec is actually populated by the &lt;strong&gt;System.Imaging.ImageCodecInfo &lt;/strong&gt;collection.&lt;/p&gt;
&lt;p&gt;Once the file is saved, the metadata can be set.&amp;nbsp; It's possible to use the built-in &lt;strong&gt;Image &lt;/strong&gt;methods to do this prior to saving, but the DSOFile code is just so convenient for working with metadata.&amp;nbsp; Data need not be converted to byte arrays, and fields are set using standard properties, not numeric ID's. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visual Basic&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;' Grab file info if it exists&lt;/span&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; fi &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; FileInfo(filename)
&lt;span class="kwrd"&gt;If&lt;/span&gt; &lt;span class="kwrd"&gt;Not&lt;/span&gt; fi.Exists &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    &lt;span class="kwrd"&gt;Return&lt;/span&gt; &lt;span class="kwrd"&gt;False&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

&lt;span class="rem"&gt;' Update the file creation date based on the supplied date&lt;/span&gt;
&lt;span class="kwrd"&gt;If&lt;/span&gt; creationDate.HasValue &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    fi.CreationTime = creationDate.Value
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

&lt;span class="rem"&gt;' Create and open the properties object&lt;/span&gt;
oleDocument = &lt;span class="kwrd"&gt;New&lt;/span&gt; OleDocumentPropertiesClass()
oleDocument.Open(fi.FullName, &lt;span class="kwrd"&gt;False&lt;/span&gt;, dsoFileOpenOptions.dsoOptionDefault)

&lt;span class="kwrd"&gt;If&lt;/span&gt; &lt;span class="kwrd"&gt;Not&lt;/span&gt; oleDocument.IsReadOnly &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    &lt;span class="rem"&gt;' Keywords should be semicolon-separated, not carriage returns or commas&lt;/span&gt;
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; keywordsSeparated &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = keywords.Replace(Chr(10), &lt;span class="str"&gt;";"&lt;/span&gt;c).Replace(&lt;span class="str"&gt;","&lt;/span&gt;c, &lt;span class="str"&gt;";"&lt;/span&gt;c)

    oleDocument.SummaryProperties.Author = docSource
    oleDocument.SummaryProperties.Comments = comments
    oleDocument.SummaryProperties.Keywords = keywordsSeparated
    oleDocument.SummaryProperties.Subject = docType
    oleDocument.SummaryProperties.Title = title

    &lt;span class="kwrd"&gt;If&lt;/span&gt; oleDocument.IsDirty &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        oleDocument.Save()
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

    &lt;span class="kwrd"&gt;Return&lt;/span&gt; &lt;span class="kwrd"&gt;True&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; If&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Visual C#&lt;/strong&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Grab file info if it exists&lt;/span&gt;
FileInfo fi = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileInfo(filename);
&lt;span class="kwrd"&gt;if&lt;/span&gt; (!fi.Exists) &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;

&lt;span class="rem"&gt;// Update the file creation date based on the supplied date&lt;/span&gt;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (creationDate.HasValue) fi.CreationTime = creationDate.Value;

&lt;span class="rem"&gt;// Create and open the properties object&lt;/span&gt;
oleDocument = &lt;span class="kwrd"&gt;new&lt;/span&gt; OleDocumentPropertiesClass();
oleDocument.Open(fi.FullName, &lt;span class="kwrd"&gt;false&lt;/span&gt;, dsoFileOpenOptions.dsoOptionDefault);

&lt;span class="kwrd"&gt;if&lt;/span&gt; (!oleDocument.IsReadOnly)
{
    &lt;span class="rem"&gt;// Keywords should be semicolon-separated, not carriage returns or commas&lt;/span&gt;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; keywordsSeparated = keywords.Replace(&lt;span class="str"&gt;'\n'&lt;/span&gt;, &lt;span class="str"&gt;';'&lt;/span&gt;).Replace(&lt;span class="str"&gt;','&lt;/span&gt;, &lt;span class="str"&gt;';'&lt;/span&gt;);

    oleDocument.SummaryProperties.Author = docSource;
    oleDocument.SummaryProperties.Comments = comments;
    oleDocument.SummaryProperties.Keywords = keywordsSeparated;
    oleDocument.SummaryProperties.Subject = docType;
    oleDocument.SummaryProperties.Title = title;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (oleDocument.IsDirty) oleDocument.Save();

    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
}&lt;/pre&gt;
&lt;p&gt;Both reading and writing properties is easy, though keep in mind that only JPEG and TIFF support properties well (no warnings or errors will occur with other containers/formats).&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_5.png"&gt;&lt;em&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="Image 5 - Showing file properties with saved metadata" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/image_thumb_5.png" width="350" border="0"&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;
&lt;p align="center"&gt;&lt;em&gt;Image 5: Showing the saved metadata&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Received &lt;/strong&gt;date picker doesn't actually update metadata.&amp;nbsp; It works using the &lt;strong&gt;FileInfo &lt;/strong&gt;object, updating the &lt;strong&gt;CreationTime &lt;/strong&gt;property which directly updates the file.&amp;nbsp; This is only done if the date field's checkbox is checked.&lt;/p&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;There are so many things to add to this start!&amp;nbsp; Faster cropping would be a start...&amp;nbsp; I also had wanted to add deskewing (straightening), but I quickly realized that I wouldn't be able to do that feature justice.&amp;nbsp; With enough time maybe!&lt;/p&gt;
&lt;p&gt;The UI itself could use some better design, multi-part documents would be good (for TIFF or GIF formats).&amp;nbsp; I had also planned on integrating Windows contacts with the &lt;strong&gt;From &lt;/strong&gt;ComboBox, but I didn't get to it.&amp;nbsp; Image rotation can be useful and isn't terribly difficult.&lt;/p&gt;
&lt;p&gt;Once you get into the document imaging world, there are so many possibilities and expectations.&amp;nbsp; I'm afraid that this just scratches the surface, but I'm pleased with it as a starting point.&amp;nbsp; If anyone's interested in taking it further, let me know!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we've learned more about scanning image manipulation, and working with file metadata.&amp;nbsp; The application is useable, but definitely not commercial-grade!&amp;nbsp; For any comments, questions, or suggestions, contact me through &lt;a href="http://www.ariankulp.com"&gt;my blog&lt;/a&gt;.&amp;nbsp; Happy scanning!&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;

&lt;p&gt;&lt;/p&gt;
&lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;
&lt;tbody&gt;
&lt;tr class="author"&gt;
&lt;td class="author_image" width="50"&gt;&lt;a href="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/Avatar80.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="84" alt="Avatar80" src="http://www.coding4fun.net/images/GoingPaperlessbackup_39A/Avatar80_thumb.png" width="74" border="0"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;td class="author_bio"&gt;Arian Kulp is an independent software developer and writer working in the Midwest.&amp;nbsp; He has been coding since the fifth grade on various platforms, and also enjoys photography, nature, and spending time with his family.&amp;nbsp; Arian can be reached through his web site at &lt;a href="http://www.ariankulp.com"&gt;http://www.ariankulp.com&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5121856" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category></item><item><title>Outlook Webmail Add-in for Windows Home Server</title><link>http://blogs.msdn.com/coding4fun/archive/2007/08/10/4320362.aspx</link><pubDate>Fri, 10 Aug 2007 14:33:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4320362</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>26</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/4320362.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=4320362</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=4320362</wfw:comment><description>&lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt; &lt;tbody&gt; &lt;tr class="entry_overview"&gt; &lt;td width="50"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="Office_MAIL" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/Office_MAIL.png" border="0"&gt; &lt;/td&gt; &lt;td&gt;&lt;span class="entry_description"&gt;In this article, Brian Peek will demonstrate how to create an add-in for Windows Home Server that will allow users to view their Outlook mail from a web browser.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td colspan="2"&gt; &lt;div class="entry_author"&gt;&lt;a href="http://www.brianpeek.com/" target="_blank"&gt;Brian Peek&lt;/a&gt;&lt;/div&gt; &lt;div class="entry_company"&gt;&lt;a href="http://www.aspsoft.com/"&gt;ASPSOFT, Inc.&lt;/a&gt;&lt;/div&gt;&lt;br&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; 2&lt;span class="entry_details_input"&gt;-3 hours&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Free&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;strong&gt;Software: &lt;/strong&gt;&lt;a href="http://www.microsoft.com/windows/products/winfamily/windowshomeserver/default.mspx" target="_blank"&gt;Windows Home Server&lt;/a&gt;,&amp;nbsp;&lt;a href="http://office.microsoft.com/en-us/outlook/default.aspx" target="_blank"&gt;Microsoft Outlook 2000/XP/2003/2007&lt;/a&gt; (&lt;strong&gt;not&lt;/strong&gt; Outlook Express/Windows Mail),&amp;nbsp;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/a&gt;, &lt;a href="http://msdn.com/express/" target="_blank"&gt;Visual Web Developer Express Edition&lt;/a&gt;, &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en" target="_blank"&gt;Microsoft .NET Framework 3.0 runtime&lt;/a&gt;, Outlook/Office Primary Interop Assemblies (more on this below),&amp;nbsp;&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=4377f86d-c913-4b5c-b87e-ef72e5b4e065&amp;amp;displaylang=en" target="_blank"&gt;Windows SDK&lt;/a&gt; (Vista or later, which includes the .NET 3.0 bits.&amp;nbsp; Note that this installs and works just fine under Windows XP.&amp;nbsp; The SDK can build applications for Windows XP and greater.)&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;None&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://www.codeplex.com/WHSMail" target="_blank"&gt;CodePlex Project&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;h3&gt;Introduction&lt;/h3&gt; &lt;p&gt;&lt;a href="http://www.microsoft.com/windows/products/winfamily/windowshomeserver/default.mspx" target="_blank"&gt;Windows Home Server&lt;/a&gt;&amp;nbsp;is a new product from Microsoft which allows home users to manage and share data, including photos, documents, videos, music, etc.&amp;nbsp; It also provides a very easy way to backup all computers on your home network to a central storage server.&lt;/p&gt; &lt;p&gt;Windows Home Server can also be extended via add-ins to enhance the experience and provide new and interesting functionality other than what comes in the box.&lt;/p&gt; &lt;p&gt;One&amp;nbsp;feature not present in WHS&amp;nbsp;that I would find useful is the ability to view my Outlook mail box from the web at any time.&amp;nbsp; I have 6&amp;nbsp;or 7 email accounts that are&amp;nbsp;all setup&amp;nbsp;to retrieve via POP3 to Outlook.&amp;nbsp; Most of these accounts do not support IMAP or have a web-based interface.&amp;nbsp; Therefore, Outlook is generally open all day and checking messages.&amp;nbsp;&amp;nbsp;When I'm away from home for work or pleasure,&amp;nbsp;it's&amp;nbsp;very often&amp;nbsp;inconvenient to have to remote desktop into&amp;nbsp;the machine with Outlook running to read my email,&amp;nbsp;so it would be nice to have a web-based version of my current&amp;nbsp;Outlook folders so I can view all email (old and new) at any time simply by browsing to a&amp;nbsp;web server at home.&amp;nbsp; Windows Home&amp;nbsp;Server comes with&amp;nbsp;Internet Information Services&amp;nbsp;6 (IIS6) and&amp;nbsp;one can easily add a new web application to IIS on the server.&lt;/p&gt; &lt;p&gt;So, this article will attempt to show how to build a new web site using ASP.NET that can be added to your Windows Home Server installation that will allow one to view the Outlook folders running on whatever computer contains your current Outlook installation and message store.&lt;/p&gt; &lt;p&gt;If you wish to just use the application, download the sample from above and skip down to the deployment section for installation instructions.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This application will only work with Microsoft Outlook.&amp;nbsp; It will not work with Outlook Express, Windows Mail, or any other mail client.&lt;/p&gt; &lt;h3&gt;Setup&lt;/h3&gt; &lt;p&gt;Setup can be a bit tricky.&amp;nbsp; Office/Outlook will need to be installed on your development machine.&amp;nbsp; It does not need to be the same machine which contains your store at this point, but that too would help.&amp;nbsp; Once Office/Outlook is installed, the &lt;strong&gt;Primary Interop Assemblies&lt;/strong&gt; for the version of Office you are using need to be installed.&amp;nbsp; For Office 2003/2007, this can be done choosing &lt;strong&gt;.NET Programming Support&lt;/strong&gt; from the list of sub-items in the &lt;strong&gt;Microsoft Office Outlook &lt;/strong&gt;section of the setup program.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/2003_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="426" alt="2003" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/2003_thumb_3.png" width="490" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/pia_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="414" alt="pia" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/pia_thumb_3.png" width="490" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Unfortunately I do not have an earlier copy of Office with which to check, but the procedure should be the same.&amp;nbsp; If anyone happens to try this with Office XP/2000, please let me know if/how it works.&lt;/p&gt; &lt;p&gt;If you will be developing on an OS earlier than Vista,&amp;nbsp;install the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en" target="_blank"&gt;.NET Framework 3.0 runtime&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Finally, install the Windows SDK linked above accepting all defaults.&lt;/p&gt; &lt;h3&gt;Architecture&lt;/h3&gt; &lt;p&gt;The architecture we will be using is very similar that to an N-tier application.&amp;nbsp; The machine running Outlook with the message store to be viewed is, in essence, the server machine.&amp;nbsp; That machine will run a host process that we will develop which will expose several methods via Windows Communication Foundation.&amp;nbsp; These methods will be consumed by an ASP.NET application running on the Windows Home Server.&lt;/p&gt; &lt;h3&gt;The Host&lt;/h3&gt; &lt;p&gt;Let's start by building the host application.&amp;nbsp; This will run on the computer where Outlook is installed and the messages are stored.&amp;nbsp; The application will be written to run in the notification area next to the Windows system clock.&lt;/p&gt; &lt;p&gt;To start, create a new Windows Application project named &lt;strong&gt;WHSMailHost&lt;/strong&gt;.&amp;nbsp; Rename the default &lt;strong&gt;Form1.cs/.vb&lt;/strong&gt; file to &lt;strong&gt;frmMain.cs/.vb&lt;/strong&gt;.&amp;nbsp; Double-click on the file in the Solution Explorer to bring up the design surface.&lt;/p&gt; &lt;p&gt;In order to get the application to run in the notification area, drag and drop a &lt;strong&gt;NotifyIcon&lt;/strong&gt; control from the Toolbox to the design surface, name it &lt;strong&gt;niIcon&lt;/strong&gt;.&amp;nbsp; Also, drag over a &lt;strong&gt;ContextMenuStrip&lt;/strong&gt; to the design surface and name it &lt;strong&gt;cmsMenu&lt;/strong&gt;.&amp;nbsp; This will be used to pop up a context menu when the icon in the notification area is clicked.&amp;nbsp;&amp;nbsp;Finally,&amp;nbsp;set the following properties on the &lt;strong&gt;niIcon&lt;/strong&gt; control:&lt;/p&gt; &lt;table cellspacing="0" cellpadding="2" width="248" border="1" unselectable="on"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt;WHS Mail Host&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="138"&gt;&lt;strong&gt;ContextMenuStrip&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt;cmsMenu&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="139"&gt;&lt;strong&gt;Visible&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="110"&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;Select the &lt;strong&gt;cmsMenu&lt;/strong&gt; control and add a single menu item named &lt;strong&gt;Exit&lt;/strong&gt; to the list.&amp;nbsp; Double-click on that menu item to create a default &lt;strong&gt;Click &lt;/strong&gt;event.&amp;nbsp; In the code for the &lt;strong&gt;Click&lt;/strong&gt; event, simply close the form as follows:&lt;/p&gt; &lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; mnuExit_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// exit the application&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Close();
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; mnuExit_Click(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs) &lt;span style="color: #0000ff"&gt;Handles&lt;/span&gt; mnuExit.Click
    &lt;span style="color: #008000"&gt;' exit the application&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.Close()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, add the following events to &lt;strong&gt;frmMain&lt;/strong&gt; by selecting them from the Event Property window and implementing them with the following code:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; frmMain_Resize(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// hide the form&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Hide();
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; frmMain_Load(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// start the WCF service&lt;/span&gt;
    MyServiceHost.StartService();
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; frmMain_FormClosing(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, FormClosingEventArgs e)
{
    &lt;span style="color: #008000"&gt;// stop the WCF service&lt;/span&gt;
    MyServiceHost.StopService();
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; frmMain_Resize(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs) &lt;span style="color: #0000ff"&gt;Handles&lt;/span&gt; &lt;span style="color: #0000ff"&gt;MyBase&lt;/span&gt;.Resize
    &lt;span style="color: #008000"&gt;' hide the form&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.Hide()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; frmMain_Load(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs) &lt;span style="color: #0000ff"&gt;Handles&lt;/span&gt; &lt;span style="color: #0000ff"&gt;MyBase&lt;/span&gt;.Load
    &lt;span style="color: #008000"&gt;' start the WCF service&lt;/span&gt;
    MyServiceHost.StartService()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; frmMain_FormClosing(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; FormClosingEventArgs) &lt;span style="color: #0000ff"&gt;Handles&lt;/span&gt; &lt;span style="color: #0000ff"&gt;MyBase&lt;/span&gt;.FormClosing
    &lt;span style="color: #008000"&gt;' stop the WCF service&lt;/span&gt;
    MyServiceHost.StopService()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code above references a class named &lt;strong&gt;MyServiceHost&lt;/strong&gt;.&amp;nbsp; This is what starts the WCF host and will be discussed next.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;Windows Communication Foundation (WCF)&lt;/h4&gt;
&lt;p&gt;Windows Communication Foundation (formerly known as Indigo) is a feature of the .NET Framework 3.0 that allows one to build and run connected systems.&amp;nbsp; The simplest definition that fits with what we will be doing here is that it allows an application running on one machine (the client, in this case, the ASP.NET application) to execute a method on another machine (the host, in this case, the application we're currently building).&lt;/p&gt;
&lt;p&gt;First, add a reference to the &lt;strong&gt;System.ServiceModel&lt;/strong&gt; assembly.&amp;nbsp; Then, add a class to the project named &lt;strong&gt;WHSMailService&lt;/strong&gt;.&amp;nbsp; Open the class and add the following code beneath the generated &lt;strong&gt;WHSMailService&lt;/strong&gt; class implementation:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MyServiceHost
{
    &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ServiceHost myServiceHost = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;

    &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; StartService()
    {
        &lt;span style="color: #008000"&gt;// Instantiate new ServiceHost &lt;/span&gt;
        myServiceHost = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ServiceHost(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(WHSMailService));
        myServiceHost.Open();
    }

    &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; StopService()
    {
        &lt;span style="color: #008000"&gt;// Call StopService from your shutdown logic (i.e. dispose method)&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (myServiceHost.State != CommunicationState.Closed)
            myServiceHost.Close();
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Friend&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; MyServiceHost
    &lt;span style="color: #0000ff"&gt;Friend&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Shared&lt;/span&gt; myServiceHost &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; ServiceHost = &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;

    &lt;span style="color: #0000ff"&gt;Friend&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Shared&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; StartService()
        &lt;span style="color: #008000"&gt;' Instantiate new ServiceHost &lt;/span&gt;
        myServiceHost = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; ServiceHost(&lt;span style="color: #0000ff"&gt;GetType&lt;/span&gt;(WHSMailService))
        myServiceHost.Open()
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

    &lt;span style="color: #0000ff"&gt;Friend&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Shared&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; StopService()
        &lt;span style="color: #008000"&gt;' Call StopService from your shutdown logic (i.e. dispose method)&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; myServiceHost.State &amp;lt;&amp;gt; CommunicationState.Closed &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
            myServiceHost.Close()
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code simply creates a new WCF &lt;strong&gt;ServiceHost&lt;/strong&gt; of the type &lt;strong&gt;WHSMailService&lt;/strong&gt; (which we will implement next) and then opens that host so that it may receive incoming connections.&amp;nbsp; We will look at how this connections are configured later in the article.&lt;/p&gt;
&lt;p&gt;Remember that the code in the form above above called the &lt;strong&gt;StartService&lt;/strong&gt; and &lt;strong&gt;StopService&lt;/strong&gt; methods located here when the main form loads and closes.&amp;nbsp; This very easily allows to immediately start the service host when the application starts and closes the service host when the application exits.&lt;/p&gt;
&lt;h4&gt;Contracts and Entities&lt;/h4&gt;
&lt;p&gt;A contract is an interface that defines which methods are exposed by the service host that can be consumed by the client application.&amp;nbsp; Both the client application and the server application will need to know what is in this interface, so we will need to create a second project that will contain the interface definition.&amp;nbsp; Additionally, we will need a way to pass folder and email information to and from each application, so we will define some custom classes to encapsulate those objects.&lt;/p&gt;
&lt;p&gt;Create a new &lt;strong&gt;Class Library&lt;/strong&gt; project in the current solution named &lt;strong&gt;WHSMailCommon&lt;/strong&gt;.&amp;nbsp; In this new project, create a directory named &lt;strong&gt;Contracts&lt;/strong&gt; and a directory named &lt;strong&gt;Entities&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Inside the &lt;strong&gt;Entities&lt;/strong&gt; directory, create a new class named &lt;strong&gt;Folder&lt;/strong&gt;.&amp;nbsp; This will represent an Outlook message folder.&amp;nbsp; The class should look like the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Collections.Generic;

&lt;span style="color: #0000ff"&gt;namespace&lt;/span&gt; WHSMailCommon.Entities
{
    &lt;span style="color: #008000"&gt;// entity object representing an Folder&lt;/span&gt;
    [Serializable]
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Folder : IComparable
    {
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _entryID;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _name;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; List&amp;lt;Folder&amp;gt; _folders;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _unreadMessages;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _totalMessages;

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Folder(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; unreadMessages, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; totalMessages)
        {
            _entryID = entryID;
            _name = name;
            _unreadMessages = unreadMessages;
            _totalMessages = totalMessages;
        }

        &lt;span style="color: #008000"&gt;// MAPI unique identifier&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EntryID
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _entryID; }
            set { _entryID = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #008000"&gt;// subfolders of this folder&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; List&amp;lt;Folder&amp;gt; Folders
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _folders; }
            set { _folders = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _name; }
            set { _name = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; UnreadMessages
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._unreadMessages; }
            set { &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._unreadMessages = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; TotalMessages
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._totalMessages; }
            set { &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._totalMessages = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #008000"&gt;// used so we can sort the folders alphabetically later on&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; CompareTo(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj)
        {
            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Compare(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Name, ((Folder)obj).Name);
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; Microsoft.VisualBasic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.Collections.Generic

&lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt; WHSMailCommon.Entities
    &lt;span style="color: #008000"&gt;' entity object representing an Folder&lt;/span&gt;
    &amp;lt;Serializable&amp;gt; _
    &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; Folder
        &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IComparable
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _name &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _folders &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder)
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _unreadMessages &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _totalMessages &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; &lt;span style="color: #0000ff"&gt;New&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; name &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; unreadMessages &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; totalMessages &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;)
            _entryID = entryID
            _name = name
            _unreadMessages = unreadMessages
            _totalMessages = totalMessages
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' MAPI unique identifier&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; EntryID() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _entryID
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _entryID = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' subfolders of this folder&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Folders() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder)
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _folders
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder))
                _folders = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Name() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _name
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _name = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; UnreadMessages() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;._unreadMessages
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;)
                &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;._unreadMessages = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; TotalMessages() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;._totalMessages
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;)
                &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;._totalMessages = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' used so we can sort the folders alphabetically later on&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; CompareTo(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; obj &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IComparable.CompareTo
            &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;.Compare(&lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.Name, (&lt;span style="color: #0000ff"&gt;CType&lt;/span&gt;(obj, Folder)).Name)
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This class defines several properties to describe the folder (EntryID, Name, etc.) and additionally implements the &lt;strong&gt;IComparable &lt;/strong&gt;interface's &lt;strong&gt;CompareTo&lt;/strong&gt; method&amp;nbsp;so that we can easily sort the folders alphabetically later on.&lt;/p&gt;
&lt;p&gt;Next, create a class named &lt;strong&gt;Email&lt;/strong&gt;.&amp;nbsp; The code for this class looks like the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Text;

&lt;span style="color: #0000ff"&gt;namespace&lt;/span&gt; WHSMailCommon.Entities
{
    &lt;span style="color: #008000"&gt;// entity object representing an Email&lt;/span&gt;
    [Serializable]
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Email
    {
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _entryID;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _from;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _fromName;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _subject;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; DateTime _received;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _size;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _body;

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Email(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; from, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; fromName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; subject, DateTime received, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; size)
        {
            _entryID = entryID;
            _from = from;
            _fromName = fromName;
            _subject = &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(subject) ? &lt;span style="color: #006080"&gt;"(no subject)"&lt;/span&gt; : subject;
            _received = received;
            _size = size;
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Email(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; from, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; fromName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; subject, DateTime received, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; size, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; body) :
            &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;(entryID, from, fromName, subject, received, size)
        {
            _body = body;
        }

        &lt;span style="color: #008000"&gt;// MAPI unique ID&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EntryID
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _entryID; }
            set { _entryID = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #008000"&gt;// email address of sender&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; From
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _from; }
            set { _from = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #008000"&gt;// name of sender&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; FromName
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _fromName; }
            set { _fromName = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Subject
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _subject; }
            set { _subject = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Body
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _body; }
            set { _body = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DateTime Received
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _received; }
            set { _received = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Size
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _size; }
            set { _size = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; }
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; Microsoft.VisualBasic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.Collections.Generic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.Text

&lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt; WHSMailCommon.Entities
    &lt;span style="color: #008000"&gt;' entity object representing an Email&lt;/span&gt;
    &amp;lt;Serializable&amp;gt; _
    &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; Email
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _from &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _fromName &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _subject &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _received &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; DateTime
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _size &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _body &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; &lt;span style="color: #0000ff"&gt;New&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; From &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; fromName &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; subject &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; received &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; DateTime, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; size &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;)
            _entryID = entryID
            _from = From
            _fromName = fromName
            &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;.IsNullOrEmpty(subject) &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
                _subject = &lt;span style="color: #006080"&gt;"(no subject)"&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Else&lt;/span&gt;
                _subject = subject
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
            _received = received
            _size = size
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; &lt;span style="color: #0000ff"&gt;New&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; From &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; fromName &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; subject &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; received &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; DateTime, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; size &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; body &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
            &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.&lt;span style="color: #0000ff"&gt;New&lt;/span&gt;(entryID, From, fromName, subject, received, size)
            _body = body
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' MAPI unique ID&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; EntryID() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _entryID
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _entryID = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' email address of sender&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; From() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _from
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _from = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' name of sender&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; FromName() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _fromName
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _fromName = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Subject() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _subject
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _subject = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Body() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _body
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)
                _body = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Received() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; DateTime
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _received
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; DateTime)
                _received = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; Size() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _size
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; value &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;)
                _size = value
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Set&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This class simply contains properties to describe an email message.&lt;/p&gt;
&lt;p&gt;You will note that both of these classes have the &lt;strong&gt;[Serializable]&lt;/strong&gt; attribute attached to them.&amp;nbsp; When objects are passed through WCF, they are serialized at the source and deserialized at the destination.&amp;nbsp; By marking the objects with the &lt;strong&gt;[Serializable]&lt;/strong&gt; attribute, the .NET CLR can do this for us automatically&amp;nbsp; since we are not using any complex data types in our entities.&lt;/p&gt;
&lt;p&gt;With our entities out of the way, we can define our contract.&amp;nbsp;&amp;nbsp;Inside&amp;nbsp;the &lt;strong&gt;Contracts&lt;/strong&gt;&amp;nbsp;directory, create a new &lt;strong&gt;Interface&lt;/strong&gt; file named &lt;strong&gt;IWHSMailService&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This interface/contract will define three methods:&amp;nbsp; one method to return a tree of objects which represent the folder tree in Outlook (&lt;strong&gt;GetFolders&lt;/strong&gt;), one method to return a list of messages inside that folder (&lt;strong&gt;GetMessages&lt;/strong&gt;), and one method to return the contents of a specific message (&lt;strong&gt;GetMessages&lt;/strong&gt;).&amp;nbsp; The interface will look like the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.ServiceModel;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; WHSMailCommon.Entities;

&lt;span style="color: #0000ff"&gt;namespace&lt;/span&gt; WHSMailCommon.Contracts
{
    &lt;span style="color: #008000"&gt;// list of methods of the WHSMailService service&lt;/span&gt;
    [ServiceContract()]
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IWHSMailService
    {
        [OperationContract]
        List&amp;lt;Folder&amp;gt; GetFolders();

        [OperationContract]
        List&amp;lt;Email&amp;gt; GetMessages(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; numPerPage, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; pageNum);

        [OperationContract]
        Email GetMessage(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; Microsoft.VisualBasic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.Collections.Generic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.ServiceModel
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; WHSMailCommon.Entities

&lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt; WHSMailCommon.Contracts
    &lt;span style="color: #008000"&gt;' list of methods of the WHSMailService service&lt;/span&gt;
    &amp;lt;ServiceContract()&amp;gt; _
    &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Interface&lt;/span&gt; IWHSMailService
        &amp;lt;OperationContract&amp;gt; _
        &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetFolders() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder)

        &amp;lt;OperationContract&amp;gt; _
        &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetMessages(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; numPerPage &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; pageNum &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email)

        &amp;lt;OperationContract&amp;gt; _
        &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetMessage(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Email
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Interface&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As with the entities, this interface is also decorated with several attributes.&amp;nbsp; First, any WCF contract interface must be tagged with the &lt;strong&gt;[ServiceContract()]&lt;/strong&gt; attribute to define it as a contract to WCF.&amp;nbsp; Additionally, all methods which will be exposed for consumption by a client must be marked with the &lt;strong&gt;[OperationContract]&lt;/strong&gt; attribute.&lt;/p&gt;
&lt;p&gt;The implementation and description of these methods will come later when we write the contract implementation.&lt;/p&gt;
&lt;h4&gt;&lt;/h4&gt;
&lt;h4&gt;Configuration&lt;/h4&gt;
&lt;p&gt;The final thing to setup on the WCF server is the configuration file.&amp;nbsp; The service can very easily be configured using an application configuration file.&amp;nbsp; Add an &lt;strong&gt;Application Configuration&lt;/strong&gt; file to the project named &lt;strong&gt;App.config&lt;/strong&gt;.&amp;nbsp; Set the contents of the file to the following:&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #800000"&gt;xml&lt;/span&gt; &lt;span style="color: #ff0000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="1.0"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;encoding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="utf-8"&lt;/span&gt; ?&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;system.serviceModel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;bindings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;netTcpBinding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;binding&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="NewBinding0"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;security&lt;/span&gt; &lt;span style="color: #ff0000"&gt;mode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="None"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;binding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;netTcpBinding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;bindings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;services&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;service&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="WHSMailHost.WHSMailService"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;endpoint&lt;/span&gt; &lt;span style="color: #ff0000"&gt;address&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="net.tcp://localhost:12345/IWHSMailService"&lt;/span&gt;
                    &lt;span style="color: #ff0000"&gt;binding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="netTcpBinding"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;bindingConfiguration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="NewBinding0"&lt;/span&gt;
                    &lt;span style="color: #ff0000"&gt;contract&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="WHSMailCommon.Contracts.IWHSMailService"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;service&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;services&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;system.serviceModel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;&amp;lt;services&amp;gt;&lt;/strong&gt; section defines the services that the WCF host will enable.&amp;nbsp; This creates a single &lt;strong&gt;&amp;lt;service&amp;gt;&lt;/strong&gt; named &lt;strong&gt;WHSMailHost.WHSMailService&lt;/strong&gt;, which is the full name of the service class that we will implement shortly.&amp;nbsp; Inside the &lt;strong&gt;&amp;lt;service&amp;gt;&lt;/strong&gt; tag an endpoint is defined.&amp;nbsp; And endpoint is essentially the "port" on which the client connects.&amp;nbsp; The endpoint defined here is using the &lt;strong&gt;net.tcp&lt;/strong&gt; protocol and is set to listen on the &lt;strong&gt;localhost&lt;/strong&gt; on port &lt;strong&gt;12345&lt;/strong&gt; at the name &lt;strong&gt;IWHSMailService&lt;/strong&gt;.&amp;nbsp; The next thing defined is a binding.&amp;nbsp; This sets protocol by which the service will communicate, its configuration,&amp;nbsp;and the contract it implements.&amp;nbsp; The binding configuration named &lt;strong&gt;NewBinding0&lt;/strong&gt; (a default name) can be found above inside the &lt;strong&gt;&amp;lt;bindings&amp;gt;&lt;/strong&gt; tag.&amp;nbsp; The only configuration item that is specified is that security will be turned off for communication between the client and server.&amp;nbsp; Given that these two machines will be connecting to each other on your own local network, security is not a great concern.&amp;nbsp; If you were to use this over a real internet connection where the client and server were open to the outside world, you would definitely not want to do this.&lt;/p&gt;
&lt;p&gt;There are around several billion other options, protocols, bindings, etc. etc. etc. that can be configured here.&amp;nbsp; At the end of the article you will find several links to WCF documentation that you can explore to learn more about the WCF internals.&amp;nbsp; Also note that you can configure WCF with a windows UI by selecting the &lt;strong&gt;Service Configuration Editor&lt;/strong&gt; application installed with the Windows SDK.&amp;nbsp; You'll find this in the &lt;strong&gt;Microsoft Windows SDK&lt;/strong&gt; program group off your Start menu.&lt;/p&gt;
&lt;h3&gt;Outlook and MAPI&lt;/h3&gt;
&lt;p&gt;MAPI (Messaging Application Programming Interface) is what allows one to develop applications and plugins for Microsoft Outlook and other messaging applications which support it (Exchange, Windows Messaging, etc.).&amp;nbsp; We will be using MAPI to get the data we require from Outlook for our application.&lt;/p&gt;
&lt;p&gt;Earlier we created a contract named &lt;strong&gt;IWHSMailService&lt;/strong&gt;.&amp;nbsp; This contract will be implemented by the &lt;strong&gt;WHSMailService&lt;/strong&gt; class that was also created earlier.&amp;nbsp; To do this, set a reference to the project's &lt;strong&gt;WHSMailCommon&lt;/strong&gt; assembly.&amp;nbsp; Then, bring the &lt;strong&gt;Contracts&lt;/strong&gt; and &lt;strong&gt;Entities&lt;/strong&gt; namespaces into the &lt;strong&gt;WHSMailService&lt;/strong&gt; class with the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; WHSMailCommon.Contracts;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; WHSMailCommon.Entities;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; WHSMailCommon.Contracts
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; WHSMailCommon.Entities&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, setup the class to implement the interface as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; WHSMailService : IWHSMailService&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; WHSMailService
    &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IWHSMailService
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Visual Studio will then create the 3 methods that must be implemented according to the interface (&lt;strong&gt;GetFolders&lt;/strong&gt;, &lt;strong&gt;GetMessages&lt;/strong&gt;, &lt;strong&gt;GetMessage&lt;/strong&gt;).&amp;nbsp; We will fill those in shortly.&amp;nbsp; But first, we must implement our constructor.&amp;nbsp; When WCF calls the service, a new instance of the object will be created on each call.&amp;nbsp; Therefore, it is easy to setup any initialization code for the service in the default constructor method.&amp;nbsp; In this case, we will initialize the MAPI layer and logon to the default instance.&lt;/p&gt;
&lt;p&gt;First, set a reference to the &lt;strong&gt;Microsoft Outlook XX.0 Object Library&lt;/strong&gt; which you will find under the COM tab assuming Outlook is installed as per the instructions above.&amp;nbsp; Note that the version will depend on what version of Outlook you have installed on your local machine.&amp;nbsp; I'm using Outlook 2007, so version 12 is what the sample code above is referencing.&amp;nbsp; If you are using a different version, reference the appropriate version before continuing.&lt;/p&gt;
&lt;p&gt;Once the reference is set, bring the namespace into the &lt;strong&gt;WHSMailService&lt;/strong&gt; class with the following line which will import the namespace and setup an alias named &lt;strong&gt;Outlook&lt;/strong&gt; to save some typing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; Outlook = Microsoft.Office.Interop.Outlook;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; Outlook = Microsoft.Office.Interop.Outlook&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the constructor can be implemented.&amp;nbsp; We need to get an instance of the Outlook &lt;strong&gt;ApplicationClass&lt;/strong&gt;.&amp;nbsp; From there we can get an instance of the &lt;strong&gt;MAPI&lt;/strong&gt; namespace.&amp;nbsp; All methods that we will be using hang off that namespace object.&amp;nbsp; The code for the constructor follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; Outlook.NameSpace _nameSpace = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;

&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; WHSMailService()
{
    &lt;span style="color: #008000"&gt;// get an instance of the MAPI namespace and login&lt;/span&gt;
    Outlook.Application app = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Outlook.ApplicationClass();
    _nameSpace = app.GetNamespace(&lt;span style="color: #006080"&gt;"MAPI"&lt;/span&gt;);
    _nameSpace.Logon(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;ReadOnly&lt;/span&gt; _nameSpace &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.&lt;span style="color: #0000ff"&gt;NameSpace&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; &lt;span style="color: #0000ff"&gt;New&lt;/span&gt;()
    &lt;span style="color: #008000"&gt;' get an instance of the MAPI namespace and login&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; app &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.Application = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; Outlook.ApplicationClass()
    _nameSpace = app.GetNamespace(&lt;span style="color: #006080"&gt;"MAPI"&lt;/span&gt;)
    _nameSpace.Logon(&lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;False&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;False&lt;/span&gt;)
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With a handle to the namespace, we can write our &lt;strong&gt;GetFolders&lt;/strong&gt; method.&amp;nbsp; This method will get the default Inbox folder in the default Outlook message store, look at the parent node, recursively enumerate from there, pulling out only folders that contain mail items, and finally sort them alphabetically (recall the &lt;strong&gt;CompareTo&lt;/strong&gt; method of the &lt;strong&gt;IComparable&lt;/strong&gt; interface we implemented earlier).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; List&amp;lt;Folder&amp;gt; GetFolders()
{
    List&amp;lt;Folder&amp;gt; list = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Folder&amp;gt;();

    &lt;span style="color: #008000"&gt;// get the inbox and then go up one level...that *should* be the root of the default store&lt;/span&gt;
    Outlook.MAPIFolder root = (Outlook.MAPIFolder)_nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent;

    &lt;span style="color: #008000"&gt;// add root folder&lt;/span&gt;
    Folder folder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Folder(root.EntryID, root.Name, root.UnReadItemCount, root.Items.Count);
    list.Add(folder);

    &lt;span style="color: #008000"&gt;// Enumerate the sub-folders&lt;/span&gt;
    EnumerateFolders(root.Folders, folder);

    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; list;
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; EnumerateFolders(Outlook.Folders folders, Folder rootFolder)
{
    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(Outlook.MAPIFolder f &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; folders)
    {
        &lt;span style="color: #008000"&gt;// ensure it's a folder that contains mail messages (i.e. no contacts, appointments, etc.)&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(f.DefaultItemType == Outlook.OlItemType.olMailItem)
        {
            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(rootFolder.Folders == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
                rootFolder.Folders = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Folder&amp;gt;();

            &lt;span style="color: #008000"&gt;// add the current folder and enumerate all sub-folders&lt;/span&gt;
            Folder subFolder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Folder(f.EntryID, f.Name, f.UnReadItemCount, f.Items.Count);
            rootFolder.Folders.Add(subFolder);
            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(f.Folders.Count &amp;gt; 0)
                &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.EnumerateFolders(f.Folders, subFolder);
        }
    }

    &lt;span style="color: #008000"&gt;// alphabetize the list (Folder implements IComparable)&lt;/span&gt;
    rootFolder.Folders.Sort();
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetFolders() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder) &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IWHSMailService.GetFolders
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder) = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; List(Of Folder)()

    &lt;span style="color: #008000"&gt;' get the inbox and then go up one level...that *should* be the root of the default store&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; root &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.MAPIFolder = &lt;span style="color: #0000ff"&gt;CType&lt;/span&gt;(_nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent, Outlook.MAPIFolder)

    &lt;span style="color: #008000"&gt;' add root folder&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; folder &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Folder = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; Folder(root.EntryID, root.Name, root.UnReadItemCount, root.Items.Count)
    list.Add(folder)

    &lt;span style="color: #008000"&gt;' Enumerate the sub-folders&lt;/span&gt;
    EnumerateFolders(root.Folders, folder)

    &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; list
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; EnumerateFolders(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; folders &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.Folders, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; rootFolder &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Folder)
    &lt;span style="color: #0000ff"&gt;For&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Each&lt;/span&gt; f &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.MAPIFolder &lt;span style="color: #0000ff"&gt;In&lt;/span&gt; folders
        &lt;span style="color: #008000"&gt;' ensure it's a folder that contains mail messages (i.e. no contacts, appointments, etc.)&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; f.DefaultItemType = Outlook.OlItemType.olMailItem &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; rootFolder.Folders &lt;span style="color: #0000ff"&gt;Is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
                rootFolder.Folders = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; List(Of Folder)()
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;

            &lt;span style="color: #008000"&gt;' add the current folder and enumerate all sub-folders&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; subFolder &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Folder = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; Folder(f.EntryID, f.Name, f.UnReadItemCount, f.Items.Count)
            rootFolder.Folders.Add(subFolder)
            &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; f.Folders.Count &amp;gt; 0 &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.EnumerateFolders(f.Folders, subFolder)
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Next&lt;/span&gt; f

    &lt;span style="color: #008000"&gt;' alphabetize the list (Folder implements IComparable)&lt;/span&gt;
    rootFolder.Folders.Sort()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code will return a generic hierarchal list of our &lt;strong&gt;Folder&lt;/strong&gt; entity objects which&amp;nbsp;will be displayed in the web application.&amp;nbsp; Note that one of the items assigned to the &lt;strong&gt;Folder&lt;/strong&gt; entity is the &lt;strong&gt;EntryID&lt;/strong&gt; property from the &lt;strong&gt;MAPIFolder&lt;/strong&gt; object.&amp;nbsp; All MAPI items, be they email messages, folders, appointments, etc. have a unique identifier which is stored in the &lt;strong&gt;EntryID&lt;/strong&gt; field.&amp;nbsp; We will need this unique value later on to retrieve messages from that folder.&lt;/p&gt;
&lt;p&gt;Next, let's implement the &lt;strong&gt;GetMessages&lt;/strong&gt; method.&amp;nbsp; This method will return a list of messages (minus the bodies) from&amp;nbsp;the folder specified using the &lt;strong&gt;GetFolderFromID&lt;/strong&gt; method, sorted by the received date with the most current first.&amp;nbsp; It will also handle paging so that the entire folder is not returned at once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; List&amp;lt;Email&amp;gt; GetMessages(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; numPerPage, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; pageNum)
{
    List&amp;lt;Email&amp;gt; list = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Email&amp;gt;();

    Outlook.MAPIFolder f;

    &lt;span style="color: #008000"&gt;// if no ID specified, open the inbox&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(entryID))
        f = _nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;
        f = _nameSpace.GetFolderFromID(entryID, &lt;span style="color: #006080"&gt;""&lt;/span&gt;);

    &lt;span style="color: #008000"&gt;// to handle the sorting, one needs to cache their own instance of the items object&lt;/span&gt;
    Outlook.Items items = f.Items;

    &lt;span style="color: #008000"&gt;// sort descending by received time&lt;/span&gt;
    items.Sort(&lt;span style="color: #006080"&gt;"[ReceivedTime]"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);

    &lt;span style="color: #008000"&gt;// pull in the correct number of items based on number of items per page and current page number&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = (numPerPage*pageNum)+1; i &amp;lt;= (numPerPage*pageNum)+numPerPage &amp;amp;&amp;amp; i &amp;lt;= items.Count; i++)
    {
        &lt;span style="color: #008000"&gt;// ensure it's a mail message&lt;/span&gt;
        Outlook.MailItem mi = (items[i] &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; Outlook.MailItem);
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(mi != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
            list.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size));
    }

    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; list;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetMessages(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; numPerPage &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; pageNum &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IWHSMailService.GetMessages
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; List(Of Email)()

    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; f &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.MAPIFolder

    &lt;span style="color: #008000"&gt;' if no ID specified, open the inbox&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;.IsNullOrEmpty(entryID) &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
        f = _nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
    &lt;span style="color: #0000ff"&gt;Else&lt;/span&gt;
        f = _nameSpace.GetFolderFromID(entryID, &lt;span style="color: #006080"&gt;""&lt;/span&gt;)
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;

    &lt;span style="color: #008000"&gt;' to handle the sorting, one needs to cache their own instance of the items object&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; items &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.Items = f.Items

    &lt;span style="color: #008000"&gt;' sort descending by received time&lt;/span&gt;
    items.Sort(&lt;span style="color: #006080"&gt;"[ReceivedTime]"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;True&lt;/span&gt;)

    &lt;span style="color: #008000"&gt;' pull in the correct number of items based on number of items per page and current page number&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; i &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt; = (numPerPage*pageNum)+1
    &lt;span style="color: #0000ff"&gt;Do&lt;/span&gt; &lt;span style="color: #0000ff"&gt;While&lt;/span&gt; i &amp;lt;= (numPerPage*pageNum)+numPerPage &lt;span style="color: #0000ff"&gt;AndAlso&lt;/span&gt; i &amp;lt;= items.Count
        &lt;span style="color: #008000"&gt;' ensure it's a mail message&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; mi &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.MailItem = (&lt;span style="color: #0000ff"&gt;TryCast&lt;/span&gt;(items(i), Outlook.MailItem))
        &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Not&lt;/span&gt; mi &lt;span style="color: #0000ff"&gt;Is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
            list.Add(&lt;span style="color: #0000ff"&gt;New&lt;/span&gt; Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size))
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
        i += 1
    &lt;span style="color: #0000ff"&gt;Loop&lt;/span&gt;

    &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; list
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The method takes a string parameter named &lt;strong&gt;entryID&lt;/strong&gt; which is the unique identifier of the folder (from the code above) from which to return the messages.&amp;nbsp; If no ID is specified, messages are returned from the Inbox.&amp;nbsp; This code also handles paging by indexing into the array of &lt;strong&gt;Items&lt;/strong&gt; of the &lt;strong&gt;MAPIFolder&lt;/strong&gt; object at the specified position and counting out &lt;strong&gt;numPerPage&lt;/strong&gt; records to be returned.&amp;nbsp; A list of &lt;strong&gt;Email&lt;/strong&gt; entity objects is returned from this method to be displayed on the web interface.&lt;/p&gt;
&lt;p&gt;Finally, let's implement the &lt;strong&gt;GetMessage&lt;/strong&gt; method.&amp;nbsp; This will return a specific message based on the MAPI &lt;strong&gt;EntryID&lt;/strong&gt; using the &lt;strong&gt;GetItemFromID&lt;/strong&gt; method and format the body for plain text or HTML display.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Email GetMessage(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; entryID)
{
    &lt;span style="color: #008000"&gt;// pull the message&lt;/span&gt;
    Outlook.MailItem mi = (_nameSpace.GetItemFromID(entryID, &lt;span style="color: #006080"&gt;""&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; Outlook.MailItem);

    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (mi != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; body;

        &lt;span style="color: #008000"&gt;// if it's a plain format message, wrap it in &amp;lt;pre&amp;gt; tags for nice output&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(mi.BodyFormat == Outlook.OlBodyFormat.olFormatPlain)
            body = &lt;span style="color: #006080"&gt;"&amp;lt;pre&amp;gt;"&lt;/span&gt; + mi.Body + &lt;span style="color: #006080"&gt;"&amp;lt;/pre&amp;gt;"&lt;/span&gt;;
        &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;
            body = mi.HTMLBody;

        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size, body);
    }
    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetMessage(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; entryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Email &lt;span style="color: #0000ff"&gt;Implements&lt;/span&gt; IWHSMailService.GetMessage
    &lt;span style="color: #008000"&gt;' pull the message&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; mi &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Outlook.MailItem = (&lt;span style="color: #0000ff"&gt;TryCast&lt;/span&gt;(_nameSpace.GetItemFromID(entryID, &lt;span style="color: #006080"&gt;""&lt;/span&gt;), Outlook.MailItem))

    &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Not&lt;/span&gt; mi &lt;span style="color: #0000ff"&gt;Is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; body &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;

        &lt;span style="color: #008000"&gt;' if it's a plain format message, wrap it in &amp;lt;pre&amp;gt; tags for nice output&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; mi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
            body = &lt;span style="color: #006080"&gt;"&amp;lt;pre&amp;gt;"&lt;/span&gt; &amp;amp; mi.Body &amp;amp; &lt;span style="color: #006080"&gt;"&amp;lt;/pre&amp;gt;"&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Else&lt;/span&gt;
            body = mi.HTMLBody
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size, body)
    &lt;span style="color: #0000ff"&gt;Else&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With these three methods in place, we can get our folders, get messages in those folders, and get a specific message from a folder.&amp;nbsp; Now we can switch our attention to the web-based "client" application which will plug into WHS.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;ASP.NET "Client"&lt;/h3&gt;
&lt;p&gt;The client we are going to produce is going to be a very simple 3-paned screen much like Outlook&amp;nbsp;with folders on the left, messages on the top right, and message text on the bottom right.&lt;/p&gt;
&lt;p&gt;Create a new&amp;nbsp;&lt;strong&gt;ASP.NET Web Application&lt;/strong&gt; named &lt;strong&gt;WHSMailWeb &lt;/strong&gt;(if you are using the Express editions of Visual Studio, you will need to do this in Visual Web Developer Express).&amp;nbsp; Set a reference to the&amp;nbsp;&lt;strong&gt;WHSMailCommon&lt;/strong&gt; assembly along with the &lt;strong&gt;System.ServiceModel&lt;/strong&gt; assembly.&amp;nbsp; Again, if you are in Express, you will have to set the reference to &lt;strong&gt;WHSMailCommon&lt;/strong&gt; in the other project's bin directory.&lt;/p&gt;
&lt;p&gt;First, let's configure the ASP.NET application so it can properly call our WCF service running on the host machine.&amp;nbsp; Open the &lt;strong&gt;web.config&lt;/strong&gt; file and add the following after the end &lt;strong&gt;&amp;lt;/system.web&amp;gt;&lt;/strong&gt; tag and before the end &lt;strong&gt;&amp;lt;/configuration&amp;gt;&lt;/strong&gt; tab:&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;system.serviceModel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;bindings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;netTcpBinding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;binding&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="NewBinding0"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;maxReceivedMessageSize&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="1048576"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;readerQuotas&lt;/span&gt; &lt;span style="color: #ff0000"&gt;maxStringContentLength&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="1048576"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;security&lt;/span&gt; &lt;span style="color: #ff0000"&gt;mode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="None"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;binding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;netTcpBinding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;bindings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;client&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;endpoint&lt;/span&gt; &lt;span style="color: #ff0000"&gt;address&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="net.tcp://SERVERNAME:12345/IWHSMailService"&lt;/span&gt;
            &lt;span style="color: #ff0000"&gt;binding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="netTcpBinding"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;bindingConfiguration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="NewBinding0"&lt;/span&gt;
            &lt;span style="color: #ff0000"&gt;contract&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="WHSMailCommon.Contracts.IWHSMailService"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="WHSMailService"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;client&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;system.serviceModel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This looks very similar to the configuration information from our host service.&amp;nbsp; An endpoint is defined which points to the host server.&amp;nbsp; &lt;strong&gt;YOU WILL NEED TO CHANGE THE "SERVERNAME" HOST TO THE NAME OR IP ADDRESS OF THE MACHINE THAT WILL RUN THE HOST SERVICE WE CREATED ABOVE!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You will see the same setup for the binding and contract.&amp;nbsp; The &lt;strong&gt;name&lt;/strong&gt; parameter will be used by the code a bit later so WCF knows how to contact the host to instantiate the remote object.&lt;/p&gt;
&lt;p&gt;The one thing that is different here is the&amp;nbsp;&lt;strong&gt;netTcpBinding&lt;/strong&gt; configuration.&amp;nbsp; The security mode is set to &lt;strong&gt;none&lt;/strong&gt; as it was before, but we have the addition of the &lt;strong&gt;maxReceivedMessageSize&lt;/strong&gt; and &lt;strong&gt;maxStringContentLength&lt;/strong&gt;.&amp;nbsp; Both of these are set at 1 megabyte to allow that much data to be transferred from the host to the client.&amp;nbsp; The default is only 64K which is not enough to return most of the data we need to serialize and transmit between the two machines.&lt;/p&gt;
&lt;p&gt;Next, add a page to the project named &lt;strong&gt;BasePage&lt;/strong&gt;.&amp;nbsp; This page will be inherited by all pages in the project to easily startup and shutdown the WCF channel required to retrieve the message data.&lt;/p&gt;
&lt;p&gt;Open the code-behind file for &lt;strong&gt;BasePage&lt;/strong&gt; and add the following code:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.ServiceModel;
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; WHSMailCommon.Contracts;

&lt;span style="color: #0000ff"&gt;namespace&lt;/span&gt; WHSMailWeb
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;partial&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; BasePage : System.Web.UI.Page
    {
        ChannelFactory&amp;lt;IWHSMailService&amp;gt; _factory = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;
        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; IWHSMailService _channel = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;

        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Page_Init(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            &lt;span style="color: #008000"&gt;// create a channel factory and then instantiate a proxy channel&lt;/span&gt;
            _factory = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ChannelFactory&amp;lt;IWHSMailService&amp;gt;(&lt;span style="color: #006080"&gt;"WHSMailService"&lt;/span&gt;);
            _channel = _factory.CreateChannel();
        }

        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Page_Unload(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
            {
                _factory.Close();
            }
            &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt;
            {
                &lt;span style="color: #008000"&gt;// for the moment, we don't really care what happens here...if it fails, so be it&lt;/span&gt;
            }
        }

        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IWHSMailService WHSMailService
        {
            get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _channel; }
        }
    
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; Microsoft.VisualBasic
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; System.ServiceModel
&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; WHSMailCommon.Contracts

&lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt; WHSMailWeb
    &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; Partial &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; BasePage
        &lt;span style="color: #0000ff"&gt;Inherits&lt;/span&gt; System.Web.UI.Page
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _factory &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; ChannelFactory(Of IWHSMailService) = &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _channel &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; IWHSMailService = &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; Page_Init(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
            &lt;span style="color: #008000"&gt;' create a channel factory and then instantiate a proxy channel&lt;/span&gt;
            _factory = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; ChannelFactory(Of IWHSMailService)(&lt;span style="color: #006080"&gt;"WHSMailService"&lt;/span&gt;)
            _channel = _factory.CreateChannel()
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; Page_Unload(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
            &lt;span style="color: #0000ff"&gt;Try&lt;/span&gt;
                _factory.Close()
            &lt;span style="color: #0000ff"&gt;Catch&lt;/span&gt;
                &lt;span style="color: #008000"&gt;' for the moment, we don't really care what happens here...if it fails, so be it&lt;/span&gt;
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Try&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

        &lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;ReadOnly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt; WHSMailService() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; IWHSMailService
            &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
                &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; _channel
            &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Get&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Property&lt;/span&gt;

    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Namespace&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code overrides the page's &lt;strong&gt;Init&lt;/strong&gt; and &lt;strong&gt;Unload&lt;/strong&gt; methods.&amp;nbsp; &lt;strong&gt;Page_Init&lt;/strong&gt; is called at the beginning of a page request and &lt;strong&gt;Page_Unload&lt;/strong&gt; is called just before the request completes.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Page_Init&lt;/strong&gt; method here uses WCF to create a &lt;strong&gt;ChannelFactory&lt;/strong&gt; object factory that will return proxy objects of type &lt;strong&gt;IWHSMailService&lt;/strong&gt;.&amp;nbsp; Recall that this is the interface which defines the contract of our service.&amp;nbsp; The name passed as a parameter to the &lt;strong&gt;ChannelFactory&lt;/strong&gt; constructor must match the name of the service in the configuration file, as discussed earlier.&lt;/p&gt;
&lt;p&gt;Next, a channel object is created by calling &lt;strong&gt;CreateChannel&lt;/strong&gt; from the &lt;strong&gt;ChannelFactory&lt;/strong&gt;.&amp;nbsp; This is what returns the fake, proxy object defined by our contract.&amp;nbsp; A property named &lt;strong&gt;WHSMailService&lt;/strong&gt; at the bottom of the class exposes this so that the inherited pages can easily use the object to call the host service.&amp;nbsp; We'll see this a bit later.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Page_Unload&lt;/strong&gt; method simply closes the factory object and very poorly handles any exceptions that may occur when doing so.&amp;nbsp; An error on close isn't critical to this application, but that is certainly not always the case.&lt;/p&gt;
&lt;p&gt;Now we will implement the default page.&amp;nbsp; I'm not going to repeat the entire HTML of the page itself here, and I'm certainly not a HTML/CSS designer, so I wouldn't recommend learning from that anyhow.&amp;nbsp; It does, however, get the job done.&lt;/p&gt;
&lt;p&gt;What you do need to know is that the page contains&amp;nbsp;4 &lt;strong&gt;&amp;lt;DIV&amp;gt; &lt;/strong&gt;tags:&amp;nbsp; one contains an ASP.NET&amp;nbsp;&lt;strong&gt;TreeView&lt;/strong&gt; object (the left-most pane), one contains an ASP.NET &lt;strong&gt;GridView&lt;/strong&gt; object (the top-right pane), one contains 2 ASP.NET &lt;strong&gt;LinkButton&lt;/strong&gt;'s which implement a Next/Back paging scheme (the middle-right pane), &amp;nbsp;and the last contains a table to display some header information, and a &lt;strong&gt;&amp;lt;DIV&amp;gt;&lt;/strong&gt; to display the message contents.&lt;/p&gt;
&lt;p&gt;After that poor description, here's what the application looks like in an instance of Internet Explorer with my instance of Outlook (with some blurring over the (not really) sensitive data):&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/webmail_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="490" alt="webmail" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/webmail_thumb_3.png" width="487" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now let's implement the actual logic for the page.&amp;nbsp; Open the &lt;strong&gt;Default.aspx&lt;/strong&gt; page's code behind file.&amp;nbsp; Bring in the &lt;strong&gt;WHSMailCommon.Entities&lt;/strong&gt; namespace as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; WHSMailCommon.Entities;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Imports&lt;/span&gt; WHSMailCommon.Entities&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, change the &lt;strong&gt;_Default&lt;/strong&gt; class to inherit from &lt;strong&gt;BasePage&lt;/strong&gt; instead of &lt;strong&gt;System.Web.UI.Page&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;partial&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; _Default : BasePage&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Public&lt;/span&gt; Partial &lt;span style="color: #0000ff"&gt;Class&lt;/span&gt; _Default
    &lt;span style="color: #0000ff"&gt;Inherits&lt;/span&gt; BasePage&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, implement the &lt;strong&gt;Page_Load&lt;/strong&gt; method.&amp;nbsp; This method will be called after the &lt;strong&gt;Page_Init&lt;/strong&gt; method which is implemented in our parent object and will be called automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _folderEntryID = &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Empty;
&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _pageNum = 0;

&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Page_Load(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// first time in (tvFolders has viewstate enabled&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(tvFolders.Nodes.Count == 0)
    {
        &lt;span style="color: #008000"&gt;// get the folder tree&lt;/span&gt;
        List&amp;lt;Folder&amp;gt; folderList = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.WHSMailService.GetFolders();

        &lt;span style="color: #008000"&gt;// add the root node and expand it&lt;/span&gt;
        TreeNode node = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TreeNode(folderList[0].Name, folderList[0].EntryID);
        node.Expanded = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;
        tvFolders.Nodes.Add(node);

        &lt;span style="color: #008000"&gt;// load up the sub-folders&lt;/span&gt;
        LoadNode(folderList[0].Folders, node);

        &lt;span style="color: #008000"&gt;// get the inbox list and bind it to the grid&lt;/span&gt;
        List&amp;lt;Email&amp;gt; list = GetMessages();
        BindMessages(list);

        &lt;span style="color: #008000"&gt;// save off the default page number and folder ID&lt;/span&gt;
        ViewState[&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;] = _pageNum;
        ViewState[&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;] = _folderEntryID;
    }

    _pageNum = &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;.Parse(ViewState[&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;].ToString());
    _folderEntryID = ViewState[&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;].ToString();
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; LoadNode(List&amp;lt;Folder&amp;gt; folders, TreeNode node)
{
    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(Folder f &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; folders)
    {
        &lt;span style="color: #008000"&gt;// add the node with the format of Folder (Unread/Total)&lt;/span&gt;
        TreeNode subNode = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TreeNode(f.Name + &lt;span style="color: #006080"&gt;" ("&lt;/span&gt; + f.UnreadMessages + &lt;span style="color: #006080"&gt;"/"&lt;/span&gt; + f.TotalMessages + &lt;span style="color: #006080"&gt;")"&lt;/span&gt;, f.EntryID);

        &lt;span style="color: #008000"&gt;// expand and select the inbox&lt;/span&gt;
        subNode.Expanded = subNode.Selected = (f.Name == &lt;span style="color: #006080"&gt;"Inbox"&lt;/span&gt;);
        node.ChildNodes.Add(subNode);

        &lt;span style="color: #008000"&gt;// load the subfolders&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(f.Folders != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
            LoadNode(f.Folders, subNode);
    }
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; List&amp;lt;Email&amp;gt; GetMessages()
{
    &lt;span style="color: #008000"&gt;// get a group of messages based on the current page number and size&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.WHSMailService.GetMessages(_folderEntryID, GridView1.PageSize, _pageNum);
}

&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; BindMessages(List&amp;lt;Email&amp;gt; list)
{
    &lt;span style="color: #008000"&gt;// load the grid&lt;/span&gt;
    GridView1.DataSource = list;
    GridView1.DataBind();

    &lt;span style="color: #008000"&gt;// save off the new page number&lt;/span&gt;
    ViewState[&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;] = _pageNum;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _folderEntryID &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;String&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;.Empty
&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; _pageNum &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt; = 0

&lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; Page_Load(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
    &lt;span style="color: #008000"&gt;' first time in (tvFolders has viewstate enabled&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; tvFolders.Nodes.Count = 0 &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
        &lt;span style="color: #008000"&gt;' get the folder tree&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; folderList &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder) = &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.WHSMailService.GetFolders()

        &lt;span style="color: #008000"&gt;' add the root node and expand it&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; node &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; TreeNode = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; TreeNode(folderList(0).Name, folderList(0).EntryID)
        node.Expanded = &lt;span style="color: #0000ff"&gt;True&lt;/span&gt;
        tvFolders.Nodes.Add(node)

        &lt;span style="color: #008000"&gt;' load up the sub-folders&lt;/span&gt;
        LoadNode(folderList(0).Folders, node)

        &lt;span style="color: #008000"&gt;' get the inbox list and bind it to the grid&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) = GetMessages()
        BindMessages(list)

        &lt;span style="color: #008000"&gt;' save off the default page number and folder ID&lt;/span&gt;
        ViewState(&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;) = _pageNum
        ViewState(&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;) = _folderEntryID
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;

    _pageNum = &lt;span style="color: #0000ff"&gt;Integer&lt;/span&gt;.Parse(ViewState(&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;).ToString())
    _folderEntryID = ViewState(&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;).ToString()
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; LoadNode(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; folders &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Folder), &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; node &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; TreeNode)
    &lt;span style="color: #0000ff"&gt;For&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Each&lt;/span&gt; f &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Folder &lt;span style="color: #0000ff"&gt;In&lt;/span&gt; folders
        &lt;span style="color: #008000"&gt;' add the node with the format of Folder (Unread/Total)&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; subNode &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; TreeNode = &lt;span style="color: #0000ff"&gt;New&lt;/span&gt; TreeNode(f.Name &amp;amp; &lt;span style="color: #006080"&gt;" ("&lt;/span&gt; &amp;amp; f.UnreadMessages &amp;amp; &lt;span style="color: #006080"&gt;"/"&lt;/span&gt; &amp;amp; f.TotalMessages &amp;amp; &lt;span style="color: #006080"&gt;")"&lt;/span&gt;, f.EntryID)

        &lt;span style="color: #008000"&gt;' expand and select the inbox&lt;/span&gt;
        subNode.Selected = (f.Name = &lt;span style="color: #006080"&gt;"Inbox"&lt;/span&gt;)
        subNode.Expanded = subNode.Selected
        node.ChildNodes.Add(subNode)

        &lt;span style="color: #008000"&gt;' load the subfolders&lt;/span&gt;
        &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Not&lt;/span&gt; f.Folders &lt;span style="color: #0000ff"&gt;Is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
            LoadNode(f.Folders, subNode)
        &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Next&lt;/span&gt; f
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt; GetMessages() &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email)
    &lt;span style="color: #008000"&gt;' get a group of messages based on the current page number and size&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.WHSMailService.GetMessages(_folderEntryID, GridView1.PageSize, _pageNum)
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Function&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; BindMessages(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email))
    &lt;span style="color: #008000"&gt;' load the grid&lt;/span&gt;
    GridView1.DataSource = list
    GridView1.DataBind()

    &lt;span style="color: #008000"&gt;' save off the new page number&lt;/span&gt;
    ViewState(&lt;span style="color: #006080"&gt;"PageNum"&lt;/span&gt;) = _pageNum
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the &lt;strong&gt;tvFolders&lt;/strong&gt; tree-view has not been filled in, we call our host service's &lt;strong&gt;GetFolders&lt;/strong&gt; method from the &lt;strong&gt;WHSMailService&lt;/strong&gt; property as defined above.&amp;nbsp; The method then enumerates through the hierarchical list of folders returned, building the same tree structure that exists in Outlook.&amp;nbsp; The &lt;strong&gt;Text&lt;/strong&gt; property of each &lt;strong&gt;TreeNode&lt;/strong&gt; is set to the folder name with a count of messages unread and total count of messages.&amp;nbsp; The &lt;strong&gt;Value&lt;/strong&gt; property of the node is set to the unique MAPI-defined &lt;strong&gt;EntryID&lt;/strong&gt; so that we can later grab that value to return the list of messages from that specific folder.&lt;/p&gt;
&lt;p&gt;Next, we call our service's &lt;strong&gt;GetMessages&lt;/strong&gt; method to return messages from the Inbox.&amp;nbsp; We pass in the value from the grid view's &lt;strong&gt;PageSize&lt;/strong&gt; property and a member variable named &lt;strong&gt;_pageNum&lt;/strong&gt;.&amp;nbsp; This will handle our paging scheme as we discussed earlier.&amp;nbsp; Once that list&amp;nbsp;of messages is returned, is it bound to the data grid for display.&lt;/p&gt;
&lt;p&gt;Finally, the default page number and folder entry ID (0 and "" respectively) are stored in the &lt;strong&gt;ViewState&lt;/strong&gt; so they can be assigned back to our member variables on each page request.&lt;/p&gt;
&lt;p&gt;If you were to run the application right now, you would see the same page that you do above, minus the message text at the bottom.&lt;/p&gt;
&lt;p&gt;Next, we will implement what occurs when a user clicks on a folder in the tree view.&amp;nbsp; We simply pull out the MAPI unique &lt;strong&gt;EntryID&lt;/strong&gt; which is stored in the &lt;strong&gt;Value&lt;/strong&gt; field of the selected node, assign it to the local member variable and view state, and then call the &lt;strong&gt;GetMessages&lt;/strong&gt; method from our service to return a list of messages from that folder, just as we did with the inbox above.&amp;nbsp; The code below shows the process:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; tvFolders_SelectedNodeChanged(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// new folder, so reset the view&lt;/span&gt;
    _pageNum = 0;
    _folderEntryID = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.tvFolders.SelectedNode.Value;
    ViewState[&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;] = _folderEntryID;

    List&amp;lt;Email&amp;gt; list = GetMessages();
    BindMessages(list);
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; tvFolders_SelectedNodeChanged(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
    &lt;span style="color: #008000"&gt;' new folder, so reset the view&lt;/span&gt;
    _pageNum = 0
    _folderEntryID = &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.tvFolders.SelectedNode.Value
    ViewState(&lt;span style="color: #006080"&gt;"FolderID"&lt;/span&gt;) = _folderEntryID

    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) = GetMessages()
    BindMessages(list)
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we can implement the Next/Back link buttons.&amp;nbsp; These methods simply increment or decrement the current page number, assign it to the view state for use on the next request, and then, just as before, gets the list of messages specific to the currently selected folder, using the unique ID stored in the view state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; btnPrev_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// first page&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(_pageNum &amp;gt; 0)
        _pageNum--;

    List&amp;lt;Email&amp;gt; list = GetMessages();
    BindMessages(list);
}

&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; btnNext_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span style="color: #008000"&gt;// next page&lt;/span&gt;
    _pageNum++;
    List&amp;lt;Email&amp;gt; list = GetMessages();

    &lt;span style="color: #008000"&gt;// if we're out of messages, go back to the previous page&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(list == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; || list.Count == 0)
    {
        _pageNum--;
        list = GetMessages();
    }
    BindMessages(list);
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; btnPrev_Click(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
    &lt;span style="color: #008000"&gt;' first page&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; _pageNum &amp;gt; 0 &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
        _pageNum -= 1
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;

    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) = GetMessages()
    BindMessages(list)
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;

&lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; btnNext_Click(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)
    &lt;span style="color: #008000"&gt;' next page&lt;/span&gt;
    _pageNum += 1
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; List(Of Email) = GetMessages()

    &lt;span style="color: #008000"&gt;' if we're out of messages, go back to the previous page&lt;/span&gt;
    &lt;span style="color: #0000ff"&gt;If&lt;/span&gt; list &lt;span style="color: #0000ff"&gt;Is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Nothing&lt;/span&gt; &lt;span style="color: #0000ff"&gt;OrElse&lt;/span&gt; list.Count = 0 &lt;span style="color: #0000ff"&gt;Then&lt;/span&gt;
        _pageNum -= 1
        list = GetMessages()
    &lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;If&lt;/span&gt;
    BindMessages(list)
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally, we need to implement what happens when the user selects a message from the top pane.&amp;nbsp; If you look at the HTML for the &lt;strong&gt;Default&lt;/strong&gt; page, you will see that the Subject field is bound to a &lt;strong&gt;LinkButton&lt;/strong&gt; control in the grid view via a &lt;strong&gt;TemplateField&lt;/strong&gt; (the rest of the fields are standard &lt;strong&gt;BoundField&lt;/strong&gt;s.&amp;nbsp; The &lt;strong&gt;LinkButton&lt;/strong&gt; sets the &lt;strong&gt;CommandArgument&lt;/strong&gt; property to the unique &lt;strong&gt;EntryID&lt;/strong&gt; of that message as defined by MAPI.&amp;nbsp; So, all we need to do is listen on the server for the &lt;strong&gt;LinkButton&lt;/strong&gt;'s &lt;strong&gt;Command&lt;/strong&gt; event, grab the unique ID and call our service's&amp;nbsp;&lt;strong&gt;GetMessage&lt;/strong&gt; method&amp;nbsp;with that ID to return the message itself.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; btnLink_Command(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, CommandEventArgs e)
{
    Email email = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.WHSMailService.GetMessage(e.CommandArgument.ToString());

    &lt;span style="color: #008000"&gt;// fill out the header with some basic info&lt;/span&gt;
    lblFrom.Text = email.FromName + &lt;span style="color: #006080"&gt;"&amp;amp;nbsp;("&lt;/span&gt; + email.From + &lt;span style="color: #006080"&gt;")"&lt;/span&gt;;
    lblSubject.Text = email.Subject;
    lblReceived.Text = email.Received.ToString();

    &lt;span style="color: #008000"&gt;// when a message is selected, write out the content&lt;/span&gt;
    msgContent.InnerHtml = email.Body;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VB&lt;/strong&gt;&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;Protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt; btnLink_Command(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; CommandEventArgs)
    &lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; email &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; Email = &lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.WHSMailService.GetMessage(e.CommandArgument.ToString())

    &lt;span style="color: #008000"&gt;' fill out the header with some basic info&lt;/span&gt;
    lblFrom.Text = email.FromName &amp;amp; &lt;span style="color: #006080"&gt;"&amp;amp;nbsp;("&lt;/span&gt; &amp;amp; email.From &amp;amp; &lt;span style="color: #006080"&gt;")"&lt;/span&gt;
    lblSubject.Text = email.Subject
    lblReceived.Text = email.Received.ToString()

    &lt;span style="color: #008000"&gt;' when a message is selected, write out the content&lt;/span&gt;
    msgContent.InnerHtml = email.Body
&lt;span style="color: #0000ff"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;Email&lt;/strong&gt; entity is retrieved, its properties are set to the labels in the header, and the message content is assigned to the &lt;strong&gt;InnerHtml&lt;/strong&gt; property of the content holding &lt;strong&gt;&amp;lt;DIV&amp;gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Voila!&amp;nbsp; A very simple mail reader.&lt;/p&gt;
&lt;p&gt;That's it for code.&amp;nbsp; Now we need to deploy the applications and configure Windows Home Server.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;WHSMailHost&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;If you are deploying to a machine that is not your development machine, install the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en" target="_blank"&gt;.NET Framework 3.0 runtime&lt;/a&gt; on the machine to which you will be running the host service.&amp;nbsp; Then, copy the &lt;strong&gt;WHSMailHost.exe&lt;/strong&gt;, &lt;strong&gt;WHSMailHost.exe.config&lt;/strong&gt;, and &lt;strong&gt;WHSMailCommon.dll&lt;/strong&gt;&amp;nbsp;files to the machine running Outlook that will be connected to by the web application.&amp;nbsp;&amp;nbsp;You may want to create a shortcut in the Startup group so it will launch when you log into Windows.&lt;/p&gt;
&lt;p&gt;Next, open Outlook and select &lt;strong&gt;Trust Center&lt;/strong&gt; from the &lt;strong&gt;Tools&lt;/strong&gt; menu.&amp;nbsp; Choose &lt;strong&gt;Programmatic Access&lt;/strong&gt; and set&amp;nbsp;the option to &lt;strong&gt;Never warn me about suspicious activity&lt;/strong&gt;.&amp;nbsp; Unfortunately this must be disabled, otherwise Outlook will prompt you every time the host process attempts to retrieve any data.&amp;nbsp; There is no way to bypass this on an application-by-application basis, so we have to turn it off for all applications.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/trustcenter_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="266" alt="trustcenter" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/trustcenter_thumb_3.png" width="490" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;If you are running firewall software on the PC, ensure that port 12345 will allow traffic to pass through.&amp;nbsp; You may also change port 12345 to a different port, but you must change it in the configuration files for both applications.&lt;/p&gt;
&lt;p&gt;Finally, note that Outlook does not need to remain open to use this application. You do, however,&amp;nbsp;need to be logged into the machine&amp;nbsp;with the host running.&lt;/p&gt;
&lt;h4&gt;WHSMailWeb&lt;/h4&gt;
&lt;p&gt;On your Windows Home Server machine, install the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en" target="_blank"&gt;.NET Framework 3.0 Runtime&lt;/a&gt;.&amp;nbsp; This is needed to use WCF.&amp;nbsp; Next, create a new directory named &lt;strong&gt;mail&lt;/strong&gt; (or anything you wish, but it is assumed it is named mail) in the &lt;strong&gt;c:\inetpub&lt;/strong&gt; directory.&amp;nbsp; Copy all .aspx pages, web.config, icon.png and the bin directory to the &lt;strong&gt;mail&lt;/strong&gt; directory.&amp;nbsp; You could also share out the &lt;strong&gt;mail&lt;/strong&gt; directory and use Visual Studio's &lt;strong&gt;Publish&lt;/strong&gt; command to automatically copy the files to that share.&amp;nbsp; Then, open the &lt;strong&gt;Internet Information Services (IIS) Manager&lt;/strong&gt; application from the &lt;strong&gt;Administrative Tools&lt;/strong&gt; group on the Start menu.&amp;nbsp; Open &lt;strong&gt;Web Sites&lt;/strong&gt; and then&amp;nbsp;&lt;strong&gt;Default Web Site&lt;/strong&gt; in the left pane.&amp;nbsp; Right-click on &lt;strong&gt;Default Web Site&lt;/strong&gt; and select &lt;strong&gt;New&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Virtual Directory...&lt;/strong&gt; from the context menu.&amp;nbsp; When prompted, use the following values:&lt;/p&gt;
&lt;table cellspacing="0" cellpadding="2" width="223" border="1" unselectable="on"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top" width="93"&gt;&lt;strong&gt;Alias&lt;/strong&gt;&lt;/td&gt;
&lt;td valign="top" width="128"&gt;mail&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="95"&gt;&lt;strong&gt;Path&lt;/strong&gt;&lt;/td&gt;
&lt;td valign="top" width="128"&gt;c:\inetpub\mail&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="97"&gt;&lt;strong&gt;Permissions&lt;/strong&gt;&lt;/td&gt;
&lt;td valign="top" width="128"&gt;Read, Run Scripts&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The next part is a bit tricky.&amp;nbsp; We want to integrate with the security already provided by Windows Home Server.&amp;nbsp; The WHS &lt;strong&gt;remote&lt;/strong&gt; website uses Forms security from ASP.NET.&amp;nbsp; Ideally, you should be able to log into the main page of the WHS remote website and then open the webmail link without having to log in again.&amp;nbsp; Additionally, if the &lt;strong&gt;mail&lt;/strong&gt; URL is used directly, you should be prompted for your login credentials.&lt;/p&gt;
&lt;p&gt;To achieve this, open the &lt;strong&gt;web.config&lt;/strong&gt; file from &lt;strong&gt;c:\inetpub\remote &lt;/strong&gt;in Notepad.&amp;nbsp; In the XML, between the start and end &lt;strong&gt;&amp;lt;system.web&amp;gt;&lt;/strong&gt; tags you will find the configuration for the Forms-based authentication used by WHS.&amp;nbsp; In order to use the cookie that is created by this authentication method, we need to have the same key values in our web.config file.&amp;nbsp; The easiest way to achieve this is to copy all of the the text&amp;nbsp;between the two &lt;strong&gt;&amp;lt;system.web&amp;gt;&lt;/strong&gt; tags.&amp;nbsp; Next, open the web.config file from the &lt;strong&gt;mail&lt;/strong&gt; directory that you just copied over and&amp;nbsp;paste the text&amp;nbsp;between the two lines informing you to do so.&amp;nbsp; Finally, we need to update the &lt;strong&gt;loginUrl&lt;/strong&gt; and &lt;strong&gt;defaultRedirect&lt;/strong&gt; paths in the &lt;strong&gt;forms&lt;/strong&gt; and &lt;strong&gt;customErrors&lt;/strong&gt; keys.&amp;nbsp; Add &lt;strong&gt;/remote/&lt;/strong&gt; to the beginning of each to make them &lt;strong&gt;/remote/login.aspx&lt;/strong&gt; and &lt;strong&gt;/remote/error.aspx&lt;/strong&gt;.&amp;nbsp; Be sure that the &lt;strong&gt;SERVERNAME&lt;/strong&gt; item in the endpoint configuration is updated to the name/IP address of the machine running the host process.&lt;/p&gt;
&lt;p&gt;With the files copied and edited, ensure that permissions on the file are propagated from the root &lt;strong&gt;mail&lt;/strong&gt; directory to the files inside.&lt;/p&gt;
&lt;p&gt;Finally, open the &lt;strong&gt;websites.xml&lt;/strong&gt; file in the &lt;strong&gt;/remote&lt;/strong&gt; directory and add the following XML before the end &lt;strong&gt;&amp;lt;/WebSites&amp;gt;&lt;/strong&gt; tag:&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;WebSite&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Outlook Webmail"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;uri&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="/mail"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;imageUrl&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="/mail/icon.png"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;absolute&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="false"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;WebSite&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the configuration done, we need to enable web site connectivity in WHS.&amp;nbsp; Double-click the Windows Home Server Console icon on the desktop.&amp;nbsp; When it loads, click the &lt;strong&gt;Settings&lt;/strong&gt; button in the top right corner.&amp;nbsp; When the &lt;strong&gt;Settings&lt;/strong&gt; dialog appears, select &lt;strong&gt;Remote Access&lt;/strong&gt; in the left pane and then click the &lt;strong&gt;Turn On&lt;/strong&gt; button in the right pane, assuming web site connectivity is off.&amp;nbsp; If it already enabled, skip this step.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/whssettings_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="353" alt="whssettings" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/whssettings_thumb_3.png" width="490" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;With all that done, create a user account for yourself in WHS so that you can login remotely.&amp;nbsp; That's it!&lt;/p&gt;
&lt;h3&gt;Running the Application&lt;/h3&gt;
&lt;p&gt;Ensure the &lt;strong&gt;WHSMailHost&lt;/strong&gt; application is running on the PC with Outlook installed.&amp;nbsp; Then, browse to your Windows Home Server's default website.&amp;nbsp; After logging in, you should see a link on the right side of the screen named &lt;strong&gt;Outlook Webmail&lt;/strong&gt;.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/web_3.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="239" alt="web" src="http://www.coding4fun.net/images/OutlookWebmailAddinforWindowsHomeServer_B4D/web_thumb_3.png" width="490" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Click that to start our application and if everything is working, you should see the web page as shown above.&lt;/p&gt;
&lt;h3&gt;Troubleshooting&lt;/h3&gt;
&lt;p&gt;If the web page displays an error message, open the &lt;strong&gt;web.config&lt;/strong&gt; file in the &lt;strong&gt;mail&lt;/strong&gt; directory on your Windows Home Server.&amp;nbsp; Look for the &lt;strong&gt;&amp;lt;customErrors&amp;gt;&lt;/strong&gt; tag and change the &lt;strong&gt;mode&lt;/strong&gt; parameter to &lt;strong&gt;Off&lt;/strong&gt;.&amp;nbsp; This should allow you to see the actual error that is occurring and provide more information as to the status of the application.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Phew!&amp;nbsp; Two applications and one shared assembly later, we have a web-based add-in for Windows Home Server that allows one to remotely access their Outlook message store.&amp;nbsp; Currently the application is read-only and provides only minimal functionality.&amp;nbsp; It's a great starting point to create a full-fledged webmail client interface.&amp;nbsp; The project is hosted on CodePlex so I'm hoping to see you readers implement additional features and functionality that you find useful.&lt;/p&gt;
&lt;h3&gt;Additional Information&lt;/h3&gt;
&lt;p&gt;Here are a few links with additional information on the items discussed here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/bb425866.aspx" target="_blank"&gt;Windows Home Server SDK Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/netframework/aa663324.aspx" target="_blank"&gt;Windows Communication Foundation (WCF) Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/bb187379.aspx" target="_blank"&gt;Outlook 2007 Primary Interop Assembly Reference&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;Bio&lt;/h3&gt;
&lt;p&gt;Brian is a Microsoft C# MVP and a recognized .NET expert with over 6 years experience developing .NET solutions, and over 9 years of professional experience architecting and developing solutions using Microsoft technologies and platforms, although he has been "coding for fun" for as long as he can remember.&amp;nbsp; Outside the world of .NET and&amp;nbsp;business applications, Brian enjoys developing&amp;nbsp;both hardware and software projects in the areas of gaming, robotics, and&amp;nbsp;whatever else strikes his fancy for the next ten minutes.&amp;nbsp;He rarely passes up an opportunity to dive into a C/C++&amp;nbsp;or assembly language project.&amp;nbsp; You can reach Brian via his blog at &lt;a href="http://www.brianpeek.com/"&gt;http://www.brianpeek.com/&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4320362" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web+services/default.aspx">web services</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web+miscellaneous/default.aspx">web miscellaneous</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows+miscellaneous/default.aspx">windows miscellaneous</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/web/default.aspx">web</category></item><item><title>Collecting Outlook 2007 Statistics Using VSTO 2005 SE</title><link>http://blogs.msdn.com/coding4fun/archive/2006/11/20/1111248.aspx</link><pubDate>Tue, 21 Nov 2006 01:08:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1111248</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/1111248.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=1111248</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=1111248</wfw:comment><description>&lt;SPAN id=c4fmetadata&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=1 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR class=entry_overview&gt;
&lt;TD class="" width=50&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;SPAN class=entry_description&gt;This article demonstrates how you can create an Outlook add-in using &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5012A573-0D84-4E39-983C-CA22F2107B07&amp;amp;displaylang=en"&gt;VSTO 2005 SE&lt;/A&gt; to listen to outlook events, store data about outlook usage, and produce reports on that usage in a custom form and a form region.&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" colSpan=2&gt;
&lt;DIV class=entry_author&gt;Kevin Marshall, Clarity Consulting, Inc.&lt;/DIV&gt;
&lt;DIV class=entry_company&gt;&lt;A href="http://blogs.claritycon.com/blogs/kevin_marshall/default.aspx"&gt;Clarity Blogs&lt;/A&gt;&lt;/DIV&gt;&lt;BR&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Difficulty: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Intermediate&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Time Required:&lt;/B&gt; &lt;SPAN class=entry_details_input&gt;1-3 hours&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Cost: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Free&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Software: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;&lt;A href="http://office.microsoft.com/en-us/products/default.aspx"&gt;Office 2007&lt;/A&gt; &lt;A href="http://msdn.microsoft.com/vstudio/express/"&gt;Visual Studio Express&lt;/A&gt; &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5012A573-0D84-4E39-983C-CA22F2107B07&amp;amp;displaylang=en"&gt;VSTO 2005 SE&lt;/A&gt; &lt;A href="http://msdn2.microsoft.com/en-us/library/ms788695.aspx"&gt;Outlook Add-in Templates&lt;/A&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Hardware: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Download: &lt;/B&gt;&lt;A href="http://channel9.msdn.com/ShowPost.aspx?PostID=259129#259129"&gt;Download&lt;/A&gt; 
&lt;UL&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;
&lt;P&gt;Outlook is used by many people everyday, but few people probably realize the wealth of data that can be learned from how they use Outlook. How long does it take you to respond to emails on average? How many hours do you spend in meetings per week? Using Visual Studio Tools for Office Second Edition (VSTO 2005 SE) and Office 2007, you can easily find the answers to these questions and more by building an add-in for Outlook. This article demonstrates how you can listen to outlook events, store data about outlook usage, and produce reports on that usage in a custom form and new to VSTO 2005 SE, a form region.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image011.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image011.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=240 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb3.png" width=317 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb3.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;What is VSTO 2005 SE?&lt;/H3&gt;
&lt;P&gt;VSTO 2005 SE is a free add-on to Visual Studio 2005 that enables developers to build applications targeting the 2007 Office system. Developers can create Office-based solutions using the professional development environment of Visual Studio 2005 and the new programming model features of Office 2007 like the ribbon bar and custom form regions. 
&lt;H3&gt;Creating an Outlook Add-in Project&lt;/H3&gt;
&lt;P&gt;After installing VSTO 2005 SE and the Outlook Add-in template, you can begin creating an Outlook 2007 add-in. Create a new project, then select Office Outlook 2007 Add-in from the My Templates group and click OK. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image012.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image012.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=184 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb4.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb4.png"&gt;&lt;/A&gt; 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The newly created project will have several files. Connect.cs is the main file which contains two methods, &lt;B&gt;InitializeAddin&lt;/B&gt; and &lt;B&gt;ShutdownAddin&lt;/B&gt; which provide you a starting point for interfacing with Outlook. 
&lt;H3&gt;Initializing the Add-in&lt;/H3&gt;
&lt;P&gt;The InitializeAddin method is called whenever your add-in is loaded into memory. For our add-in, we will do three things during start up: 
&lt;UL&gt;
&lt;LI&gt;Create an instance of our EventTracker class. This is the main class that handles all of the logic for processing incoming appointment and mail items. 
&lt;LI&gt;Load existing Outlook data via the EventTracker. 
&lt;LI&gt;Add a menu item to the Outlook toolbar. The menu item is used to pop up the report window.&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;Visual C#&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; InitalizeAddin()
{
   &lt;SPAN class=rem&gt;//Initialize report menu item&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.InitializeMenu();

   &lt;SPAN class=rem&gt;// Initialize the event tracker object.&lt;/SPAN&gt;
   _eventTracker = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; EventTracker(&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.Application);

   ListenToEvents(&lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;);

   _eventTracker.LoadData();
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; InitalizeAddin()

    &lt;SPAN class=rem&gt;'//Initialize report menu item&lt;/SPAN&gt;
   InitializeMenu()

    &lt;SPAN class=rem&gt;'// Initialize the event tracker object.&lt;/SPAN&gt;
   _eventTracker = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; EventTracker(&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.Application)

    ListenToEvents(&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)

   _eventTracker.LoadData()
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;Top-level menu items can be created the same way in office application. For this add-in, we’ll create a new menu “Reports”, with a single menu item to launch the report popup window. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image013.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image013.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=54 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb5.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb5.png"&gt;&lt;/A&gt; 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;// Get the Outlook menu bar.&lt;/SPAN&gt;
_menuBar = &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.Application.ActiveExplorer().CommandBars.ActiveMenuBar;

&lt;SPAN class=rem&gt;// Get the index of the Help menu item on the Outlook menu bar.&lt;/SPAN&gt;
_helpMenuIndex = _menuBar.Controls[_MENU_BEFORE].Index;
&lt;SPAN class=rem&gt;// Add the top-level menu right before the Help menu.&lt;/SPAN&gt;
_topMenu = &lt;/PRE&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;(Office.CommandBarPopup)_menuBar.Controls.Add(Office.MsoControlType.msoControlPopup,
   Type.Missing, Type.Missing, _helpMenuIndex, &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;);&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;_topMenu.Caption = &lt;SPAN class=str&gt;"Reports"&lt;/SPAN&gt;;
_topMenu.Visible = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;

&lt;SPAN class=rem&gt;// Add the menu item for loading email reports.&lt;/SPAN&gt;
_reports = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   (Office.CommandBarButton)_topMenu.Controls.Add(Office.MsoControlType.msoControlButton, &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   Type.Missing, Type.Missing, Type.Missing, t&lt;SPAN class=kwrd&gt;rue&lt;/SPAN&gt;);                                                                                   Type.Missing,                                                                                 Type.Missing,                                                                                   Type.Missing,                                                                                    &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;);

_reports.Caption = &lt;SPAN class=str&gt;"Calendar / Email Reports"&lt;/SPAN&gt;;
_reports.Visible = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt; &lt;SPAN class=rem&gt;'// Get the Outlook menu bar.&lt;/SPAN&gt;
 _menuBar = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.Application.ActiveExplorer().CommandBars.ActiveMenuBar

 &lt;SPAN class=rem&gt;'// Get the index of the Help menu item on the Outlook menu bar.&lt;/SPAN&gt;
_helpMenuIndex = _menuBar.Controls(_MENU_BEFORE).Index

 &lt;SPAN class=rem&gt;'// Add the top-level menu right before the Help menu.&lt;/SPAN&gt;
_topMenu = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;   CType&lt;/SPAN&gt;(_menuBar.Controls.Add(Office.MsoControlType.msoControlPopup, _
      Type.Missing, Type.Missing, _helpMenuIndex, &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;), Office.CommandBarPopup)&lt;/PRE&gt;&lt;PRE class=csharpcode&gt; _topMenu.Caption = &lt;SPAN class=str&gt;"Reports"&lt;/SPAN&gt;
 _topMenu.Visible = &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;

 &lt;SPAN class=rem&gt;' Add the menu item for loading email reports.&lt;/SPAN&gt;
_reports = _topMenu.Controls.Add(Office.MsoControlType.msoControlButton, _
         Type.Missing, Type.Missing, Type.Missing, &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)
 _reports.Caption = &lt;SPAN class=str&gt;"Calendar / Email Reports"&lt;/SPAN&gt;
 _reports.Visible = &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;H3&gt;Loading Statistics Based on Existing Outlook Data&lt;/H3&gt;
&lt;P&gt;Data to produce reports on Outlook usage is stored in a SQL Express database. When the add-in first loads, it needs to scan the mail and calendar folders to gather statistics on existing items. The EventTracker class handles the initial data load, as well as hooking events fired when new items are added to those folders. 
&lt;P&gt;The schema for the database has tables for storing information about the three types of items we are reporting statistics: inbox items, sent mail items, and appointment items. &lt;PRE class=csharpcode&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image01.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image01.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=141 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0.png" width=240 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0.png"&gt;&lt;/A&gt; &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;Since scanning through the folders can take some time if you are like me and keep every email ever received, it’s best to start the initial data load on a separate thread. Now Outlook can continue responding to user input, while the add-in does its work. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; LoadData()
{
   &lt;SPAN class=rem&gt;//create new thread for large inboxes&lt;/SPAN&gt;
   Thread thread = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread(&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ThreadStart(CheckInitialLoad));
   thread.IsBackground = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
   thread.Start();
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; LoadData()
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; thread &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Thread = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; Thread(&lt;SPAN class=kwrd&gt;AddressOf&lt;/SPAN&gt; CheckInitialLoad)
   thread.IsBackground = &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;
   thread.Start()
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;The initial data load raises an to notify other code, like the report popup form, that the data isn’t ready to produce reports yet. If the database doesn’t contain any exisitng data, then the data load will add records for each exisiting item. Allowing the thread to sleep briefly between iterations prevents the data load from interfering with the responsiveness of the main Outlook thread. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; CheckInitialLoad()
{
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;.Equals(StartDataLoad,&lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;))
   {
      StartDataLoad(&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;);
   }

ReportDBDataSetTableAdapters.SentMailTableAdapter sentItemTA = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ReportDBDataSetTableAdapters.SentMailTableAdapter();
ReportDBDataSetTableAdapters.InboxTableAdapter inboxTA = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter();
ReportDBDataSetTableAdapters.CalendarTableAdapter calTA = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ReportDBDataSetTableAdapters.CalendarTableAdapter();

   &lt;SPAN class=rem&gt;//check to see if calendar stats have been loaded&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (calTA.GetData().Rows.Count == 0)
   {
      &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; _calendarItems)
      {
         &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (item &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; Outlook.AppointmentItem)
         {
            AddCalendarItem(item &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; Outlook.AppointmentItem);
         }
         Thread.Sleep(10);
      }
   }
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;.Equals(StopDataLoad, &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;))
   {
      StopDataLoad(&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;);
   }
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt; &lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; CheckInitialLoad()

   &lt;SPAN class=kwrd&gt;RaiseEvent&lt;/SPAN&gt; StartDataLoad(&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;)

   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; sentItemTA &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; ReportDBDataSetTableAdapters.SentMailTableAdapter = _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      &lt;SPAN class=kwrd&gt;New&lt;FONT color=#000000&gt; &lt;/FONT&gt;&lt;/SPAN&gt;ReportDBDataSetTableAdapters.SentMailTableAdapter
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; inboxTA &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter = _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      &lt;SPAN class=kwrd&gt;New &lt;/SPAN&gt;ReportDBDataSetTableAdapters.InboxTableAdapter
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; calTA &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; ReportDBDataSetTableAdapters.CalendarTableAdapter = _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      &lt;SPAN class=kwrd&gt;New&lt;FONT color=#000000&gt; &lt;/FONT&gt;&lt;/SPAN&gt;ReportDBDataSetTableAdapters.CalendarTableAdapter

   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; calTA.GetData.Rows.Count = 0 &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; _calendarItems
         &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;TypeOf&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; Outlook.AppointmentItem &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
            AddCalendarItem(&lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(item, Outlook.AppointmentItem))
         &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
         Thread.Sleep(10)
      &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; inboxTA.GetData.Rows.Count = 0 &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
       &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; _inboxItems
          &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;TypeOf&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; Outlook.MailItem &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
             AddInboxItem(&lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(item, Outlook.MailItem))
          &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
          Thread.Sleep(10)
        &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; sentItemTA.GetData.Rows.Count = 0 &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
       &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; _sentMailItems
          &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;TypeOf&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; Outlook.MailItem &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
             AddSentMailItem(&lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(item, Outlook.MailItem))
          &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
      Thread.Sleep(10)
      &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;

   &lt;SPAN class=kwrd&gt;RaiseEvent&lt;/SPAN&gt; StopDataLoad(&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;)

&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;By listening to the StartDataLoad and StopDataLoad events, we can display a message to the user if they try to load a report. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (_isDataLoading)
{
MessageBox.Show(&lt;SPAN class=str&gt;"Outlook is currently initializing your folders to &lt;/SPAN&gt;&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=str&gt;   enable reporting for the first time.  Try again in a few minutes."&lt;/SPAN&gt;, 
   &lt;SPAN class=str&gt;"Loading initial data"&lt;/SPAN&gt;, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; (_isDataLoading) &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;

MessageBox.Show(&lt;SPAN class=str&gt;"Outlook is currently initializing your folders to enable reporting for the first time.  Try again in a few minutes."&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"Loading initial data"&lt;/SPAN&gt;, MessageBoxButtons.OK, MessageBoxIcon.Warning)&lt;/PRE&gt;
&lt;P&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;
&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;H3&gt;Listening for New Items&lt;/H3&gt;
&lt;P&gt;After the initial data load, the add-in can just listen for incoming items to keep track of Outlook usage. To listen for incoming items, you can use folder events. To hook into folder events you first need to obtain a reference to an Outlook.MAPIFolder object that encapsulates an Outlook folder like Inbox, Sent Mail, or Calendar. In order to get the default Outbox folder call the GetDefaultFolder method of the MAPI namespace object. Then you need to add handlers for the ItemAdd event of the Outlook folders. The following code shows how to listen for incoming mail items in the Inbox folder. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;// Obtain references to the folder objects that fire the events we are interested in.&lt;/SPAN&gt;
Outlook.MAPIFolder inbox = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   app.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
&lt;SPAN class=rem&gt;// Store references to the item collection objects.&lt;/SPAN&gt;
_inboxItems = inbox.Items;
_inboxItems.ItemAdd += &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Outlook.ItemsEvents_ItemAddEventHandler(InboxFolderItemAdded)
&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// Handles new mail items added to the inbox&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// &amp;lt;param name="Item"&amp;gt;Reference to the Outlook object added&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; InboxFolderItemAdded(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; Item)
{
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (Item &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; Outlook.MailItem)
   {
      AddInboxItem(Item &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; Outlook.MailItem);
   }
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; inbox &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Outlook.MAPIFolder = _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   app.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
_inboxItems = inbox.Items
&lt;SPAN class=kwrd&gt;AddHandler&lt;/SPAN&gt; _inboxItems.ItemAdd, &lt;SPAN class=kwrd&gt;AddressOf&lt;/SPAN&gt; InboxFolderItemAdded&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; InboxFolderItemAdded(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; Item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;)
   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;TypeOf&lt;/SPAN&gt; Item &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; Outlook.MailItem &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      AddInboxItem(&lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(Item, Outlook.MailItem))
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;Appointments and sent mail items can be tracked in a similar manner. Additionally, the Outlook folders support events for removing or changing items. 
&lt;P&gt;Items can easily be stored in the database by using table adapters automatically generated from the dataset. Each item has a table adapter which corresponds to a table in the database. 
&lt;P&gt;Visual C#&lt;/P&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// Stores a new message in the database&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;/// &amp;lt;param name="mailItem"&amp;gt;&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; AddInboxItem(Outlook.MailItem mailItem)
{
ReportDBDataSetTableAdapters.InboxTableAdapter ta = &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter();

   &lt;SPAN class=rem&gt;//determine if mail was sent to an alias or group address&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; isAliased = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (mailItem.To == mailItem.ReceivedOnBehalfOfName || mailItem.CC == mailItem.ReceivedOnBehalfOfName)
   {
      isAliased = &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;
   }
   &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
   {
      ta.Insert(mailItem.SenderName, &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      mailItem.SenderName, mailItem.SentOn, isAliased, &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;, &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      mailItem.Subject, mailItem.EntryID);
   }
   &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (Exception ex)
   {
      System.Diagnostics.Debug.Write(ex);
   }
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;&lt;BR&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; AddInboxItem(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; mailItem &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Outlook.MailItem)
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; ta &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; isAliased &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Boolean&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; mailItem.&lt;SPAN class=kwrd&gt;To&lt;/SPAN&gt; = mailItem.ReceivedOnBehalfOfName &lt;SPAN class=kwrd&gt;OrElse&lt;/SPAN&gt; mailItem.CC = mailItem.ReceivedOnBehalfOfName &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
                isAliased = &lt;SPAN class=kwrd&gt;False&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
      ta.Insert(mailItem.SenderName, mailItem.SenderName, mailItem.SentOn, isAliased, &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;, mailItem.Subject, mailItem.EntryID)
   &lt;SPAN class=kwrd&gt;Catch&lt;/SPAN&gt; ex &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Exception
      System.Diagnostics.Debug.Write(ex)
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;H3&gt;Producing the Reports&lt;/H3&gt;
&lt;P&gt;Now that we a have some data points about our Outlook usage, we can produce reports. The reports are displayed in a datagrid on a form that is launched from the Reports menu. The report popup dialog contains a selector for various report types and a selectable date range. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image019.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image019.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=185 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb7.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb7.png"&gt;&lt;/A&gt; 
&lt;P&gt;Each report is populated using a method from our table adapters. For example, to get a count of emails sent over a given period, you can use the following code: 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.inboxTableAdapter.CountEmailsRecieved(&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.reportDBDataSet.Inbox, fromDate, toDate);
&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.dataGridView1.Columns.Add(&lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"Emails Received"&lt;/SPAN&gt;);
&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.dataGridView1.Columns[&lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;].DataPropertyName = &lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;;
&lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.reportDBDataSetBindingSource.DataSource = &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.reportDBDataSet.Inbox;&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.InboxTableAdapter.CountEmailsRecieved(&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.ReportDBDataSet.Inbox, fromDate, toDate)
&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.dataGridView1.Columns.Add(&lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"Emails Received"&lt;/SPAN&gt;)
&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.dataGridView1.Columns(&lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;).DataPropertyName = &lt;SPAN class=str&gt;"Emails Recieved"&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.reportDBDataSetBindingSource.DataSource = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.ReportDBDataSet.Inbox&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;H3&gt;Creating a Form Region&lt;/H3&gt;
&lt;P&gt;Another way you can display data about Outlook usage is a form region. Form regions can be added to any existing Outlook form. You can also control whether the region is shown in the preview pane, the inspector, or on new items. For this add-in, we’ll add a form region on email messages to show statistics about the recipient / sender. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image018.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image018.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=67 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb6.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb6.png"&gt;&lt;/A&gt; 
&lt;P&gt;The first step in creating a new form region is to customize an existing Outlook form. In Outlook, click Tools -&amp;gt; Forms -&amp;gt; Design a Form. Then select Message from the standard forms library. The Outlook form will appear in the design view. On the ribbon bar, select the button for creating a new form region. &lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image022.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image022.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=222 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb8.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb8.png"&gt;&lt;/A&gt; &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;On the form, add a new textbox control. You can’t use the regular Outlook textbox though. Right-click the Toolbox window and select Custom Controls. Scroll through the list of controls and select the Microsoft Office Outlook TextBox Control, and then click OK. &lt;PRE class=csharpcode&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image025.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image025.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=199 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb9.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb9.png"&gt;&lt;/A&gt; &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;Add the textbox to the form to display the Outlook statistics. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image028.png" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image028.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=116 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb10.png" width=320 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/image0_thumb10.png"&gt;&lt;/A&gt; 
&lt;P&gt;Now you can save the form region as an .ofs file and add it to the project as a resource file. In order to connect the form region with our add-in, we need to create a region manifest file and a registry entry. The region manifest is an xml file that defines how Outlook displays the region. &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN class=html&gt;xml&lt;/SPAN&gt; &lt;SPAN class=attr&gt;version&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="1.0"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;encoding&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="utf-8"&lt;/SPAN&gt; ?&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;FormRegion&lt;/SPAN&gt; &lt;SPAN class=attr&gt;xmlns&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://schemas.microsoft.com/office/12/outlook/formregion.xsd"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;OutlookStatsRegionCS&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;formRegionType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;adjoining&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;formRegionType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;Outlook Statistics&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;showInspectorRead&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;true&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;showInspectorRead&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;showReadingPane&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;true&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;showReadingPane&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;showInspectorCompose&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;false&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;showInspectorCompose&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;addin&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;OutlookStatsCS.Connect&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;addin&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;FormRegion&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;The documentation for the XML Schema for form regions is located &lt;A href="http://www.microsoft.com/downloads/details.aspx?familyid=15805380-f2c0-4b80-9ad1-2cb0c300aef9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?familyid=15805380-f2c0-4b80-9ad1-2cb0c300aef9&amp;amp;displaylang=en"&gt;here&lt;/A&gt;. Since the form for composing new mail item shouldn’t have usage statistics at the bottom, set the showInspectorCompose property to false. 
&lt;P&gt;To associate the region manifest with Outlook, you need to create a new registry key under HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\FormRegions\IPM.Note called OutlookStatsRegionCS. The value of the key should be the path to the region manifest XML file. A sample registry file is included in the project’s \Registry folder in the region_registry.reg file. 
&lt;H3&gt;Wiring the Region to the Outlook Add-in&lt;/H3&gt;
&lt;P&gt;Because form regions are based on the Microsoft Forms 2.0 types, you need to add a reference in the add-in project to Microsoft Forms 2.0 Object Library. Now you can add a new class to manage that form region, called OutlookStatsRegion.cs. 
&lt;P&gt;The constructor for this class needs a reference to the instance of the form region. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; OutlookStatsRegion(Outlook.FormRegion region)
{
   _region = region;
   _region.Close += &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Outlook.FormRegionEvents_CloseEventHandler(Region_Close);

   _form = region.Form &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; Forms.UserForm;

   _txtStats = (Outlook.OlkTextBox)_form.Controls.Item(&lt;SPAN class=str&gt;"txtStats"&lt;/SPAN&gt;);
   _txtStats.Text = GetEmailStatistics(region.Item);
}
&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; [region] &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Outlook.FormRegion)
   _region = [region]
   &lt;SPAN class=kwrd&gt;AddHandler&lt;/SPAN&gt; _region.Close, &lt;SPAN class=kwrd&gt;AddressOf&lt;/SPAN&gt; Region_Close

   _form = &lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;([region].Form, Forms.UserForm)

   _txtStats = &lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(_form.Controls.Item(&lt;SPAN class=str&gt;"txtStats"&lt;/SPAN&gt;), Outlook.OlkTextBox)
   _txtStats.Text = GetEmailStatistics([region].Item)
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; 'New&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;Using the reference to the region, we can get access to the mail item, and therefore the sender name and email address need to display the statistics. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; GetEmailStatistics(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; Item)
{
   &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; result = &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.Empty;

   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (Item &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; Outlook.MailItem)
   {
      Outlook.MailItem mailItem = Item &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; Outlook.MailItem;

ReportDBDataSetTableAdapters.InboxTableAdapter inboxTA = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter();

      &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;? countEmailsReceived = inboxTA.CountEmailsReceivedFrom(mailItem.SenderName);
                
      sb.Append(&lt;SPAN class=str&gt;"Emails received from "&lt;/SPAN&gt;);
      sb.Append(mailItem.SenderName);
      sb.Append(&lt;SPAN class=str&gt;": "&lt;/SPAN&gt;);
      sb.Append(countEmailsReceived.Value.ToString());
      sb.Append(&lt;SPAN class=str&gt;"  ["&lt;/SPAN&gt;);
      sb.Append(percentTotalReceived);
      sb.AppendLine(&lt;SPAN class=str&gt;"% of total received]"&lt;/SPAN&gt;);

      result = sb.ToString();
   }

   &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; result;
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt; GetEmailStatistics(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; Item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;) &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; result &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;.Empty

   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;TypeOf&lt;/SPAN&gt; Item &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; Outlook.MailItem &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; mailItem &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Outlook.MailItem = &lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(Item, Outlook.MailItem)
      &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; inboxTA &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; ReportDBDataSetTableAdapters.InboxTableAdapter()
      &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; inbox &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; ReportDBDataSet.InboxDataTable()
      &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; countEmailsReceived &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Nullable(Of &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt;) = _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;         inboxTA.CountEmailsReceivedFrom(mailItem.SenderName)

      sb.Append(&lt;SPAN class=str&gt;"Emails received from "&lt;/SPAN&gt;)
      sb.Append(mailItem.SenderName)
      sb.Append(&lt;SPAN class=str&gt;": "&lt;/SPAN&gt;)
      sb.Append(countEmailsReceived.Value.ToString())
      sb.Append(&lt;SPAN class=str&gt;"  ["&lt;/SPAN&gt;)
      sb.Append(percentTotalReceived)

      result = sb.ToString()
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;

    &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; result
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt; &lt;SPAN class=rem&gt;'GetEmailStatistics&lt;/SPAN&gt;
&lt;/PRE&gt;
&lt;P&gt;Almost there. Next we have to modify the Connect class to implement the form region interface. 
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;partial&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Connect : Outlook.FormRegionStartup&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;Partial &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Class&lt;/SPAN&gt; Connect
&lt;SPAN class=kwrd&gt;&lt;FONT color=#000000&gt;   &lt;/FONT&gt;Implements&lt;/SPAN&gt; Outlook.FormRegionStartup&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;The two methods defined in this interface are called as Outlook loads an item and prepares to show a form. When Outlook starts to load the user interface for a message class that has a form region registered, it first calls the &lt;B&gt;GetFormRegionStorage&lt;/B&gt; method to load the layout information for the form region. &lt;B&gt;GetFormRegionStorage&lt;/B&gt; should return either a string (which is the path to the .ofs file), an &lt;B&gt;IStorage&lt;/B&gt; instance for the contents of the .ofs file, or a byte array that contains the contents of the .ofs file. Before Outlook displays the form region to the user, it calls the &lt;B&gt;BeforeFormRegionShow&lt;/B&gt; method, and passes a reference to the form region object.&lt;/P&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;Visual C#&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; GetFormRegionStorage(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; FormRegionName, &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; Item,
   &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; LCID, Outlook.OlFormRegionMode FormRegionMode,
   Outlook.OlFormRegionSize FormRegionSize)
{
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (FormRegionName == &lt;SPAN class=str&gt;"OutlookStatsRegionCS"&lt;/SPAN&gt;)
   {
      &lt;SPAN class=rem&gt;// Return the storage only when there are headers&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; Properties.Resources.OutlookStatsRegionCS;
   }

   &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
}

&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; BeforeFormRegionShow(Outlook.FormRegion FormRegion)
{
   &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (FormRegion.InternalName == &lt;SPAN class=str&gt;"OutlookStatsRegionCS"&lt;/SPAN&gt;)
   {
      OutlookStatsRegion newRegion = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; OutlookStatsRegion(FormRegion);
      newRegion.Closed += &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; EventHandler(Region_Closed);

      _openRegions.Add(newRegion);
   }
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; BeforeFormRegionShow(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; FormRegion &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Microsoft.Office.Interop.Outlook.FormRegion) &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; Microsoft.Office.Interop.Outlook._FormRegionStartup.BeforeFormRegionShow
   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; FormRegion.InternalName = &lt;SPAN class=str&gt;"OutlookStatsRegionVB"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; newRegion &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; OutlookStatsRegion(FormRegion)
      &lt;SPAN class=kwrd&gt;AddHandler&lt;/SPAN&gt; newRegion.Closed, &lt;SPAN class=kwrd&gt;AddressOf&lt;/SPAN&gt; Region_Closed

      _openRegions.Add(newRegion)

   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt; GetFormRegionStorage(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; FormRegionName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; Item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; LCID &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt;, _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; FormRegionMode &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Microsoft.Office.Interop.Outlook.OlFormRegionMode, _&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;   &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; FormRegionSize &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Microsoft.Office.Interop.Outlook.OlFormRegionSize) &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; Microsoft.Office.Interop.Outlook._FormRegionStartup.GetFormRegionStorage

   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; FormRegionName = &lt;SPAN class=str&gt;"OutlookStatsRegionVB"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; My.Resources.OutlookStatsRegionVB
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;

   &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Function&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;P&gt;The last step is to register the add-in with Outlook. The add-in template provided with this article automatically generates a .reg file with the necessary settings to register the COM add-in created by the project with Outlook. Double click the .reg in Windows Explorer to register the add-in. Now you can change the debug properties of the project to start Outlook when debugging by setting the Start Action to Start External Program and then browse to the path of Outlook 2007. 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/clip_image002114.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/clip_image002114.jpg"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=170 src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/clip_image002113.jpg" width=240 border=0 mce_src="http://www.coding4fun.net/images/CollectingOutlook2007StatisticsUsingVSTO_CABF/clip_image002113.jpg"&gt;&lt;/A&gt; 
&lt;H3&gt;Conclusion&lt;/H3&gt;
&lt;P&gt;As you can see, VSTO 2005 SE allows developers a powerful tool for customizing Office 2007. New features in VSTO 2005 SE such as the Ribbon bar and custom form regions allow for even better integration than previous versions of VSTO. Outlook events made it possible for us to calculate statistics about email and calendar usage. In addition to the reports included in this add-in there is room for future additions. Some possibilities are: 
&lt;UL&gt;
&lt;LI&gt;Adding a custom region on contacts to show amount of time spent in meetings with a particular person 
&lt;LI&gt;Tracking the amount of time spent reading / composing emails 
&lt;LI&gt;Tracking the amount spent on tasks or the percentage of tasks completed on time&lt;/LI&gt;&lt;/UL&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { 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; }
&lt;/STYLE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1111248" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/productivity/default.aspx">productivity</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category></item><item><title>Building a Windows Vista Email Gadget using the .NET Framework</title><link>http://blogs.msdn.com/coding4fun/archive/2006/11/10/1055051.aspx</link><pubDate>Fri, 10 Nov 2006 22:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1055051</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/1055051.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=1055051</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=1055051</wfw:comment><description>&lt;SPAN id=c4fmetadata&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=1 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR class=entry_overview&gt;
&lt;TD class="" width=50&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;IMG height=50 src="http://blogs.msdn.com/photos/coding4fun/images/1055021/original.aspx" width=62 mce_src="http://blogs.msdn.com/photos/coding4fun/images/1055021/original.aspx"&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;SPAN class=entry_description&gt;&lt;BR&gt;&lt;BR&gt;The E-mail Alert Gadget is a simple yet indispensible Gadget for the Windows Sidebar platform. It provides users with a dynamic unread e-mail counter in the Windows Sidebar. By leveraging the convenience and functionality of Windows Sidebar and the power of .NET Framework applications, E-mail Alert is able to provide users with quick access to a useful piece of information: the number of unread e-mails in the user’s inbox.&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" colSpan=2&gt;
&lt;DIV class=entry_author&gt;Rohan Singh&lt;/DIV&gt;
&lt;DIV class=entry_company&gt;&lt;A href="http://www.sharplogic.com/" mce_href="http://www.sharplogic.com"&gt;SharpLogic Software&lt;/A&gt;&lt;/DIV&gt;&lt;BR&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Difficulty: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Easy&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Time Required:&lt;/B&gt; &lt;SPAN class=entry_details_input&gt;1-3 hours&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Cost: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Free&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Software: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Tested on Windows Vista Beta 2 (Build 5384), &lt;A href="http://msdn.com/express/" mce_href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/A&gt;, &lt;A href="http://msdn.microsoft.com/vstudio/express/vwd/" mce_href="http://msdn.microsoft.com/vstudio/express/vwd/"&gt;Visual Web Developer Express&lt;/A&gt; for JavaScript editing.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Hardware: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;None&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Download: &lt;/B&gt;&lt;A href="http://channel9.msdn.com/ShowPost.aspx?PostID=255919" mce_href="http://channel9.msdn.com/ShowPost.aspx?PostID=255919"&gt;Download&lt;/A&gt; 
&lt;UL&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&amp;nbsp; &lt;/H3&gt;
&lt;H3&gt;&lt;STRONG&gt;Windows Sidebar&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;Windows Sidebar is an application host of sorts that enables you to host customizable mini-applications or “Gadgets” to boost your personal productivity. Windows Sidebar is supported on &lt;STRIKE&gt;both Windows XP&lt;/STRIKE&gt;&lt;STRONG&gt;*&lt;/STRONG&gt; and Windows Vista. Figure 1 shows a Sidebar with three Gadgets: a clock, a stock ticker, and a CPU and memory gauge. 
&lt;P&gt;* Sidebar is not supported in Windows XP (thank you to alert C4F reader Tom Sage for pointing this out)&amp;nbsp; 
&lt;P&gt;&lt;A&gt;&lt;/A&gt;&lt;A&gt;&lt;FONT color=#000000&gt;Fig