<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9 - Entries tagged with windows miscellaneous</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Tags/windows+miscellaneous/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9 - Entries tagged with windows miscellaneous</title>
      <link>http://channel9.msdn.com/Tags/windows+miscellaneous</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Tags/windows+miscellaneous</link>
    <language>en</language>
    <pubDate>Sat, 25 May 2013 10:31:43 GMT</pubDate>
    <lastBuildDate>Sat, 25 May 2013 10:31:43 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>7</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Windows 7: Jump Lists</title>
      <description><![CDATA[
<p>In this article, learn how to provide quick access to links and actions in your Windows 7 application by creating a Jump List.</p>

<h3>Introduction</h3>
<p>Windows 7 includes a wealth of new features for developers to take advantage of.&nbsp; This includes better rendering subsystems, new sensor and location API's, file libraries, federated search, and of course, the improved taskbar.&nbsp; My last article discussed
 the taskbar's ability to show custom previews and toolbar icons.&nbsp; This article focuses on Jump Lists - the replacement for notification area context menus.</p>
<p>To get started, download <a href="http://www.microsoft.com/exPress/" target="_blank">
Visual Studio 2008 Express Edition</a> or higher (C# or VB).&nbsp; Or, just go for <a href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx" target="_blank">
Visual Studio 2010 Beta 2</a> - it's available now and well worth the download.&nbsp; All Express editions are free, and either 2008 or 2010 versions will work fine with this article's accompanying code.</p>
<h3>What's a Jump List?</h3>
<p>Jump Lists are a new concept in Windows 7 that allow developers to provide shortcuts for users right from their icon's context menu in the taskbar or Start menu.&nbsp; The shortcuts could be simple links to the documents folder or a library for a given application,
 or links back to the same application with a parameter passed to cause something to happen.</p>
<p>You can use this method in Live Messenger to change online status, display the new message window, or open web pages relating to the application.&nbsp; In the end, all of these are shortcuts.&nbsp; Shortcuts to URL's, or shortcuts back to the executable with an argument
 that causes some change to occur.</p>
<h3>Windows API Code Pack</h3>
<p>The Windows API Code Pack lets you take advantage of specific features of Windows Vista and Windows 7 that aren't available across the general framework, as well as native features that don't make sense in the common CLR used across all the supported configurations.
 Much of it consists of interop wrappers. </p>
<p>With the Code Pack, you get access to the new taskbar, Direct2D, DirectWrite, shell properties, Jump Lists, and more. The download also includes numerous sample code projects to get you started, so there's no excuse for avoiding new features!
</p>
<h3>Adding a Jump List</h3>
<p>Adding a Jump List is easy.&nbsp; After you create the list itself, add items (shortcuts to files or folders, and tasks) to it.&nbsp; Then, you can choose how a user's recent or frequently used documents show up.&nbsp; Windows manages the user documents list, which relieves
 you of some work. </p>
<p>It's important to note that in order to make a change to the list, you have to recreate the entire thing.&nbsp; In other words, you'll replace the old list with a new one, rather than updating it.
</p>
<p>Here's how the process works: </p>
<p>First, add the two required references from the Windows API Code Pack.&nbsp; You can either build a project and reference the DLL's, or directly add projects to your solution:
</p>
<p></p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_6.png"><img title="Windows API Code Pack references" border="0" alt="Windows API Code Pack references" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_1.png" width="244" height="84"></a></p>
<p>For convenience, you can add the namespaces to your <em>using </em>block to shorten typing later:
</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Imports</span> Microsoft.WindowsAPICodePack.Taskbar
<span class="kwrd">Imports</span> Microsoft.WindowsAPICodePack.Shell</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.WindowsAPICodePack.Taskbar;
<span class="kwrd">using</span> Microsoft.WindowsAPICodePack.Shell;</pre>
<p>&nbsp;</p>
<p>The <em>Microsoft.WindowsAPICodePack.Taskbar.JumpList </em>class is where most of the action is.&nbsp; There's a static factory method,
<em>CreateJumpList</em>, to create the list.&nbsp; Always start by calling this method, even if the application has created a Jump List in the past.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> CreateJumpList()
    <span class="kwrd">Dim</span> jl <span class="kwrd">As</span> JumpList = JumpList.CreateJumpList()</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> CreateJumpList()
{
    JumpList jl = JumpList.CreateJumpList();</pre>
<p>&nbsp;</p>
<p>Next, you have several options, depending on what you need in the list.&nbsp; The most basic group is the list of files.&nbsp; You can choose to show Recent files, Frequent files, or neither-but you can't have both.&nbsp; If you don't make a choice here, you'll get Recent
 files automatically, as long as you have a registered file type. </p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="rem">' Show user files: Recent, Frequent, or None</span>
jl.KnownCategoryToDisplay = JumpListKnownCategoryType.Recent</pre>
<p><strong>Visual C#</strong></p>
<p><span class="rem">// Show user files: Recent, Frequent, or None</span> <br>
jl.KnownCategoryToDisplay = JumpListKnownCategoryType.Recent; <br>
</p>
<p>Now you can add one or more custom categories of items.&nbsp; These are either folders or files.&nbsp; There are two very important rules:</p>
<ol>
<li>The files/folders must exist!&nbsp; If necessary, check the path before adding the
<em>JumpListItem </em>or you'll have a crash.&nbsp; </li><li>The files you add have to be of a type registered for your application, or you'll crash. Even worse: the exception won't occur on the line where you add it, but rather when you're done setting it up and try to refresh the list.
</li></ol>
<p>I've commented out the last item here, but you would use a <em>JumpListItem </em>
for actual file system files, and <em>JumpListLink </em>objects for non-filesystem references.&nbsp; Again, don't add a JumpListItem unless you know that it exists and that you're registered to handle it.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="rem">' Add my own links (nouns)</span>
<span class="kwrd">Dim</span> catActions <span class="kwrd">As</span> <span class="kwrd">New</span> JumpListCustomCategory(<span class="str">&quot;Destinations&quot;</span>)

catActions.AddJumpListItems(
    <span class="kwrd">New</span> JumpListLink(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), <span class="str">&quot;My Pictures&quot;</span>), _
    <span class="kwrd">New</span> JumpListLink(<span class="str">&quot;http://blogs.msdn.com/coding4fun&quot;</span>, <span class="str">&quot;Visit Coding4Fun&quot;</span>), _
    <span class="kwrd">New</span> JumpListLink(<span class="str">&quot;http://code.msdn.microsoft.com/WindowsAPICodePack&quot;</span>, <span class="str">&quot;Windows API Code Pack&quot;</span>))
    <span class="rem">'new JumpListItem(@&quot;c:\Test1.c4f&quot;)</span>

jl.AddCustomCategories(catActions)</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="rem">// Add my own links (nouns)</span>
JumpListCustomCategory catActions = <span class="kwrd">new</span> JumpListCustomCategory(<span class="str">&quot;Destinations&quot;</span>);
catActions.AddJumpListItems(
    <span class="kwrd">new</span> JumpListLink(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), <span class="str">&quot;My Pictures&quot;</span>),
    <span class="kwrd">new</span> JumpListLink(<span class="str">&quot;http://blogs.msdn.com/coding4fun&quot;</span>, <span class="str">&quot;Visit Coding4Fun&quot;</span>),
    <span class="kwrd">new</span> JumpListLink(<span class="str">&quot;http://code.msdn.microsoft.com/WindowsAPICodePack&quot;</span>, <span class="str">&quot;Windows API Code Pack&quot;</span>)
    <span class="rem">//new JumpListItem(@&quot;c:\Test1.c4f&quot;)</span>
    );

jl.AddCustomCategories( catActions);</pre>
<p>You can add one or more tasks as&nbsp; links to system executables by using the <em>
AddUserTasks </em>method of the JumpList object.&nbsp; Either create multiple objects and add them as a variable argument list, or add them one at a time, as I have here.</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="rem">' Add our user tasks (verbs)</span>
jl.AddUserTasks(<span class="kwrd">New</span> JumpListLink(Path.Combine(systemFolder, <span class="str">&quot;notepad.exe&quot;</span>), <span class="str">&quot;Open Notepad&quot;</span>) _
    <span class="kwrd">With</span> {.IconReference = <span class="kwrd">New</span> IconReference(Path.Combine(systemFolder, <span class="str">&quot;notepad.exe&quot;</span>), 0)})</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">jl.AddUserTasks(<span class="kwrd">new</span> JumpListLink(Path.Combine(systemFolder, <span class="str">&quot;notepad.exe&quot;</span>), <span class="str">&quot;Open Notepad&quot;</span>)
{
    IconReference = <span class="kwrd">new</span> IconReference(Path.Combine(systemFolder, <span class="str">&quot;notepad.exe&quot;</span>), 0)
});</pre>
<p>The <em>IconReference</em> property sets a pointer to the icon by referencing a DLL or EXE and then an index.&nbsp; Specifying an EXE with &quot;0&quot; is a good way to get the default icon for an executable that you are linking to.</p>
<p>You can add a separator to the list whenever you need to.&nbsp; The <i>JumpListSeparator
</i>class represents a separator and can be added using the <i>AddUserTasks </i>call.
</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">jl.AddUserTasks(<span class="kwrd">New</span> JumpListSeparator())</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">jl.AddUserTasks(<span class="kwrd">new</span> JumpListSeparator());</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The final links in our Jump List link back to our own executable. This is the most common use of Jump Lists.&nbsp; Just having a Recent/Frequent list is nice, but being able to trigger actions on the program itself-even when it's not started-is really handy.&nbsp;
 It's almost like a menu of command line options! </p>
<p>Commands in the list that invoke actions on the application itself involve calling the same application with different arguments.&nbsp; Remember that this isn't a true menu; you won't receive a
<em>Click</em> event.&nbsp; Instead, you need to deal with an argument that's passed to you, even if you're already running.
</p>
<p>Remember that the first argument on the command line is always the fully-qualified location to the running executable.&nbsp; The
<i>Arguments </i>property lets you specify command line arguments that users don't directly see.&nbsp; For this sample application, I've defined three dummy arguments.&nbsp; If one of these is passed in, the application changes the background color of a label and indicates
 which argument it was. </p>
<p></p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">jl.AddUserTasks(<span class="kwrd">New</span> JumpListLink(<span class="kwrd">Assembly</span>.GetEntryAssembly().Location, <span class="str">&quot;Action 1 (Green)&quot;</span>) _
    <span class="kwrd">With</span> {.Arguments = <span class="str">&quot;-1&quot;</span>, .IconReference = <span class="kwrd">New</span> IconReference(<span class="kwrd">Assembly</span>.GetEntryAssembly().Location, 0)})</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode">jl.AddUserTasks(<span class="kwrd">new</span> JumpListLink(Assembly.GetEntryAssembly().Location, <span class="str">&quot;Action 1 (Green)&quot;</span>)
{
    IconReference = <span class="kwrd">new</span> IconReference(Assembly.GetEntryAssembly().Location, 0),
    Arguments = <span class="str">&quot;-1&quot;</span>
});</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_12.png"><img title="Sample JumpList" border="0" alt="Sample JumpList" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_2.png" width="267" height="367"></a>
</p>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3>Invoking Self Actions</h3>
<p>Windows Live Messenger uses Jump List actions for setting its own available status, and Windows Media Player has Jump List actions for skipping tracks or stopping.&nbsp; Likewise, you can add tasks that invoke actions on the same executable.&nbsp; If the application
 isn't running (remember that the Jump List is still available), this will cause it to be launched with the right argument.&nbsp; That's no problem.&nbsp; What if it's already running though?</p>
<p>The key is to find a way to pass messages between running instances.&nbsp; When the application starts up, check to see if another instance is running by using a
<em>Mutex </em>(see <em>Program.cs</em>).&nbsp; If not, just use the arguments directly.&nbsp; If it is running, send the information about the parameter to the other instance and then quit.&nbsp; You could use temporary files, shared registry keys, or memory-mapped files.&nbsp;
 I find it easiest to use window messages.</p>
<p>You can find the code to create custom message ID's, to find the right window, and to send the message in my
<em>WindowsMessageHelper </em>class.</p>
<p>From the main window code, override the <em>WndProc </em>method.&nbsp; This is the message loop for everything: mouse events, key events, window closing, and much more.&nbsp; Ensure that the message is something you need; otherwise pass it on to the underlying handler.</p>
<p>If the application is already running, post a message.&nbsp; If not, start as usual and watch your message queue.&nbsp; If you see a message of interest, take some action (in this case, just showing a message and changing a color).&nbsp;
</p>
<p>The only other tricky thing to remember, is that you might startup as the only instance, and
<em>also </em>have a parameter.&nbsp; For example, if the user clicked a task on the Jump List but the application isn't running.&nbsp; I take the easy way out and check for parameters after fully starting up and then post to my own queue if needed!&nbsp; That simplifies
 some of the logic anyway.</p>
<p>If you don't mind using the <strong>Microsoft.VisualBasic.ApplicationServices</strong> namespace from C#, then you can take advantage of the VB SingleInstance application mode.&nbsp; This removes the need for any explicit mutex, interop, or message passing.&nbsp;
 You can find some great information about this on Jocelyn Villaraza's excellent <a href="http://aimeegurl.com/2009/11/13/making-your-win7-jumplists-trigger-on-the-same-application-instance/" target="_blank">
blog post</a>.</p>
<h3>Registering a File Type</h3>
<p>Remember: unless you're registered as a file handler for the type, you can't show recent or frequent files or point to individual files.&nbsp; Register to be a file handler by creating a registry write operation to a key under HKEY_CLASSES.&nbsp;
</p>
<p>The problem is, you can't write to the HKEY_CLASSES branch of the registry without proper permissions.&nbsp; By default, permission is only granted to the Administrators group.&nbsp; You really don't want to require that your application run under administrative privileges-that
 would be <i>so </i>Windows XP! </p>
<p>There are two alternatives: you could create a second application that can run elevated in order to perform the registration.&nbsp; This is how the samples do it with the Windows API Code Pack. A better method is to create a custom installer for the project and
 perform the association there.&nbsp; Installers always require administrative rights, and they only need to run once.
</p>
<p></p>
<h3>Creating the Installer</h3>
<p>To create the installer, first add a setup project to your solution, following the usual steps. Then, from the
<b>Project types </b>list, click <b>Other Project Types | Setup and Deployment</b>.&nbsp; In the
<b>Templates </b>list, click <b>Setup Project</b>. Give it a name, then add it.</p>
<h3><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_10.png"><img title="New project types" border="0" alt="New project types" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_4.png" width="640" height="463"></a>
</h3>
<p>From <strong>Solution Explorer</strong>, right-click the setup project, then click the
<strong>View | File Types </strong>menu command.</p>
<h3><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_8.png"><img title="View File Types" border="0" alt="View File Types" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_3.png" width="418" height="264"></a>
</h3>
<p>From the File Types list, right-click <strong>File Types on Target Machine</strong>, and then click
<strong>Add File Type</strong>.&nbsp; Fill out the properties to name the file type and provide the extension.&nbsp; For
<strong>Command</strong>, be sure to set it to the Primary output of the main project.&nbsp;
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_16.png"><img title="File type properties" border="0" alt="File type properties" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_6.png" width="342" height="194"></a>
</p>
<p>The file type should appear like the following in the <strong>File Types </strong>
tab:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_14.png"><img title="File Types list" border="0" alt="File Types list" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9933039/image_thumb_5.png" width="196" height="87"></a>
</p>
<p>Now you have a registered file type.&nbsp; You still need to modify your setup project to copy the primary output (the EXE) to Program Files and customize any other properties in the setup project, but these are the special steps for file types.&nbsp; If in doubt,
 take a look at sample code to see how the Setup project is configured.</p>
<h3>Conclusion</h3>
<p></p>
<p></p>
<p></p>
<p>Working with the Windows API Code Pack makes it much easier to customize the taskbar and add Jump Lists, and gives you a great experience that really integrates well with the system.&nbsp; Download Visual Studio Express, grab the Windows API Code Pack, and start
 digging in.</p>
<p>The new features won't work on machines prior to Windows 7, so be sure to check that they're supported.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:b31966c53e384bc0ab3f9e7600ca8ef7">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists</comments>
      <itunes:summary>
In this article, learn how to provide quick access to links and actions in your Windows 7 application by creating a Jump List. 

Introduction
Windows 7 includes a wealth of new features for developers to take advantage of.&amp;nbsp; This includes better rendering subsystems, new sensor and location API&#39;s, file libraries, federated search, and of course, the improved taskbar.&amp;nbsp; My last article discussed
 the taskbar&#39;s ability to show custom previews and toolbar icons.&amp;nbsp; This article focuses on Jump Lists - the replacement for notification area context menus. 
To get started, download 
Visual Studio 2008 Express Edition or higher (C# or VB).&amp;nbsp; Or, just go for 
Visual Studio 2010 Beta 2 - it&#39;s available now and well worth the download.&amp;nbsp; All Express editions are free, and either 2008 or 2010 versions will work fine with this article&#39;s accompanying code. 
What&#39;s a Jump List?
Jump Lists are a new concept in Windows 7 that allow developers to provide shortcuts for users right from their icon&#39;s context menu in the taskbar or Start menu.&amp;nbsp; The shortcuts could be simple links to the documents folder or a library for a given application,
 or links back to the same application with a parameter passed to cause something to happen. 
You can use this method in Live Messenger to change online status, display the new message window, or open web pages relating to the application.&amp;nbsp; In the end, all of these are shortcuts.&amp;nbsp; Shortcuts to URL&#39;s, or shortcuts back to the executable with an argument
 that causes some change to occur. 
Windows API Code Pack
The Windows API Code Pack lets you take advantage of specific features of Windows Vista and Windows 7 that aren&#39;t available across the general framework, as well as native features that don&#39;t make sense in the common CLR used across all the supported configurations.
 Much of it consists of interop wrappers.  
With the Code Pack, you get access to the new taskbar, Direct2D, DirectWrite, shell properties, Jump Li</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists</link>
      <pubDate>Wed, 09 Dec 2009 21:59:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9933039_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9933039_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Arian Kulp </dc:creator>
      <itunes:author>Arian Kulp </itunes:author>
      <slash:comments>13</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists/RSS</wfw:commentRss>
      <category>Windows 7</category>
      <category>windows miscellaneous</category>
    </item>
  <item>
      <title>Creating a Utility Framework</title>
      <description><![CDATA[
<p>In this article I demonstrate how you can take advantage of a light application framework when creating simple utilities.&nbsp; Instead of working on lower-level plumbing, just create the code for whatever tool you need, and this framework can get you working
 faster.</p>

<h3>Introduction</h3>
<p>When you write small utilities, there's a certain amount of tedious repetitive work to get it up and going. Creating the main window, the tray icon (including the icon and context menu), and other common tasks just get in the way. In this article, I've created
 a reusable utility framework and will show you how to make use of it.</p>
<p>To run this code, you'll need to use Visual Studio 2008 SP1, Express Edition or higher. If you haven't downloaded it yet, go to
<a href="http://www.microsoft.com/express">http://www.microsoft.com/express</a>. You can either use Visual Basic or Visual C# to work with the main project or create add-ins for this project.</p>
<h3>A Framework?</h3>
<p>So what did I actually create for this article? We all know that using base classes is a great way to tie together closely-related objects. As a very practical example, a base window or control class lets you add functionality to something that already exists
 without reinventing the wheel, so to speak. Windows exposes a number of code execution models such as services, console apps, Sidebar gadgets, Windows forms, WPF, COM, and more. Each of these provides a certain amount of functionality that you don't need to
 worry about, such as start/stop hooks for services, or the system message loop for Windows forms and WPF.</p>
<p>Having built a good number of small utilities over the years, I've definitely realized that I'm copying or rewriting too much code. What a waste! Since I always create a notification icon (shows up by the system clock), and I like to hide to tray on minimize,
 and remember window settings, I implement these in each project. I probably should have created a project template in Visual Studio as a shortcut, but this has a disadvantage. If I added a cool new feature to my framework, I'd need to recompile and rework
 the older apps to take advantage of it</p>
<p>The better solution was to create a “base application.” This would actually be its own application that exposes a notification icon and menu, and a main window. If you move the window, the location is saved. Individual utilities can then be added as plugins.
 I originally envisioned a framework able to host multiple applications, but that creates some interesting design challenges with visual apps. In the end, I settled on a reusable application which can host a single utility.</p>
<h3>A Common User Interface</h3>
<p>I decided to write this in WPF since it affords so many great options for layout and interactivity. I still write some Winforms code, but WPF is just an incredible way to build your application declaratively (not that XAML is required…) and it enables a
 nice clean code layout. If you are really tied to Windows Forms, you can always use the
<b>WindowsFormsHost</b> control to expose it.</p>
<p>The basic application isn't very complicated. It lets you set the application name which it uses in the tray menu and in the main window title. You can also set whether it minimizes to tray or not. If not, the close button will actually kill the application.
 Minimize always minimizes as normal.</p>
<p>Finally, the main window shows both the preferences UI. Most small utility apps don't really have a UI other than settings. You can always show dialogs and windows, but if all you have is a few settings, you can just create a UserControl to contain them
 and the application will host it.</p>
<p>As an example, I created a utility add-in. It looks like some sort of file watching utility. It's not actually functional – it's just a collection of controls in a UserControl. This is paired up with the application name, icon, and more.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9535026/clip_image002_2.jpg"><img title="Figure 1 : Main Window" border="0" alt="Figure 1 : Main Window" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9535026/clip_image002_thumb.jpg" width="409" height="338"></a></p>
<p align="center"><em>Figure 1 : Main Application Window</em></p>
<h3>Modularity</h3>
<p>So I mentioned before that one of my motivations with this project was to allow me to update the framework without needing to recompile the utilities themselves. To be clear, this won't be possible 100% of the time, but as long as I leave the public interfaces
 alone, it should work well. So here's the cool implementation: Managed Extensibility Framework, or MEF.</p>
<p>MEF allows you to build extensibility into your applications with little effort. Build your interfaces or contracts, and as long as plugins use that contract, code can be compiled into separate assemblies with no dependencies. When the application starts
 up, you tell it where to find extensions and it takes care of loading them. The contract for addins (<b>IWpfService</b>) is defined as:</p>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">interface</span> IWpfService
{
    <span class="rem">// Gets the custom control to display in the host preferences dialog.</span>
    UserControl OptionsUserControl { get; }

    <span class="kwrd">string</span> Name { get; }
    System.Drawing.Icon TrayIcon { get; }
    <span class="kwrd">string</span> Description { get; }
    <span class="kwrd">string</span> Author { get; }
    Version Version { get; }
    Uri AuthorUri { get; }
    <span class="kwrd">bool</span> HideOnClose { get; }
    <span class="kwrd">string</span> Status { get; set; }

    <span class="kwrd">void</span> Initialize();
    <span class="kwrd">void</span> Start();
    <span class="kwrd">void</span> Stop();

    <span class="kwrd">event</span> EventHandler StatusUpdated;
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Interface</span> IWpfService
    <span class="rem">' Gets the custom control to display in the host preferences dialog.</span>
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> OptionsUserControl() <span class="kwrd">As</span> UserControl

    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Name() <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> TrayIcon() <span class="kwrd">As</span> System.Drawing.Icon
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Description() <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Author() <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Version() <span class="kwrd">As</span> Version
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> AuthorUri() <span class="kwrd">As</span> Uri
    <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> HideOnClose() <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Property</span> Status() <span class="kwrd">As</span> <span class="kwrd">String</span>

    <span class="kwrd">Sub</span> Initialize()
    <span class="kwrd">Sub</span> Start()
    <span class="kwrd">Sub</span> [<span class="kwrd">Stop]</span>()

    <span class="kwrd">Event</span> StatusUpdated <span class="kwrd">As</span> EventHandler

<span class="kwrd">End</span> Interface</pre>
<p>The UserControl reference is a composite control with any necessary user interface elements for configuring the application. This could be a file dialog, checkboxes for options, buttons to start or stop processing threads, or whatever makes sense. The base
 application (the host) then provides access to them based on user request. The <b>
Name</b>, <b>TrayIcon</b>, <b>Description</b>, and other such properties are used to generate information such as found in an About dialog. The methods are used by the host to control the lifecycle, similar to a Windows service. The
<b>Initialize()</b> method is called on startup, followed by <b>Start()</b>. <b>Stop()</b> is called at shutdown/close. The hosted utility doesn't need to worry about many of the general application logic – just specific units of work.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9535026/clip_image004_2.jpg"><img title="Figure 2 : Showing About this Application" border="0" alt="Figure 2 : Showing About this Application" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9535026/clip_image004_thumb.jpg" width="438" height="377"></a></p>
<p align="center"><em>Figure 2 : Showing About this Application</em></p>
<p>The <b>ExtensibleWpfApp </b>project contains a base class called <b>ApplicationWindow</b>, which descends from Window. This can be used by any application that wants a simple tray menu, position and size saving, and minimize to tray. On top of that is the
<b>MainAppWindow</b> class. This descends from <b>ApplicationWindow</b> and also implements
<b>IWpfHost</b>. This takes care of creating a main window that displays the application metadata and settings. You're welcome to take either class as a base class, but then you wouldn't get the benefit of MEF extensibility.</p>
<p>During the instantiation of the <b>MainAppWindow </b>class it also initializes itself and its base class using properties from the add-in:</p>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> MainAppWindow()
{
    InitializeComponent();

    Compose();

    <span class="rem">// Settings menu item on or off, ShowApp menu item on or off, Wire up callbacks, etc.</span>
    CurrentAddin.Start();

    <span class="kwrd">this</span>.ApplicationName = CurrentAddin.Name;
    <span class="kwrd">this</span>.HideOnClose = CurrentAddin.HideOnClose;

    <span class="rem">// Sets a custom icon or leaves it as default</span>
    <span class="kwrd">if</span>( CurrentAddin.TrayIcon != <span class="kwrd">null</span> )
    {
        <span class="kwrd">this</span>.TrayIcon = CurrentAddin.TrayIcon;
    }

    dockPanelAddinInfo.DataContext = CurrentAddin;

    Application.Current.Exit &#43;= <span class="kwrd">new</span> ExitEventHandler(CurrentApp_Exit);
    CurrentAddin.StatusUpdated &#43;= <span class="kwrd">new</span> EventHandler(CurrentAddin_StatusUpdated);
}</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()
    InitializeComponent()

    Compose()

    <span class="rem">' Settings menu item on or off, ShowApp menu item on or off, Wire up callbacks, etc.</span>
    CurrentAddin.Start()

    <span class="kwrd">Me</span>.ApplicationName = CurrentAddin.Name
    <span class="kwrd">Me</span>.HideOnClose = CurrentAddin.HideOnClose

    <span class="rem">' Sets a custom icon or leaves it as default</span>
    <span class="kwrd">If</span> CurrentAddin.TrayIcon IsNot <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        <span class="kwrd">Me</span>.TrayIcon = CurrentAddin.TrayIcon
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    dockPanelAddinInfo.DataContext = CurrentAddin

    <span class="kwrd">AddHandler</span> Application.Current.<span class="kwrd">Exit</span>, <span class="kwrd">AddressOf</span> CurrentApp_Exit
    <span class="kwrd">AddHandler</span> CurrentAddin.StatusUpdated, <span class="kwrd">AddressOf</span> CurrentAddin_StatusUpdated
<span class="kwrd">End</span> Sub</pre>
<p>Notice how it has the concept of application name and a tray icon – something a standard application doesn't have. It's easy enough to add these things, but it can be tedious, and beginner programmers just have that much more to figure to get started.</p>
<h3>Next Steps</h3>
<p>Though the application is a good start, I see a need for more. The application could invoke add-in features on a timer with the framework prompting the user for the interval and handling that automatically. The concept of saving and cancelling settings changes
 should really be built into the framework. It might also be good for the add-in to have access to show/hide the window as needed. Hooking into the system Event Log or other logging and other tracing mechanisms could also be handled by the framework.</p>
<p>The key is to find common services that applications can use which also normally require some user configuration. If the framework can handle that automatically, it makes for less work for each utility.</p>
<h3>Conclusion</h3>
<p>First of all, this is only the first part of this article. Next time I'll dig into the MEF implementation and explain how an add-in works in better detail. I'll flesh out the sample add-in a bit as a point of reference and hopefully you'll see how you might
 benefit from it as well.</p>
<p>Building reusable application code can make a huge difference over time. Unfortunately it always takes longer the first time to do it right. Good code ends up being reused, but copy-and-paste reuse isn't as good as binary reuse (referencing an assembly/DLL),
 and that's still not as good as composition where new components bind to a framework at runtime. Frameworks like MEF, System.Addin, PRISM, and others make it much easier than it used to be to create extension points so code can fit in later. Used wisely this
 can lead to a more streamlined code base where you can rely on other contributors or communities to implement new features instead of coming to you each time. You can focus on creating a solid foundation and let people create niche or mainstream features as
 they see fit. You'll be happier and your users will love it too!</p>
<p>If you haven't already, download Visual Studio Express Edition today and get started.</p>
<h3>About the Author</h3>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="157">
<p align="center"><img title="Arian Kulp" border="0" alt="Arian Kulp" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9535026/Avatar80_3.jpg" width="90" height="100"></p>
</td>
<td valign="top" width="481">
<p><strong>Arian Kulp</strong> is a software developer living in the Midwest.&nbsp; He has been writing software since the fifth grade (though not always professionally).&nbsp; Arian creates developer evangelism stuff, speaks at INETA and Code Camps, and loves to stay
 on the cutting edge of technology.&nbsp; In his spare time, he enjoys nature, photography, and his family.</p>
</td>
</tr>
</tbody>
</table>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:ff724226e967403f81289e7600ccac4c">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Creating-a-Utility-Framework</comments>
      <itunes:summary>
In this article I demonstrate how you can take advantage of a light application framework when creating simple utilities.&amp;nbsp; Instead of working on lower-level plumbing, just create the code for whatever tool you need, and this framework can get you working
 faster. 

Introduction
When you write small utilities, there&#39;s a certain amount of tedious repetitive work to get it up and going. Creating the main window, the tray icon (including the icon and context menu), and other common tasks just get in the way. In this article, I&#39;ve created
 a reusable utility framework and will show you how to make use of it. 
To run this code, you&#39;ll need to use Visual Studio 2008 SP1, Express Edition or higher. If you haven&#39;t downloaded it yet, go to
http://www.microsoft.com/express. You can either use Visual Basic or Visual C# to work with the main project or create add-ins for this project. 
A Framework?
So what did I actually create for this article? We all know that using base classes is a great way to tie together closely-related objects. As a very practical example, a base window or control class lets you add functionality to something that already exists
 without reinventing the wheel, so to speak. Windows exposes a number of code execution models such as services, console apps, Sidebar gadgets, Windows forms, WPF, COM, and more. Each of these provides a certain amount of functionality that you don&#39;t need to
 worry about, such as start/stop hooks for services, or the system message loop for Windows forms and WPF. 
Having built a good number of small utilities over the years, I&#39;ve definitely realized that I&#39;m copying or rewriting too much code. What a waste! Since I always create a notification icon (shows up by the system clock), and I like to hide to tray on minimize,
 and remember window settings, I implement these in each project. I probably should have created a project template in Visual Studio as a shortcut, but this has a disadvantage. If I added a cool new feature t</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Creating-a-Utility-Framework</link>
      <pubDate>Tue, 14 Apr 2009 13:00:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Creating-a-Utility-Framework</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9535026_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9535026_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>ArianKulp</dc:creator>
      <itunes:author>ArianKulp</itunes:author>
      <slash:comments>7</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Creating-a-Utility-Framework/RSS</wfw:commentRss>
      <category>Windows</category>
      <category>windows miscellaneous</category>
    </item>
  <item>
      <title>WPF Custom Screen Saver Art</title>
      <description><![CDATA[
<h3>Summary</h3>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/thum.png"><img title="thum" border="0" alt="thum" align="left" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/thum_thumb.png" width="71" height="63"></a>Creating custom
 wallpaper is easy. But what about custom screen savers? This post will detail how to build a custom saver using Windows Presentation Framework (WPF). The posted code also provides some insight on how to create interesting particle effects using WPF's animation
 engine, and how to implement multiple monitor support in .Net.</p>
<p>Erik Klimczak - <a href="http://www.claritycon.com/">Clarity Consulting</a></p>
<h5>Download</h5>
<ul>
<li><span><a href="http://wpfscreensaverart.codeplex.com/">http://wpfscreensaverart.codeplex.com/</a>&nbsp;</span>&nbsp;</li></ul>
<h4></h4>
<h4>Introduction</h4>
<p><a href="http://www.microsoft.com/uc/default.mspx">Microsoft Unified Communications</a> (UC) is a new technology that has been getting a lot of hype in the past couple of months. UC is essentially the integration of messaging, voice, and video across the
 applications and devices that people use every day. More information about UC can be found
<a href="http://www.microsoft.com/uc/default.mspx">here</a>. One of the coolest things about UC is the concept of “presence” (see below). The Presence indicator effectively allows the user to reflect his/her status in other Office Communicator Server friendly
 applications (i.e. Outlook, Office communicator, Live Meeting, etc.)</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image002.jpg"><img title="clip_image002" border="0" alt="clip_image002" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image002_thumb.jpg" width="240" height="151"></a></p>
<p>While building out some communicator functionality on another project I found myself recreating the presence “bubbles” in xaml so that they could scale without losing quality (see below). I used Expression Design to re-create the presence bubbles and export
 then to xaml.</p>
<p>In doing so it occurred to me that the presence “bubbles” would make for some excellent art sprites.
</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image004.jpg"><img title="clip_image004" border="0" alt="clip_image004" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image004_thumb.jpg" width="470" height="342"></a>&nbsp;</p>
<p>So after a hop-skip-and a jump to Photoshop I found myself with a shiny new “presence art” wallpaper.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image006.jpg"><img title="clip_image006" border="0" alt="clip_image006" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image006_thumb.jpg" width="496" height="312"></a></p>
<p>Immediately after creating the wallpaper I thought to myself, “this would also make a great screen saver”. This article will attempt to show how to build a custom WPF screen saver that implements a simple physics particle effect using the WPF animation engine.</p>
<h4>Particle Animation</h4>
<p>With my graphic designer hat on I knew that I wanted to create a floating particle effect. Particle effects can be used to simulate anything from rain, snow, fire to bubbles and clouds. Then by varying the presence “bubbles” in size and opacity the illusion
 of depth and space can be created. After some research I found the CompositionTarget.Rendering event handler in WPF. Essentially, this event is a timer that ticks all the time and fires once each time WPF decides to render a frame. Inside the event handler
 you have complete freedom to do whatever you want to any object.&nbsp; In other words, hooking CompositionTarget.Rendering is very much a &quot;do it yourself&quot; animation system. This event is especially good for physics-based animations and is very similar to the way
 Flash's rendering engine works. The MSDN entry for this event handler can be found
<a href="http://msdn.microsoft.com/en-us/library/system.windows.media.compositiontarget.rendering.aspx">
here</a>.</p>
<p>Once I had found the appropriate animation hook I created the particle user control. This control holds the various particle attributes that will be animated. The code below shows the various properties that can be used to create very interesting physics-based
 effects. These properties can be used to calculate collision detection, gravitational pull and other kinetics-related effects.</p>
<p>C#</p>
<div>
<div>
<pre><span>   1:</span> <span>public</span> <span>partial</span> <span>class</span> Particle : UserControl</pre>
<pre><span>   2:</span>    {</pre>
<pre><span>   3:</span>&nbsp; </pre>
<pre><span>   4:</span>        <span>public</span> Particle()</pre>
<pre><span>   5:</span>        {</pre>
<pre><span>   6:</span>&nbsp; </pre>
<pre><span>   7:</span>            InitializeComponent();</pre>
<pre><span>   8:</span>        }</pre>
<pre><span>   9:</span>&nbsp; </pre>
<pre><span>  10:</span>        <span>public</span> <span>static</span> <span>readonly</span> DependencyProperty StatusProperty = DependencyProperty.Register(<span>&quot;Status&quot;</span>, <span>typeof</span>(Status), <span>typeof</span>(Particle), <span>new</span> UIPropertyMetadata(Particle.StatusValueChanged));</pre>
<pre><span>  11:</span>        <span>public</span> Status Status</pre>
<pre><span>  12:</span>        {</pre>
<pre><span>  13:</span>            get { <span>return</span> (Status)GetValue(StatusProperty); }</pre>
<pre><span>  14:</span>            set { SetValue(StatusProperty, <span>value</span>); }</pre>
<pre><span>  15:</span>        }</pre>
<pre><span>  16:</span>&nbsp; </pre>
<pre><span>  17:</span>        <span>private</span> <span>static</span> <span>void</span> StatusValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)</pre>
<pre><span>  18:</span>        {</pre>
<pre><span>  19:</span>            Particle myclass = (Particle)d;</pre>
<pre><span>  20:</span>            myclass.imgStatus.Source = Application.Current.FindResource(((Status)e.NewValue).ToString() &#43; <span>&quot;Png&quot;</span>) <span>as</span> BitmapImage;</pre>
<pre><span>  21:</span>        }</pre>
<pre><span>  22:</span>&nbsp; </pre>
<pre><span>  23:</span>        <span>public</span> <span>double</span> Radius</pre>
<pre><span>  24:</span>        {</pre>
<pre><span>  25:</span>            get { <span>return</span> <span>this</span>.imgStatus.Height / 2; }</pre>
<pre><span>  26:</span>            set { <span>this</span>.imgStatus.Height = <span>this</span>.imgStatus.Width = <span>value</span> * 2; }</pre>
<pre><span>  27:</span>        }</pre>
<pre><span>  28:</span>&nbsp; </pre>
<pre><span>  29:</span>        <span>private</span> <span>double</span> vy;</pre>
<pre><span>  30:</span>        <span>public</span> <span>double</span> VY</pre>
<pre><span>  31:</span>        {</pre>
<pre><span>  32:</span>            get { <span>return</span> <span>this</span>.vy; }</pre>
<pre><span>  33:</span>            set { <span>this</span>.vy = <span>value</span>; }</pre>
<pre><span>  34:</span>        }</pre>
<pre><span>  35:</span>&nbsp; </pre>
<pre><span>  36:</span>        <span>private</span> <span>double</span> vx;</pre>
<pre><span>  37:</span>        <span>public</span> <span>double</span> VX</pre>
<pre><span>  38:</span>        {</pre>
<pre><span>  39:</span>            get { <span>return</span> <span>this</span>.vx; }</pre>
<pre><span>  40:</span>            set { <span>this</span>.vx = <span>value</span>; }</pre>
<pre><span>  41:</span>        }</pre>
<pre><span>  42:</span>&nbsp; </pre>
<pre><span>  43:</span>        <span>private</span> <span>double</span> mass;</pre>
<pre><span>  44:</span>        <span>public</span> <span>double</span> Mass</pre>
<pre><span>  45:</span>        {</pre>
<pre><span>  46:</span>            get { <span>return</span> <span>this</span>.mass; }</pre>
<pre><span>  47:</span>            set { <span>this</span>.mass = <span>value</span>; }</pre>
<pre><span>  48:</span>        }</pre>
<pre><span>  49:</span>        <span>private</span> <span>double</span> x;</pre>
<pre><span>  50:</span>        <span>public</span> <span>double</span> X</pre>
<pre><span>  51:</span>        {</pre>
<pre><span>  52:</span>            get { <span>return</span> <span>this</span>.x; }</pre>
<pre><span>  53:</span>            set { <span>this</span>.x = <span>value</span>; }</pre>
<pre><span>  54:</span>        }</pre>
<pre><span>  55:</span>&nbsp; </pre>
<pre><span>  56:</span>        <span>private</span> <span>double</span> y;</pre>
<pre><span>  57:</span>        <span>public</span> <span>double</span> Y</pre>
<pre><span>  58:</span>        {</pre>
<pre><span>  59:</span>            get { <span>return</span> <span>this</span>.y; }</pre>
<pre><span>  60:</span>            set { <span>this</span>.y = <span>value</span>; }</pre>
<pre><span>  61:</span>        }</pre>
<pre><span>  62:</span>    }</pre>
</div>
</div>
<pre class="csharpcode">VB</pre>
<div>
<div>
<pre><span>   1:</span> Partial <span>Public</span> <span>Class</span> Particle</pre>
<pre><span>   2:</span>     <span>Inherits</span> UserControl</pre>
<pre><span>   3:</span>&nbsp; </pre>
<pre><span>   4:</span>&nbsp; </pre>
<pre><span>   5:</span>     <span>Public</span> <span>Sub</span> <span>New</span>()</pre>
<pre><span>   6:</span>         InitializeComponent()</pre>
<pre><span>   7:</span>     <span>End</span> <span>Sub</span></pre>
<pre><span>   8:</span>&nbsp; </pre>
<pre><span>   9:</span>     <span>Public</span> <span>Shared</span> <span>ReadOnly</span> StatusProperty <span>As</span> DependencyProperty = DependencyProperty.Register(<span>&quot;Status&quot;</span>, <span>GetType</span>(Status), <span>GetType</span>(Particle), <span>New</span> PropertyMetadata(<span>AddressOf</span> Particle.StatusValueChanged))</pre>
<pre><span>  10:</span>     <span>Public</span> <span>Property</span> Status() <span>As</span> Status</pre>
<pre><span>  11:</span>         <span>Get</span></pre>
<pre><span>  12:</span>             <span>Return</span> <span>CType</span>(GetValue(StatusProperty), Status)</pre>
<pre><span>  13:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  14:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> Status)</pre>
<pre><span>  15:</span>             SetValue(StatusProperty, value)</pre>
<pre><span>  16:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  17:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  18:</span>&nbsp; </pre>
<pre><span>  19:</span>     <span>Private</span> <span>Shared</span> <span>Sub</span> StatusValueChanged(<span>ByVal</span> d <span>As</span> DependencyObject, <span>ByVal</span> e <span>As</span> DependencyPropertyChangedEventArgs)</pre>
<pre><span>  20:</span>         <span>Dim</span> [<span>myclass</span>] <span>As</span> Particle = <span>CType</span>(d, Particle)</pre>
<pre><span>  21:</span>         [<span>myclass</span>].imgStatus.Source = <span>TryCast</span>(Application.Current.FindResource((<span>CType</span>(e.NewValue, Status)).ToString() &amp; <span>&quot;Png&quot;</span>), BitmapImage)</pre>
<pre><span>  22:</span>     <span>End</span> <span>Sub</span></pre>
<pre><span>  23:</span>&nbsp; </pre>
<pre><span>  24:</span>     <span>Public</span> <span>Property</span> Radius() <span>As</span> <span>Double</span></pre>
<pre><span>  25:</span>         <span>Get</span></pre>
<pre><span>  26:</span>             <span>Return</span> <span>Me</span>.imgStatus.Height / 2</pre>
<pre><span>  27:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  28:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  29:</span>             <span>Me</span>.imgStatus.Width = value * 2</pre>
<pre><span>  30:</span>             <span>Me</span>.imgStatus.Height = <span>Me</span>.imgStatus.Width</pre>
<pre><span>  31:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  32:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  33:</span>&nbsp; </pre>
<pre><span>  34:</span>     <span>Private</span> _vy <span>As</span> <span>Double</span></pre>
<pre><span>  35:</span>     <span>Public</span> <span>Property</span> VY() <span>As</span> <span>Double</span></pre>
<pre><span>  36:</span>         <span>Get</span></pre>
<pre><span>  37:</span>             <span>Return</span> <span>Me</span>._vy</pre>
<pre><span>  38:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  39:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  40:</span>             <span>Me</span>._vy = value</pre>
<pre><span>  41:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  42:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  43:</span>&nbsp; </pre>
<pre><span>  44:</span>     <span>Private</span> _vx <span>As</span> <span>Double</span></pre>
<pre><span>  45:</span>     <span>Public</span> <span>Property</span> VX() <span>As</span> <span>Double</span></pre>
<pre><span>  46:</span>         <span>Get</span></pre>
<pre><span>  47:</span>             <span>Return</span> <span>Me</span>._vx</pre>
<pre><span>  48:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  49:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  50:</span>             <span>Me</span>._vx = value</pre>
<pre><span>  51:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  52:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  53:</span>&nbsp; </pre>
<pre><span>  54:</span>     <span>Private</span> _mass <span>As</span> <span>Double</span></pre>
<pre><span>  55:</span>     <span>Public</span> <span>Property</span> Mass() <span>As</span> <span>Double</span></pre>
<pre><span>  56:</span>         <span>Get</span></pre>
<pre><span>  57:</span>             <span>Return</span> <span>Me</span>._mass</pre>
<pre><span>  58:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  59:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  60:</span>             <span>Me</span>._mass = value</pre>
<pre><span>  61:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  62:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  63:</span>&nbsp; </pre>
<pre><span>  64:</span>     <span>Private</span> _x <span>As</span> <span>Double</span></pre>
<pre><span>  65:</span>     <span>Public</span> <span>Property</span> X() <span>As</span> <span>Double</span></pre>
<pre><span>  66:</span>         <span>Get</span></pre>
<pre><span>  67:</span>             <span>Return</span> <span>Me</span>._x</pre>
<pre><span>  68:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  69:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  70:</span>             <span>Me</span>._x = value</pre>
<pre><span>  71:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  72:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  73:</span>&nbsp; </pre>
<pre><span>  74:</span>     <span>Private</span> _y <span>As</span> <span>Double</span></pre>
<pre><span>  75:</span>     <span>Public</span> <span>Property</span> Y() <span>As</span> <span>Double</span></pre>
<pre><span>  76:</span>         <span>Get</span></pre>
<pre><span>  77:</span>             <span>Return</span> <span>Me</span>._y</pre>
<pre><span>  78:</span>         <span>End</span> <span>Get</span></pre>
<pre><span>  79:</span>         <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Double</span>)</pre>
<pre><span>  80:</span>             <span>Me</span>._y = value</pre>
<pre><span>  81:</span>         <span>End</span> <span>Set</span></pre>
<pre><span>  82:</span>     <span>End</span> <span>Property</span></pre>
<pre><span>  83:</span>&nbsp; </pre>
<pre><span>  84:</span> <span>End</span> <span>Class</span></pre>
<pre><span>  85:</span>&nbsp; </pre>
<pre><span>  86:</span>&nbsp; </pre>
</div>
</div>
<p>Once I had the particle class created, I decided to use a variation of a spring physics equation to get the desired float animation. The spring equation forces the particles toward each other and then springs them past each other similar to how a ball on
 the end of a rubber band would act when pulling it and letting it spring back and forth. Then by tweaking the force and velocity applied to each particle I successfully simulated a floating effect (I am by no means a physicist and I am sure there is a better
 way of implementing this equation). By combining the CompositionTarget.Rendering event and the positioning logic we can effectively scatter and animate the particles on our Canvas. The math involved looks something like this:</p>
<h6></h6>
C#
<div>
<div>
<pre><span>   1:</span> <span>void</span> Spring(Particle a, Particle b)</pre>
<pre><span>   2:</span>         {</pre>
<pre><span>   3:</span> <span>double</span> dx = b.X - a.X;</pre>
<pre><span>   4:</span> <span>double</span> dy = b.Y - a.Y;</pre>
<pre><span>   5:</span>&nbsp; </pre>
<pre><span>   6:</span> <span>double</span> dist = Math.Sqrt(dx * dx &#43; dy * dy);</pre>
<pre><span>   7:</span> <span>if</span> (dist &lt; _minDist)</pre>
<pre><span>   8:</span>             {</pre>
<pre><span>   9:</span> <span>double</span> ax = dx * _spring;</pre>
<pre><span>  10:</span> <span>double</span> ay = dy * _spring;</pre>
<pre><span>  11:</span>&nbsp; </pre>
<pre><span>  12:</span>                 a.VX &#43;= ax;</pre>
<pre><span>  13:</span>                 a.VY &#43;= ay;</pre>
<pre><span>  14:</span>&nbsp; </pre>
<pre><span>  15:</span>                 b.VX -= ax;</pre>
<pre><span>  16:</span>                 b.VY -= ay;</pre>
<pre><span>  17:</span>&nbsp; </pre>
<pre><span>  18:</span> Canvas.SetLeft(a, a.X);</pre>
<pre><span>  19:</span> Canvas.SetTop(a, a.Y);</pre>
<pre><span>  20:</span>&nbsp; </pre>
<pre><span>  21:</span> Canvas.SetLeft(b, b.X);</pre>
<pre><span>  22:</span> Canvas.SetTop(b, b.Y);</pre>
<pre><span>  23:</span>&nbsp; </pre>
<pre><span>  24:</span>&nbsp; </pre>
<pre><span>  25:</span>             }</pre>
<pre><span>  26:</span>&nbsp; </pre>
<pre><span>  27:</span> Canvas.SetLeft(a, a.X);</pre>
<pre><span>  28:</span> Canvas.SetTop(a, a.Y);</pre>
<pre><span>  29:</span>&nbsp; </pre>
<pre><span>  30:</span> Canvas.SetLeft(b, b.X);</pre>
<pre><span>  31:</span> Canvas.SetTop(b, b.Y);</pre>
<pre><span>  32:</span>&nbsp; </pre>
<pre><span>  33:</span>&nbsp; </pre>
<pre><span>  34:</span>         }</pre>
<pre><span>  35:</span>&nbsp; </pre>
<pre><span>  36:</span> VB:</pre>
<pre><span>  37:</span> PrivateSub Spring(ByVal a As Particle, ByVal b As Particle)</pre>
<pre><span>  38:</span> Dim dx AsDouble = b.X - a.X</pre>
<pre><span>  39:</span> Dim dy AsDouble = b.Y - a.Y</pre>
<pre><span>  40:</span>&nbsp; </pre>
<pre><span>  41:</span> Dim dist AsDouble = Math.Sqrt(dx * dx &#43; dy * dy)</pre>
<pre><span>  42:</span> If dist &lt; _minDist Then</pre>
<pre><span>  43:</span> Dim ax AsDouble = dx * _spring</pre>
<pre><span>  44:</span> Dim ay AsDouble = dy * _spring</pre>
<pre><span>  45:</span>&nbsp; </pre>
<pre><span>  46:</span>             a.VX &#43;= ax</pre>
<pre><span>  47:</span>             a.VY &#43;= ay</pre>
<pre><span>  48:</span>&nbsp; </pre>
<pre><span>  49:</span>             b.VX -= ax</pre>
<pre><span>  50:</span>             b.VY -= ay</pre>
<pre><span>  51:</span>&nbsp; </pre>
<pre><span>  52:</span>             Canvas.SetLeft(a, a.X)</pre>
<pre><span>  53:</span>             Canvas.SetTop(a, a.Y)</pre>
<pre><span>  54:</span>&nbsp; </pre>
<pre><span>  55:</span>             Canvas.SetLeft(b, b.X)</pre>
<pre><span>  56:</span>             Canvas.SetTop(b, b.Y)</pre>
<pre><span>  57:</span>&nbsp; </pre>
<pre><span>  58:</span>&nbsp; </pre>
<pre><span>  59:</span> EndIf</pre>
<pre><span>  60:</span>&nbsp; </pre>
<pre><span>  61:</span>         Canvas.SetLeft(a, a.X)</pre>
<pre><span>  62:</span>         Canvas.SetTop(a, a.Y)</pre>
<pre><span>  63:</span>&nbsp; </pre>
<pre><span>  64:</span>         Canvas.SetLeft(b, b.X)</pre>
<pre><span>  65:</span>         Canvas.SetTop(b, b.Y)</pre>
<pre><span>  66:</span>&nbsp; </pre>
<pre><span>  67:</span>&nbsp; </pre>
<pre><span>  68:</span> EndSub</pre>
<pre><span>  69:</span>&nbsp; </pre>
<pre><span>  70:</span> And the main animation loop looks like <span>this</span>:</pre>
<pre><span>  71:</span>&nbsp; </pre>
<pre><span>  72:</span> C#:</pre>
<pre><span>  73:</span> <span>void</span> CompositionTarget_Rendering(<span>object</span> sender, EventArgs e)</pre>
<pre><span>  74:</span>         {</pre>
<pre><span>  75:</span> <span>for</span> (<span>int</span> i = 0; i &lt; _numParticles; i&#43;&#43;)</pre>
<pre><span>  76:</span>             {</pre>
<pre><span>  77:</span>                 _particles[i].X &#43;= _particles[i].VX;</pre>
<pre><span>  78:</span>                 _particles[i].Y &#43;= _particles[i].VY;</pre>
<pre><span>  79:</span>&nbsp; </pre>
<pre><span>  80:</span> Particle p = _particles[i];</pre>
<pre><span>  81:</span>&nbsp; </pre>
<pre><span>  82:</span> <span>if</span> (p.X &gt;<span>this</span>.Width)</pre>
<pre><span>  83:</span>                 {</pre>
<pre><span>  84:</span>                     p.X = 0;</pre>
<pre><span>  85:</span>                 }</pre>
<pre><span>  86:</span>&nbsp; </pre>
<pre><span>  87:</span> elseif (p.X &lt; 0)</pre>
<pre><span>  88:</span>                 {</pre>
<pre><span>  89:</span>                     p.X = <span>this</span>.Width;</pre>
<pre><span>  90:</span>                 }</pre>
<pre><span>  91:</span>&nbsp; </pre>
<pre><span>  92:</span> <span>if</span> (p.Y &gt;<span>this</span>.Height)</pre>
<pre><span>  93:</span>                 {</pre>
<pre><span>  94:</span>                     p.Y = 0;</pre>
<pre><span>  95:</span>                 }</pre>
<pre><span>  96:</span> elseif (p.Y &lt; 0)</pre>
<pre><span>  97:</span>                 {</pre>
<pre><span>  98:</span>                     p.Y = <span>this</span>.Height;</pre>
<pre><span>  99:</span>                 }</pre>
<pre><span> 100:</span>             }</pre>
<pre><span> 101:</span>&nbsp; </pre>
<pre><span> 102:</span>&nbsp; </pre>
<pre><span> 103:</span> <span>for</span> (<span>int</span> i = 0; i &lt; _numParticles - 1; i&#43;&#43;)</pre>
<pre><span> 104:</span>             {</pre>
<pre><span> 105:</span> var partA = _particles[i];</pre>
<pre><span> 106:</span> <span>for</span> (<span>int</span> j = i &#43; 1; j &lt; _numParticles; j&#43;&#43;)</pre>
<pre><span> 107:</span>                 {</pre>
<pre><span> 108:</span> var partB = _particles[j];</pre>
<pre><span> 109:</span>                     Spring(partA, partB);</pre>
<pre><span> 110:</span>&nbsp; </pre>
<pre><span> 111:</span>                 }</pre>
<pre><span> 112:</span>             }</pre>
<pre><span> 113:</span>         }</pre>
</div>
</div>
<p>VB</p>
<div>
<div>
<pre><span>   1:</span> Sub CompositionTarget_Rendering(ByVal sender As System.Object, ByVal e As System.EventArgs)</pre>
<pre><span>   2:</span> For i AsInteger = 0 To _numParticles - 1</pre>
<pre><span>   3:</span>             _particles(i).X &#43;= _particles(i).VX</pre>
<pre><span>   4:</span>             _particles(i).Y &#43;= _particles(i).VY</pre>
<pre><span>   5:</span>&nbsp; </pre>
<pre><span>   6:</span> Dim p As Particle = _particles(i)</pre>
<pre><span>   7:</span>&nbsp; </pre>
<pre><span>   8:</span> If p.X &gt;Me.Width Then</pre>
<pre><span>   9:</span>                 p.X = 0</pre>
<pre><span>  10:</span>&nbsp; </pre>
<pre><span>  11:</span> ElseIf p.X &lt; 0 Then</pre>
<pre><span>  12:</span>                 p.X = Me.Width</pre>
<pre><span>  13:</span> EndIf</pre>
<pre><span>  14:</span>&nbsp; </pre>
<pre><span>  15:</span> If p.Y &gt;Me.Height Then</pre>
<pre><span>  16:</span>                 p.Y = 0</pre>
<pre><span>  17:</span> ElseIf p.Y &lt; 0 Then</pre>
<pre><span>  18:</span>                 p.Y = Me.Height</pre>
<pre><span>  19:</span> EndIf</pre>
<pre><span>  20:</span> Next i</pre>
<pre><span>  21:</span>&nbsp; </pre>
<pre><span>  22:</span>&nbsp; </pre>
<pre><span>  23:</span> For i AsInteger = 0 To _numParticles - 2</pre>
<pre><span>  24:</span> Dim partA = _particles(i)</pre>
<pre><span>  25:</span> For j AsInteger = i &#43; 1 To _numParticles - 1</pre>
<pre><span>  26:</span> Dim partB = _particles(j)</pre>
<pre><span>  27:</span>                 Spring(partA, partB)</pre>
<pre><span>  28:</span>&nbsp; </pre>
<pre><span>  29:</span> Next j</pre>
<pre><span>  30:</span> Next</pre>
<pre><span>  31:</span>&nbsp; </pre>
<pre><span>  32:</span> EndSub</pre>
<pre><span>  33:</span>&nbsp; </pre>
</div>
</div>
<h4>&nbsp;</h4>
<h4>Supporting Multiple Monitors</h4>
<p>After the animation was rendering correctly the next step was getting it to run on multiple monitors. To make this happen I wrote some code in the application entry point to get a handle to the active screens. The System.Windows.Forms namespace has a Screen
 class which contains a collection of screens and their attributes including working area, width, and height. By looping through the screen collection I measure the screen boundaries and set the window size dynamically based on the available screen real estate.</p>
<p>C#</p>
<div>
<div>
<pre><span>   1:</span> <span>private</span> <span>void</span> Application_Startup(<span>object</span> sender, StartupEventArgs e)</pre>
<pre><span>   2:</span>         {</pre>
<pre><span>   3:</span>&nbsp; </pre>
<pre><span>   4:</span> Window1 _window = <span>null</span>;</pre>
<pre><span>   5:</span>&nbsp; </pre>
<pre><span>   6:</span>             System.Windows.Forms.Cursor.Hide();</pre>
<pre><span>   7:</span>&nbsp; </pre>
<pre><span>   8:</span> <span>foreach</span> (Screen screen inScreen.AllScreens)</pre>
<pre><span>   9:</span>             {</pre>
<pre><span>  10:</span> <span>if</span> (screen.Primary)</pre>
<pre><span>  11:</span>                 {</pre>
<pre><span>  12:</span> Rectangle location = screen.Bounds;</pre>
<pre><span>  13:</span>                     _window = newWindow1(location.Height, location.Width);</pre>
<pre><span>  14:</span>                     _window.Width = location.Width;</pre>
<pre><span>  15:</span>                     _window.Height = location.Height;</pre>
<pre><span>  16:</span>                     _window.Left = 0;</pre>
<pre><span>  17:</span>                     _window.Top = 0;</pre>
<pre><span>  18:</span>                     _window.WindowState = WindowState.Maximized;</pre>
<pre><span>  19:</span>                     _window.Show();</pre>
<pre><span>  20:</span>                 }</pre>
<pre><span>  21:</span>&nbsp; </pre>
<pre><span>  22:</span> elseif (!screen.Primary)</pre>
<pre><span>  23:</span>                 {</pre>
<pre><span>  24:</span>&nbsp; </pre>
<pre><span>  25:</span> Rectangle location = screen.Bounds;</pre>
<pre><span>  26:</span>                     _window = newWindow1(location.Height, location.Width);</pre>
<pre><span>  27:</span>                     _window.Left = screen.WorkingArea.Left;</pre>
<pre><span>  28:</span>                     _window.Top = screen.WorkingArea.Top;</pre>
<pre><span>  29:</span>                     _window.Width = location.Width;</pre>
<pre><span>  30:</span>                     _window.Height = location.Height;</pre>
<pre><span>  31:</span>                     _window.Show();</pre>
<pre><span>  32:</span>                 }</pre>
<pre><span>  33:</span>&nbsp; </pre>
<pre><span>  34:</span>             }</pre>
<pre><span>  35:</span>&nbsp; </pre>
<pre><span>  36:</span>         }</pre>
</div>
</div>
<p>VB</p>
<div>
<div>
<pre><span>   1:</span> <span>private</span> void Application_Startup(<span>object</span> sender, StartupEventArgs e)</pre>
<pre><span>   2:</span>         {</pre>
<pre><span>   3:</span>&nbsp; </pre>
<pre><span>   4:</span> Window1 _window = null;</pre>
<pre><span>   5:</span>&nbsp; </pre>
<pre><span>   6:</span>             System.Windows.Forms.Cursor.Hide();</pre>
<pre><span>   7:</span>&nbsp; </pre>
<pre><span>   8:</span> foreach (Screen screen inScreen.AllScreens)</pre>
<pre><span>   9:</span>             {</pre>
<pre><span>  10:</span> <span>if</span> (screen.Primary)</pre>
<pre><span>  11:</span>                 {</pre>
<pre><span>  12:</span> Rectangle location = screen.Bounds;</pre>
<pre><span>  13:</span>                     _window = newWindow1(location.Height, location.Width);</pre>
<pre><span>  14:</span>                     _window.Width = location.Width;</pre>
<pre><span>  15:</span>                     _window.Height = location.Height;</pre>
<pre><span>  16:</span>                     _window.Left = 0;</pre>
<pre><span>  17:</span>                     _window.Top = 0;</pre>
<pre><span>  18:</span>                     _window.WindowState = WindowState.Maximized;</pre>
<pre><span>  19:</span>                     _window.Show();</pre>
<pre><span>  20:</span>                 }</pre>
<pre><span>  21:</span>&nbsp; </pre>
<pre><span>  22:</span> <span>elseif</span> (!screen.Primary)</pre>
<pre><span>  23:</span>                 {</pre>
<pre><span>  24:</span>&nbsp; </pre>
<pre><span>  25:</span> Rectangle location = screen.Bounds;</pre>
<pre><span>  26:</span>                     _window = newWindow1(location.Height, location.Width);</pre>
<pre><span>  27:</span>                     _window.Left = screen.WorkingArea.Left;</pre>
<pre><span>  28:</span>                     _window.Top = screen.WorkingArea.Top;</pre>
<pre><span>  29:</span>                     _window.Width = location.Width;</pre>
<pre><span>  30:</span>                     _window.Height = location.Height;</pre>
<pre><span>  31:</span>                     _window.Show();</pre>
<pre><span>  32:</span>                 }</pre>
<pre><span>  33:</span>&nbsp; </pre>
<pre><span>  34:</span>             }</pre>
<pre><span>  35:</span>&nbsp; </pre>
<pre><span>  36:</span>         }</pre>
</div>
</div>
<h4></h4>
<h4></h4>
<h4>Making it a Screen Saver</h4>
<p>The last step to this application is making it a screen saver. By implementing mouse and keyboard event handlers to shut down the application we essentially can mimic the interaction of a screen saver.
</p>
<p>C#</p>
<div>
<div>
<pre><span>   1:</span> MouseMove &#43;= newMouseEventHandler(Window2_MouseMove);</pre>
<pre><span>   2:</span>   MouseDown &#43;= newMouseButtonEventHandler(Window2_MouseDown);</pre>
<pre><span>   3:</span>   KeyDown &#43;= newKeyEventHandler(Window2_KeyDown);</pre>
<pre><span>   4:</span> <span>void</span> Window2_KeyDown(<span>object</span> sender, KeyEventArgs e)</pre>
<pre><span>   5:</span>         {</pre>
<pre><span>   6:</span> Application.Current.Shutdown();</pre>
<pre><span>   7:</span>         }</pre>
<pre><span>   8:</span>&nbsp; </pre>
<pre><span>   9:</span> <span>void</span> Window2_MouseDown(<span>object</span> sender, MouseButtonEventArgs e)</pre>
<pre><span>  10:</span>         {</pre>
<pre><span>  11:</span> Application.Current.Shutdown();</pre>
<pre><span>  12:</span>         }</pre>
<pre><span>  13:</span>&nbsp; </pre>
<pre><span>  14:</span> <span>void</span> Window2_MouseMove(<span>object</span> sender, MouseEventArgs e)</pre>
<pre><span>  15:</span>         {</pre>
<pre><span>  16:</span> Point currentPosition = e.MouseDevice.GetPosition(<span>this</span>);</pre>
<pre><span>  17:</span>&nbsp; </pre>
<pre><span>  18:</span> <span>if</span> (!isActive)</pre>
<pre><span>  19:</span>             {</pre>
<pre><span>  20:</span>                 mousePosition = currentPosition;</pre>
<pre><span>  21:</span>                 isActive = <span>true</span>;</pre>
<pre><span>  22:</span>             }</pre>
<pre><span>  23:</span> <span>else</span></pre>
<pre><span>  24:</span>             {</pre>
<pre><span>  25:</span>&nbsp; </pre>
<pre><span>  26:</span> <span>if</span> ((Math.Abs(mousePosition.X - currentPosition.X) &gt; 10) ||</pre>
<pre><span>  27:</span>                     (Math.Abs(mousePosition.Y - currentPosition.Y) &gt; 10))</pre>
<pre><span>  28:</span>                 {</pre>
<pre><span>  29:</span> Application.Current.Shutdown();</pre>
<pre><span>  30:</span>                 }</pre>
<pre><span>  31:</span>             }</pre>
<pre><span>  32:</span>         }</pre>
</div>
</div>
<p>VB</p>
<div>
<div>
<pre><span>   1:</span> AddHandlerMe.MouseMove, <span>AddressOf</span> Window_MouseMove</pre>
<pre><span>   2:</span> AddHandlerMe.MouseDown, <span>AddressOf</span> Window_MouseDown</pre>
<pre><span>   3:</span> AddHandlerMe.KeyDown, <span>AddressOf</span> Window_KeyDown</pre>
<pre><span>   4:</span>&nbsp; </pre>
<pre><span>   5:</span> PrivateSub Window_KeyDown(<span>ByVal</span> sender AsObject, <span>ByVal</span> e <span>As</span> KeyEventArgs)</pre>
<pre><span>   6:</span>         Application.Current.Shutdown()</pre>
<pre><span>   7:</span> EndSub</pre>
<pre><span>   8:</span>&nbsp; </pre>
<pre><span>   9:</span> PrivateSub Window_MouseDown(<span>ByVal</span> sender AsObject, <span>ByVal</span> e <span>As</span> MouseButtonEventArgs)</pre>
<pre><span>  10:</span>         Application.Current.Shutdown()</pre>
<pre><span>  11:</span> EndSub</pre>
<pre><span>  12:</span>&nbsp; </pre>
<pre><span>  13:</span> PrivateSub Window_MouseMove(<span>ByVal</span> sender AsObject, <span>ByVal</span> e <span>As</span> MouseEventArgs)</pre>
<pre><span>  14:</span> <span>Dim</span> currentPosition <span>As</span> Point = e.MouseDevice.GetPosition(<span>Me</span>)</pre>
<pre><span>  15:</span> <span>If</span> (<span>Not</span> isActive) <span>Then</span></pre>
<pre><span>  16:</span>             mousePosition = currentPosition</pre>
<pre><span>  17:</span>             isActive = <span>True</span></pre>
<pre><span>  18:</span> <span>Else</span></pre>
<pre><span>  19:</span> <span>If</span> (Math.Abs(mousePosition.X - currentPosition.X) &gt; 10) <span>OrElse</span> (Math.Abs(mousePosition.Y - currentPosition.Y) &gt; 10) <span>Then</span></pre>
<pre><span>  20:</span>                 Application.Current.Shutdown()</pre>
<pre><span>  21:</span> <span>EndIf</span></pre>
<pre><span>  22:</span> <span>EndIf</span></pre>
<pre><span>  23:</span> EndSub</pre>
<pre><span>  24:</span>&nbsp; </pre>
</div>
</div>
<p>Lastly, simply set the build configuration to Release mode and build it. In the output bin-&gt;Release directory find the built executable. Rename the file extension from .exe to .scr then right click and choose
<b>Install</b> from the context menu.</p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image008.jpg"><img title="clip_image008" border="0" alt="clip_image008" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image008_thumb.jpg" width="423" height="319"></a></p>
<p align="center"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image010.jpg"><img title="clip_image010" border="0" alt="clip_image010" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/8626294/clip_image010_thumb.jpg" width="413" height="217"></a></p>
<p>That's it! </p>
<h4>Challenges to You</h4>
<p>One of the interesting things about Office Communicator Server is that it comes with an SDK to build your own custom Unified Communications applications.</p>
<ul>
<li>I would love to see the presence bubbles actually hooked up to real users' status, and maybe a cool animation to indicate when a users' status is changed.
</li><li>Create a config file to let the user specify his/her own images and tweak other settings like speed and velocity.&nbsp;
</li></ul>
<h4>Conclusion</h4>
<p>This was a great opportunity to brush up on my physics skills and play with some of the animation possibilities in WPF. This application is also a great example of alternative data visualization. Sometimes I get tired of seeing everything in tabular form
 and I think that “presence art” is a great example of Art &#43; Code (aesthetically pleasing and functional). I hope you enjoy it.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:19ddc2e88de5497fb0669e7600cf331e">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/WPF-Custom-Screen-Saver-Art</comments>
      <itunes:summary>
Summary
Creating custom
 wallpaper is easy. But what about custom screen savers? This post will detail how to build a custom saver using Windows Presentation Framework (WPF). The posted code also provides some insight on how to create interesting particle effects using WPF&#39;s animation
 engine, and how to implement multiple monitor support in .Net. 
Erik Klimczak - Clarity Consulting 
Download

http://wpfscreensaverart.codeplex.com/&amp;nbsp;&amp;nbsp;

Introduction
Microsoft Unified Communications (UC) is a new technology that has been getting a lot of hype in the past couple of months. UC is essentially the integration of messaging, voice, and video across the
 applications and devices that people use every day. More information about UC can be found
here. One of the coolest things about UC is the concept of “presence” (see below). The Presence indicator effectively allows the user to reflect his/her status in other Office Communicator Server friendly
 applications (i.e. Outlook, Office communicator, Live Meeting, etc.) 
 
While building out some communicator functionality on another project I found myself recreating the presence “bubbles” in xaml so that they could scale without losing quality (see below). I used Expression Design to re-create the presence bubbles and export
 then to xaml. 
In doing so it occurred to me that the presence “bubbles” would make for some excellent art sprites.
 
&amp;nbsp; 
So after a hop-skip-and a jump to Photoshop I found myself with a shiny new “presence art” wallpaper. 
 
Immediately after creating the wallpaper I thought to myself, “this would also make a great screen saver”. This article will attempt to show how to build a custom WPF screen saver that implements a simple physics particle effect using the WPF animation engine. 
Particle Animation
With my graphic designer hat on I knew that I wanted to create a floating particle effect. Particle effects can be used to simulate anything from rain, snow, fire to bubbles and clouds. Then by va</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/WPF-Custom-Screen-Saver-Art</link>
      <pubDate>Fri, 20 Jun 2008 15:24:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/WPF-Custom-Screen-Saver-Art</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8626294_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/8626294_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Erik Klimczak </dc:creator>
      <itunes:author>Erik Klimczak </itunes:author>
      <slash:comments>12</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/WPF-Custom-Screen-Saver-Art/RSS</wfw:commentRss>
      <category>Windows</category>
      <category>windows miscellaneous</category>
    </item>
  <item>
      <title>YeahTrivia: Creating a Trivia Server/Client with WPF and WCF</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50"><img height="50" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/yeahtriviathumb.gif" width="50"></td>
<td class=""><span class="entry_description">In this article I'll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication
 Foundation (WCF). Afterwards, you'll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&nbsp;
<em>And in honor of Halloween, I've included three games of horror movie trivia.</em></span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Steve Holstad</div>
<div class="entry_company"><a href="http://blogs.claritycon.com/blogs/steve_holstad/archive/2007/10/29/3403.aspx" target="_blank">The Bright Lights</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Advanced</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
6-10 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input">Visual Studio Express, 2005, 2008 Beta 2
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en">
Microsoft .NET Framework 3.0</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b><a class="" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia.zip" target="_blank">Download Source</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>&nbsp;</p>
<h3>What can YeahTrivia do for me?</h3>
<p>Glad you asked. This project started when I decided I wanted to dive headfirst into learning WPF and WCF, without hacking through countless Hello World examples.&nbsp; And I wanted something fun that I could improve over time as my skills developed in these new
 technologies.&nbsp; In this article I'll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication Foundation (WCF).
 Afterwards, you'll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&nbsp; And in honor of Halloween, I've included three games of horror movie trivia.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia_Client5.jpg"><img height="194" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia_Client_thumb1.jpg" width="280" border="0"></a>
</p>
<p>In case you were wondering, the &quot;YeahTrivia&quot; name honors my new bride&nbsp;&amp; her&nbsp;favorite prefix.&nbsp; Think of it as&nbsp;YeeeeaaaaahhTrivia!</p>
<h3>Basic Setup</h3>
<p>This demo project was built using Visual Studio 2008 Beta 2, and is based on the Microsoft .NET Framework version 3.0.&nbsp; The game is fed by a small windows app that acts as a game server, providing game selection, user&nbsp;registration, question loading, response
 times, chat messaging&nbsp;and scorekeeping.&nbsp; The server loads a game by reading a predefined XML format, which we will look at a bit later.&nbsp; This dynamic load lets anyone create their own flavor of trivia game, with any number of questions.</p>
<p>The server app exposes one WCF endpoint, a wsDualHttpBinding channel that supports duplex (two-way) communication between the server and any number of game clients.&nbsp; Clients attach themselves to this endpoint and provide a callback address to the server.&nbsp;
 The server saves an instance of this callback channel and uses each client's instance to&nbsp;contact the clients en masse during general game flow.&nbsp; Enough talk, here's how to build one yourself.</p>
<h3>Trivia Common and WCF Service Interfaces</h3>
<p>The TriviaCommon project provides both the server and client projects access to shared objects.&nbsp; To keep things simple the Common project only contains two classes:</p>
<p>Constants.cs defines the AnswerItem enumeration, which gives easy access to the five answer options (None, A, B, C, D), and the QuestionItem struct.&nbsp; This structure is delivered to the client and contains question text, answer text, and the correct answer
 object of type AnswerItem.&nbsp; Notice that objects being directly passed over the wire need to be marked with the [DataContract] attribute.</p>
<p>The second class, Interfaces.cs is where our WCF fun begins.&nbsp; Take a look:</p>
<strong>C#:</strong><br>
<pre class="csharpcode"><span class="kwrd">using</span> System;
<span class="kwrd">using</span> System.Collections.Generic;
<span class="kwrd">using</span> System.ServiceModel;
<span class="kwrd">using</span> System.Text;

<span class="kwrd">namespace</span> Trivia.Common
{
    <span class="preproc">#region</span> Interfaces

    <span class="preproc">#region</span> Service Interface

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// Interface that defines Trivia service contract.</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    [ServiceContract(CallbackContract = <span class="kwrd">typeof</span>(ITriviaCallback))]
    <span class="kwrd">public</span> <span class="kwrd">interface</span> ITrivia
    {
        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> RegisterUser(<span class="kwrd">string</span> userName);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> AcceptAnswer(<span class="kwrd">string</span> userName, <span class="kwrd">string</span> answerValue);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> ChatPublish(<span class="kwrd">string</span> userName, <span class="kwrd">string</span> message);
    }

    <span class="preproc">#endregion</span> Service Interface

    <span class="preproc">#region</span> Client Callback Interface

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// Interface that defines Trivia client callback contract.</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    <span class="kwrd">public</span> <span class="kwrd">interface</span> ITriviaCallback
    {        
        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnGameStart(<span class="kwrd">int</span> questionCount);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnGameEnd();

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnUserRegistered(<span class="kwrd">string</span> userName);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnPublishChat(<span class="kwrd">string</span> userName, <span class="kwrd">string</span> chatMessage);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnQuestionLoad(<span class="kwrd">int</span> questionIndex, QuestionItem questionItem);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnQuestionEnd();

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnQuestionStatusUpdate(Int64 questionTimeRemaining);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnScoreboardUpdate(Dictionary&lt;<span class="kwrd">string</span>, Int64&gt; scoreboard);

        [OperationContract(IsOneWay = <span class="kwrd">true</span>)]
        <span class="kwrd">void</span> OnGameServerStopped();
    }

    <span class="preproc">#endregion</span> Client Callback Interface

    <span class="preproc">#endregion</span> Interfaces
}
</pre>
<pre class="csharpcode"></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>VB:</strong></p>
<pre class="csharpcode"><span class="kwrd">Imports</span> System
<span class="kwrd">Imports</span> System.Collections.Generic
<span class="kwrd">Imports</span> System.ServiceModel
<span class="kwrd">Imports</span> System.Text

<span class="kwrd">Namespace</span> Trivia.Common

<span class="preproc">#Region</span> <span class="str">&quot;Interfaces&quot;</span>

<span class="preproc">#Region</span> <span class="str">&quot;Service Interface&quot;</span>
    
    <span class="rem">''' &lt;summary&gt;</span>
    <span class="rem">''' Interface that defines Trivia service contract.</span>
    <span class="rem">''' &lt;/summary&gt;</span>
    &lt;ServiceContract(CallbackContract:=<span class="kwrd">GetType</span>(ITriviaCallback))&gt; _
    <span class="kwrd">Public</span> <span class="kwrd">Interface</span> ITrivia
        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> RegisterUser(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> AcceptAnswer(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> answerValue <span class="kwrd">As</span> <span class="kwrd">String</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> ChatPublish(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> message <span class="kwrd">As</span> <span class="kwrd">String</span>)
    <span class="kwrd">End</span> <span class="kwrd">Interface</span>
        
<span class="preproc">#End Region</span>

<span class="preproc">#Region</span> <span class="str">&quot;Client Callback Interface&quot;</span>

    <span class="rem">''' &lt;summary&gt;</span>
    <span class="rem">''' Interface that defines Trivia client callback contract.</span>
    <span class="rem">''' &lt;/summary&gt;</span>
    <span class="rem">''' &lt;remarks&gt;&lt;/remarks&gt;</span>
    <span class="kwrd">Public</span> <span class="kwrd">Interface</span> ITriviaCallback
        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
      <span class="kwrd">Sub</span> OnGameStart(<span class="kwrd">ByVal</span> questionCount <span class="kwrd">As</span> <span class="kwrd">Integer</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnGameEnd()

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnUserRegistered(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnPublishChat(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> chatMessage <span class="kwrd">As</span> <span class="kwrd">String</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnQuestionLoad(<span class="kwrd">ByVal</span> questionIndex <span class="kwrd">As</span> <span class="kwrd">Integer</span>, <span class="kwrd">ByVal</span> questionItem <span class="kwrd">As</span> QuestionItem)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnQuestionEnd()

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnQuestionStatusUpdate(<span class="kwrd">ByVal</span> questionTimeRemaining <span class="kwrd">As</span> <span class="kwrd">Long</span>)

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnScoreboardUpdate(<span class="kwrd">ByVal</span> scoreboard <span class="kwrd">As</span> Dictionary(Of <span class="kwrd">String</span>, <span class="kwrd">Long</span>))

        &lt;OperationContract(IsOneWay:=<span class="kwrd">True</span>)&gt; _
        <span class="kwrd">Sub</span> OnGameServerStopped()

    <span class="kwrd">End</span> <span class="kwrd">Interface</span>

<span class="preproc">#End Region</span>

<span class="preproc">#End Region</span>

<span class="kwrd">End</span> <span class="kwrd">Namespace</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>A few items of interest here.&nbsp; Notice we're importing the System.ServiceModel namespace.&nbsp; This is the key assembly when using WCF, so don't forget to add a reference to your project.&nbsp; The first interface, ITrivia, defines the operations the server is required
 to implement, which handle basic user actions: Register a team, accept an answer and accept a chat message.&nbsp; Easy.</p>
<p>The second interface, cleverly named ITriviaCallback, lays out the callback contract a client must fulfill in order to play nicely with our server.&nbsp; The operations listed here describe events the server will publish.&nbsp; These aren't actual events, but the
 naming convention &quot;OnX...&quot; helps you remember that these are server published activities.</p>
<p>Notice that the [OperationContract] attribute notifies WCF that each method is part of a service contract.&nbsp; The IsOneWay flag gives us &quot;fire-and-forget&quot; behavior (the app shouldn't wait around for a response).&nbsp; So now that the common objects are ready, let's
 move on to...</p>
<h3>Building the Trivia Server</h3>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia_Server1.jpg"><img height="202" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia_Server.jpg" width="240" border="0"></a>
</p>
<p>The YeahTrivia Server is a simple utility app, but don't let&nbsp;the plain looks fool you; I thought about calling this the BrainStumper Pumper, but this is a family site.&nbsp; This app&nbsp;lets a user (anyone acting as game admin)&nbsp;start the service, select the desired
 game, await team registrations, and then start the game.&nbsp; If this were to become a larger scale project, I would make this an IIS hosted service that manages multiple games and provides more autonomy.&nbsp; Until those sports bar royalty checks start rolling in,
 however, a utility app will do just fine.</p>
<p>The only form, GameServerDashboard, simply provides user interaction with the GameServer class.&nbsp; On startup, the form&nbsp;inits an instance of GameServer and tells it to start the service.&nbsp; It also loads all trivia question sets from the Games directory, and
 displays them in the list.</p>
<p>GameServer is the brain behind YeahTrivia.&nbsp;The attributes below set up the GameServer for action:</p>
<p><strong>C#:</strong><br>
</p>
<pre class="csharpcode">[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant
        ,InstanceContextMode = InstanceContextMode.Single)]
    <span class="kwrd">public</span> <span class="kwrd">class</span> GameServer : ITrivia</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p><strong>VB:</strong><br>
</p>
<pre class="csharpcode">&lt;ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Reentrant, InstanceContextMode:=InstanceContextMode.<span class="kwrd">Single</span>)&gt; _
    <span class="kwrd">Public</span> <span class="kwrd">Class</span> GameServer
        <span class="kwrd">Implements</span> ITrivia</pre>
<pre class="csharpcode"></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>ConcurrencyMode.Reentrant prevents deadlocks between the&nbsp;apps&nbsp;by stating that while this service is single-threaded, callbacks are allowed to invoke&nbsp;new&nbsp;operations.</p>
<p>InstanceContextMode.Single sets the service as a singleton, so that all messages are delivered to the same object instance.</p>
<p>These are advanced topics if you're new to WCF, so I'll include some links at the end that helped clarify some of this for me.&nbsp; Let's keep moving forward by looking at a few activities of the game server:</p>
<p><em>Start the Service:</em>&nbsp; Passes in the configured base address as a Uri, inits and opens a new ServiceHost.</p>
<p><strong>C#:</strong></p>
<blockquote>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> StartService()
{
<span class="rem">   // Set base address and open service host</span>
   Uri baseAddress = <span class="kwrd">new</span> Uri(ConfigurationManager.AppSettings[CONFIG_KEY_BASEURI]);
   _serviceHost = <span class="kwrd">new</span> ServiceHost(<span class="kwrd">new</span> GameServer(), baseAddress);
   _serviceHost.Open();
}</pre>
</blockquote>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>VB:</strong></p>
<pre class="csharpcode">  <span class="kwrd">Public</span> <span class="kwrd">Sub</span> StartService()
     <span class="rem">'Set base address and open service host</span>
     <span class="kwrd">Dim</span> baseAddress <span class="kwrd">As</span> <span class="kwrd">New</span> Uri(ConfigurationManager.AppSettings(CONFIG_KEY_BASEURI))
     _serviceHost = <span class="kwrd">New</span> ServiceHost(<span class="kwrd">New</span> GameServer(), baseAddress)
     _serviceHost.Open()
  <span class="kwrd">End Sub</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><em></em>&nbsp;</p>
<p><em>Register a new team:</em>&nbsp;Saves off the callback, adds it to the callback collection and scoreboard containers, notifies the user of a successful registration, and notifies all game clients of the new team.</p>
<p><strong>C#:</strong></p>
<pre class="csharpcode"> <span class="kwrd">public</span> <span class="kwrd">void</span> RegisterUser(<span class="kwrd">string</span> userName)
 {
     _currentCallback = OperationContext.Current.GetCallbackChannel&lt;ITriviaCallback&gt;();

     <span class="rem">// Store callback</span>
     <span class="kwrd">if</span> (!_callbacks.ContainsKey(userName))
     {
         _callbacks.Add(userName, _currentCallback);
         _scoreboard.Add(userName, 0);
</pre>
<pre class="csharpcode">         <span class="rem">// Notify user of registration</span>
         _currentCallback.OnUserRegistered(userName);
</pre>
<pre class="csharpcode">         <span class="rem">// Notify clients of new user</span>
         <span class="kwrd">foreach</span> (<span class="kwrd">string</span> userKey <span class="kwrd">in</span> _callbacks.Keys)
         {
            _currentCallback = _callbacks[userKey];
            _currentCallback.OnPublishChat(GAME_USERKEY, <span class="kwrd">string</span>.Format(FORMAT_USER_REGISTERED, userName));
         }                
     }
     <span class="kwrd">else</span>
     {
         <span class="rem">// User already registered, throw exception</span>
         <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(ERROR_USER_ALREADY_EXISTS);
     }
 }</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><strong>VB:</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> RegisterUser(<span class="kwrd">ByVal</span> userName <span class="kwrd">As</span> <span class="kwrd">String</span>) <span class="kwrd">Implements</span> ITrivia.RegisterUser
   _currentCallback = OperationContext.Current.GetCallbackChannel(Of ITriviaCallback)()

   <span class="rem">'Store callback</span>
   <span class="kwrd">If</span> <span class="kwrd">Not</span> _callbacks.ContainsKey(userName) <span class="kwrd">Then</span>
      _callbacks.Add(userName, _currentCallback)
      _scoreboard.Add(userName, 0)

      <span class="rem">'Notify user of registration</span>
      _currentCallback.OnUserRegistered(userName)

      <span class="rem">'Notify clients of new user</span>
      <span class="kwrd">For</span> <span class="kwrd">Each</span> userKey <span class="kwrd">As</span> <span class="kwrd">String</span> <span class="kwrd">In</span> _callbacks.Keys
         _currentCallback = _callbacks(userKey)
         _currentCallback.OnPublishChat(GAME_USERKEY, <span class="kwrd">String</span>.Format(FORMAT_USER_REGISTERED, userName))
      <span class="kwrd">Next</span>
   <span class="kwrd">Else</span>
      <span class="rem">'User already registered, throw exception</span>
      <span class="kwrd">Throw</span> <span class="kwrd">New</span> Exception(ERROR_USER_ALREADY_EXISTS)
   <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End Sub</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>You can start to see how the server is able to handle incoming calls and process them back to the clients using the duplex channel.&nbsp; I'll leave the rest of the server actions for you to examine on your own.</p>
<h3>Building the Game Client (WCF) </h3>
<p>Address, Binding, Contract.&nbsp; These are the ABC's of WCF.&nbsp; The client's app.config file handles connecting to the service and specifying the channel and contract used to interact with it.&nbsp; Examine the client portion of the client .config:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">client</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">endpoint</span> <span class="attr">address</span><span class="kwrd">=&quot;http://localhost:8088/Trivia&quot;</span> <span class="attr">binding</span><span class="kwrd">=&quot;wsDualHttpBinding&quot;</span>
      <span class="attr">bindingConfiguration</span><span class="kwrd">=&quot;WSDualHttpBinding_ITrivia&quot;</span> <span class="attr">contract</span><span class="kwrd">=&quot;Trivia.Common.ITrivia&quot;</span>
      <span class="attr">name</span><span class="kwrd">=&quot;WSDualHttpBinding_ITrivia&quot;</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">endpoint</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">client</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The address points to the exposed service endpoint.&nbsp; The binding sets the channel as &quot;wsDualHttpBinding&quot; (our http duplex channel).&nbsp; The bindingConfiguration attribute is an optional&nbsp;pointer to another group of configurations for the binding, and finally,
 the contract sets the interface with which our client will be interacting.</p>
<p>Next it's time to generate a proxy class.&nbsp;&nbsp;Memorize this: Svcutil.exe is your friend.&nbsp; The client needs a proxy class that it can use to interact with the service model.&nbsp; The&nbsp;utility is a bit tricky at first, because of the wealth of optional flags, but
 stick with it, it's better than coding the proxy class by hand!&nbsp; You can generate your client code by starting the service and running a command line similar to this:</p>
<pre class="csharpcode">svcutil /language:cs /out:ServerProxy.cs <a href="http://localhost:8088/Trivia">http://localhost:8088/Trivia</a></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Add the generated class to the client project and you can begin to interact with the service.&nbsp; The svcutil is available as part of the Windows SDK.&nbsp; Check out the referenced site below&nbsp;for more information on this handy utility.</p>
<h3>Building the Game Client (WPF)</h3>
<p>Building the WPF portion of the client app was really a learning experience, and it will&nbsp;be the&nbsp;priority for me to improve in a later version.&nbsp; Learning to program in XAML markup can seem daunting, and it requires a large paradigm shift on your part in order
 to grasp the new concepts.&nbsp;&nbsp;Microsoft Expression is powerful tool for XAML work, but this time I coded all of the XAML by hand in order to fully see what was taking place inside.</p>
<p>A deep discussion of WPF is beyond the scope of this article, but take a look at the example code to get an idea of the layout.&nbsp; An excellent book to start with is
<u>WPF Unleashed</u> by Adam Nathan.&nbsp; An easy read (for a programming book), and solid examples to get you rolling.</p>
<p>I've set up the client using&nbsp;a instance of the Window class, which is shown below:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Window</span> <span class="attr">x:Class</span><span class="kwrd">=&quot;Trivia.Client.GameClient&quot;</span>
    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span>
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span>
    <span class="attr">Title</span><span class="kwrd">=&quot;YeahTrivia&quot;</span> <span class="attr">MinHeight</span><span class="kwrd">=&quot;620&quot;</span> <span class="attr">MinWidth</span><span class="kwrd">=&quot;620&quot;</span> 
    <span class="attr">WindowStartupLocation</span><span class="kwrd">=&quot;CenterScreen&quot;</span> <span class="attr">WindowState</span><span class="kwrd">=&quot;Normal&quot;</span>  <span class="attr">Style</span><span class="kwrd">=&quot;{DynamicResource MainWindowStyle}&quot;</span>
    <span class="attr">Background</span><span class="kwrd">=&quot;{DynamicResource MainWindowBackgroundBrush}&quot;</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The window class sets up the outermost container of the app, and includes two default namespaces.&nbsp; I've also set a few other properties here: a min height and width, window startup location &amp; state, and two styling attributes set by dynamic resources.</p>
<p>Resources are a great way to further separate form &amp; function, allowing a programmer to handle the behavior of an app, while a designer can work simultaneously on the look, all without stepping on too many toes.&nbsp; As a 2.0 task for this project, I would remove
 all inline styling and move them into resource dictionaries.&nbsp; A dictionary contains styles and control templates (a skin) that can be loaded &amp; switched&nbsp;at runtime.</p>
<p>ResourceDictionaries are linked to your XAML in the App.Xaml file.&nbsp; Once you've set up the reference, the&nbsp;example above show&nbsp;how to&nbsp;reference the current dictionary:&nbsp; The Background and Style&nbsp;properties are set as dynamic resources by naming&nbsp;the Keys specified
 in the&nbsp;ResourceDictionary (DefaultResources.xaml):</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">LinearGradientBrush</span> <span class="attr">x:Key</span><span class="kwrd">=&quot;MainWindowBackgroundBrush&quot;</span> <span class="attr">StartPoint</span><span class="kwrd">=&quot;.45,.45&quot;</span> <span class="attr">EndPoint</span><span class="kwrd">=&quot;.55,.55&quot;</span> <span class="attr">SpreadMethod</span><span class="kwrd">=&quot;Reflect&quot;</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">GradientStop</span> <span class="attr">Offset</span><span class="kwrd">=&quot;0&quot;</span> <span class="attr">Color</span><span class="kwrd">=&quot;DodgerBlue&quot;</span><span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">GradientStop</span> <span class="attr">Offset</span><span class="kwrd">=&quot;.8&quot;</span> <span class="attr">Color</span><span class="kwrd">=&quot;DarkSlateBlue&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">LinearGradientBrush</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">Style</span> <span class="attr">TargetType</span><span class="kwrd">=&quot;{x:Type Window}&quot;</span> <span class="attr">x:Key</span><span class="kwrd">=&quot;MainWindowStyle&quot;</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">Setter</span> <span class="attr">Property</span><span class="kwrd">=&quot;FontFamily&quot;</span> <span class="attr">Value</span><span class="kwrd">=&quot;Trebuchet MS&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Style</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Not quite as easy as CSS, but for a Forms project, it's a nice feature.&nbsp; The sample ResourceDictionary includes a button control template for all of my buttons, based on Rob Eisenberg's excellent article (link below).</p>
<p>One other interesting feature to point out: Take a look at the code-behind class MarshalToUIThread method, which accepts a SendOrPostCallback parameter.&nbsp; This is where&nbsp;the client is transferring actions from the sync thread back to the UI thread.&nbsp; In each
 interface method implementation (OnX..), you can see how I wrap any UI-directed code and assign&nbsp;it to the postCallback field.&nbsp; Passing this to the MarshalToUIThread method simply issues a SynchronizationContext.Post call, and the UI thread executes as expected.</p>
<h3>Creating a New Trivia Game (XML)</h3>
<p>New trivia games can be added at any time using&nbsp;the simple XML format shown here.&nbsp; After installing the server application, simply drop the new .XML file into the Games directory ([Server Install Location]\Yeah Trivia Server\Games).&nbsp; This demo comes pre-loaded
 with Geek Trivia, and&nbsp;a special Halloween Trivia version in case you're feeling festive.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">TriviaQuestionDataSet</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://tempuri.org/TriviaQuestionDataSet.xsd&quot;</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">TriviaQuestion</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">QuestionText</span><span class="kwrd">&gt;</span>Name the highest grossing Monty Python creation.<span class="kwrd">&lt;/</span><span class="html">QuestionText</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextA</span><span class="kwrd">&gt;</span>A) Holy Grail<span class="kwrd">&lt;/</span><span class="html">AnswerTextA</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextB</span><span class="kwrd">&gt;</span>B) The Life of Brian<span class="kwrd">&lt;/</span><span class="html">AnswerTextB</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextC</span><span class="kwrd">&gt;</span>C) Shrubbery<span class="kwrd">&lt;/</span><span class="html">AnswerTextC</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextD</span><span class="kwrd">&gt;</span>D) The Meaning of Life<span class="kwrd">&lt;/</span><span class="html">AnswerTextD</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">CorrectAnswerKey</span><span class="kwrd">&gt;</span>A<span class="kwrd">&lt;/</span><span class="html">CorrectAnswerKey</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">TriviaQuestion</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">TriviaQuestion</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">QuestionText</span><span class="kwrd">&gt;</span>Ferris Bueller's best friend was _________.<span class="kwrd">&lt;/</span><span class="html">QuestionText</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextA</span><span class="kwrd">&gt;</span>A) Sloane Peterson<span class="kwrd">&lt;/</span><span class="html">AnswerTextA</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextB</span><span class="kwrd">&gt;</span>B) Edward R. Rooney<span class="kwrd">&lt;/</span><span class="html">AnswerTextB</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextC</span><span class="kwrd">&gt;</span>C) Charlie Sheen<span class="kwrd">&lt;/</span><span class="html">AnswerTextC</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AnswerTextD</span><span class="kwrd">&gt;</span>D) Cameron Frye<span class="kwrd">&lt;/</span><span class="html">AnswerTextD</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">CorrectAnswerKey</span><span class="kwrd">&gt;</span>D<span class="kwrd">&lt;/</span><span class="html">CorrectAnswerKey</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">TriviaQuestion</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">TriviaQuestionDataSet</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3>It's Time to Play YeahTrivia</h3>
<p>Install both the Server and Client applications.&nbsp; First, fire up the server, and then start your game client(s).&nbsp; Once everyone has registered a team, select your game and hit &quot;Start Game&quot;.&nbsp;&nbsp;&nbsp; You're off...</p>
<h3>Game Over</h3>
<p>So there you have it.&nbsp; We've seen&nbsp;how WCF manages communication between objects, extracting complicated service protocols away from your code.&nbsp; And just a&nbsp;small subset of the WPF functionality has shown us&nbsp;how quickly a rich, XAML-based UI can come together.&nbsp;
 And maybe, just maybe, you've learned why a CD is 74 minutes long... but I'm not telling.</p>
<p>I challenge you to improve on this initial version of YeahTrivia:&nbsp; Crack open the XAML and add animations, images, video, music &amp; more.&nbsp;&nbsp;Create a self-maintaining server to run multiple games at once.&nbsp; Add a High Score storage system.&nbsp; Extend the WCF settings
 to enable other communication channels.&nbsp; Add a new skin.&nbsp;Create new question files to share with us.&nbsp;&nbsp;Whatever you do, have fun and&nbsp;go nuts.&nbsp; YeahCoding4Fun.</p>
<p>Download <a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/5773166/YeahTrivia.zip">
source files</a></p>
<p>Download <a href="http://employees.claritycon.com/sholstad/blog/Coding4Fun/YeahTrivia/">
compiled demo (C# and VB)</a></p>
<h3>About The Author</h3>
<p>Steve Holstad works as a software consultant for Clarity Consulting in Chicago.&nbsp; He blogs at
<a href="http://blogs.claritycon.com/blogs/steve_holstad/default.aspx" target="_blank">
The Bright Lights</a>, and is available via email at <a href="mailto:sholstad@claritycon.com">
sholstad@claritycon.com</a></p>
<p>&nbsp;</p>
<h3>References</h3>
<p><a href="http://wcf.netfx3.com/" target="_blank">wcf.netfx3.com/</a><br>
<a href="http://wpf.netfx3.com/" target="_blank">wpf.netfx3.com/</a><br>
<a href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx" target="_blank">Generating a client proxy class</a><br>
<a href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx" target="_blank">ConcurrencyMode</a><br>
<a href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx">SvcUtil.exe Tutorial</a>
<br>
<a href="http://devlicio.us/blogs/rob_eisenberg/archive/2006/12/03/net-3-0-crash-course-part-6-wpf-styles-and-control-templates.aspx" target="_blank">Rob Eisenberg's WPF control template</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><em>Special thanks to <a href="https://blogs.claritycon.com/blogs/bryan_dougherty/default.aspx" target="_blank">
Bryan Dougherty</a> for the WCF jumpstart, <a href="https://blogs.claritycon.com/blogs/kevin_marshall/default.aspx" target="_blank">
Kevin Marshall</a> for the Halloween Trivia and <a href="http://blogs.techrepublic.com.com/geekend/index.php?cat=400&amp;submit=view" target="_blank">
Jay Garmon</a>, creator of TechRepublic's Geek Trivia.</em></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:85a5cfe91af449478d329e7600d1c0ef">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/YeahTrivia-Creating-a-Trivia-ServerClient-with-WPF-and-WCF</comments>
      <itunes:summary>




In this article I&#39;ll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication
 Foundation (WCF). Afterwards, you&#39;ll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&amp;nbsp;
And in honor of Halloween, I&#39;ve included three games of horror movie trivia.



Steve Holstad
The Bright Lights

Difficulty: Advanced
Time Required: 
6-10 hours
Cost: Free
Software: Visual Studio Express, 2005, 2008 Beta 2

Microsoft .NET Framework 3.0
Hardware: 
Download: Download Source








&amp;nbsp; 
What can YeahTrivia do for me?
Glad you asked. This project started when I decided I wanted to dive headfirst into learning WPF and WCF, without hacking through countless Hello World examples.&amp;nbsp; And I wanted something fun that I could improve over time as my skills developed in these new
 technologies.&amp;nbsp; In this article I&#39;ll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication Foundation (WCF).
 Afterwards, you&#39;ll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&amp;nbsp; And in honor of Halloween, I&#39;ve included three games of horror movie trivia. 

 
In case you were wondering, the &amp;quot;YeahTrivia&amp;quot; name honors my new bride&amp;nbsp;&amp;amp; her&amp;nbsp;favorite prefix.&amp;nbsp; Think of it as&amp;nbsp;YeeeeaaaaahhTrivia! 
Basic Setup
This demo project was built using Visual Studio 2008 Beta 2, and is based on the Microsoft .NET Framework version 3.0.&amp;nbsp; The game is fed by a small windows app that acts as a game server, providing game selection, user&amp;nbsp;registration, question loading, response
 times, chat messaging&amp;nbsp;and scorekeeping.&amp;nbsp; The server </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/YeahTrivia-Creating-a-Trivia-ServerClient-with-WPF-and-WCF</link>
      <pubDate>Mon, 29 Oct 2007 21:01:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/YeahTrivia-Creating-a-Trivia-ServerClient-with-WPF-and-WCF</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/5773166_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/5773166_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Steve Holstad</dc:creator>
      <itunes:author>Steve Holstad</itunes:author>
      <slash:comments>12</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/YeahTrivia-Creating-a-Trivia-ServerClient-with-WPF-and-WCF/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>Halloween</category>
      <category>Windows</category>
      <category>arcade</category>
      <category>windows miscellaneous</category>
      <category>card and board games</category>
    </item>
  <item>
      <title>Outlook Webmail Add-in for Windows Home Server</title>
      <description><![CDATA[
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50"><img alt="Office_MAIL" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/Office_MAIL.png" border="0">
</td>
<td><span class="entry_description">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.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author"><a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a></div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> 2<span class="entry_details_input">-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><strong>Software: </strong><a href="http://www.microsoft.com/windows/products/winfamily/windowshomeserver/default.mspx" target="_blank">Windows Home Server</a>,&nbsp;<a href="http://office.microsoft.com/en-us/outlook/default.aspx" target="_blank">Microsoft
 Outlook 2000/XP/2003/2007</a> (<strong>not</strong> Outlook Express/Windows Mail),&nbsp;<span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://msdn.com/express/" target="_blank">Visual Web Developer Express Edition</a>,
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en" target="_blank">
Microsoft .NET Framework 3.0 runtime</a>, Outlook/Office Primary Interop Assemblies (more on this below),&nbsp;<a href="http://www.microsoft.com/downloads/details.aspx?familyid=4377f86d-c913-4b5c-b87e-ef72e5b4e065&amp;displaylang=en" target="_blank">Windows SDK</a>
 (Vista or later, which includes the .NET 3.0 bits.&nbsp; Note that this installs and works just fine under Windows XP.&nbsp; The SDK can build applications for Windows XP and greater.)</span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details"><b>Download: </b><a href="http://www.codeplex.com/WHSMail" target="_blank">CodePlex Project</a></div>
</td>
</tr>
</tbody>
</table>
<h3>Introduction</h3>
<p><a href="http://www.microsoft.com/windows/products/winfamily/windowshomeserver/default.mspx" target="_blank">Windows Home Server</a>&nbsp;is a new product from Microsoft which allows home users to manage and share data, including photos, documents, videos, music,
 etc.&nbsp; It also provides a very easy way to backup all computers on your home network to a central storage server.</p>
<p>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.</p>
<p>One&nbsp;feature not present in WHS&nbsp;that I would find useful is the ability to view my Outlook mail box from the web at any time.&nbsp; I have 6&nbsp;or 7 email accounts that are&nbsp;all setup&nbsp;to retrieve via POP3 to Outlook.&nbsp; Most of these accounts do not support IMAP or
 have a web-based interface.&nbsp; Therefore, Outlook is generally open all day and checking messages.&nbsp;&nbsp;When I'm away from home for work or pleasure,&nbsp;it's&nbsp;very often&nbsp;inconvenient to have to remote desktop into&nbsp;the machine with Outlook running to read my email,&nbsp;so
 it would be nice to have a web-based version of my current&nbsp;Outlook folders so I can view all email (old and new) at any time simply by browsing to a&nbsp;web server at home.&nbsp; Windows Home&nbsp;Server comes with&nbsp;Internet Information Services&nbsp;6 (IIS6) and&nbsp;one can easily
 add a new web application to IIS on the server.</p>
<p>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.</p>
<p>If you wish to just use the application, download the sample from above and skip down to the deployment section for installation instructions.</p>
<p><strong>NOTE:</strong> This application will only work with Microsoft Outlook.&nbsp; It will not work with Outlook Express, Windows Mail, or any other mail client.</p>
<h3>Setup</h3>
<p>Setup can be a bit tricky.&nbsp; Office/Outlook will need to be installed on your development machine.&nbsp; It does not need to be the same machine which contains your store at this point, but that too would help.&nbsp; Once Office/Outlook is installed, the
<strong>Primary Interop Assemblies</strong> for the version of Office you are using need to be installed.&nbsp; For Office 2003/2007, this can be done choosing
<strong>.NET Programming Support</strong> from the list of sub-items in the <strong>
Microsoft Office Outlook </strong>section of the setup program.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/2003_3.png"><img height="426" alt="2003" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/2003_thumb_3.png" width="490" border="0"></a>
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/pia_3.png"><img height="414" alt="pia" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/pia_thumb_3.png" width="490" border="0"></a>
</p>
<p>Unfortunately I do not have an earlier copy of Office with which to check, but the procedure should be the same.&nbsp; If anyone happens to try this with Office XP/2000, please let me know if/how it works.</p>
<p>If you will be developing on an OS earlier than Vista,&nbsp;install the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en" target="_blank">
.NET Framework 3.0 runtime</a>.</p>
<p>Finally, install the Windows SDK linked above accepting all defaults.</p>
<h3>Architecture</h3>
<p>The architecture we will be using is very similar that to an N-tier application.&nbsp; The machine running Outlook with the message store to be viewed is, in essence, the server machine.&nbsp; That machine will run a host process that we will develop which will expose
 several methods via Windows Communication Foundation.&nbsp; These methods will be consumed by an ASP.NET application running on the Windows Home Server.</p>
<h3>The Host</h3>
<p>Let's start by building the host application.&nbsp; This will run on the computer where Outlook is installed and the messages are stored.&nbsp; The application will be written to run in the notification area next to the Windows system clock.</p>
<p>To start, create a new Windows Application project named <strong>WHSMailHost</strong>.&nbsp; Rename the default
<strong>Form1.cs/.vb</strong> file to <strong>frmMain.cs/.vb</strong>.&nbsp; Double-click on the file in the Solution Explorer to bring up the design surface.</p>
<p>In order to get the application to run in the notification area, drag and drop a
<strong>NotifyIcon</strong> control from the Toolbox to the design surface, name it
<strong>niIcon</strong>.&nbsp; Also, drag over a <strong>ContextMenuStrip</strong> to the design surface and name it
<strong>cmsMenu</strong>.&nbsp; This will be used to pop up a context menu when the icon in the notification area is clicked.&nbsp;&nbsp;Finally,&nbsp;set the following properties on the
<strong>niIcon</strong> control:</p>
<table cellspacing="0" cellpadding="2" width="248" border="1">
<tbody>
<tr>
<td valign="top" width="136"><strong>Text</strong></td>
<td valign="top" width="110">WHS Mail Host</td>
</tr>
<tr>
<td valign="top" width="138"><strong>ContextMenuStrip</strong></td>
<td valign="top" width="110">cmsMenu</td>
</tr>
<tr>
<td valign="top" width="139"><strong>Visible</strong></td>
<td valign="top" width="110">True</td>
</tr>
</tbody>
</table>
<p>Select the <strong>cmsMenu</strong> control and add a single menu item named <strong>
Exit</strong> to the list.&nbsp; Double-click on that menu item to create a default <strong>
Click </strong>event.&nbsp; In the code for the <strong>Click</strong> event, simply close the form as follows:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>private</span> <span>void</span> mnuExit_Click(<span>object</span> sender, EventArgs e)
{
    <span>// exit the application</span>
    <span>this</span>.Close();
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Private</span> <span>Sub</span> mnuExit_Click(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs) <span>Handles</span> mnuExit.Click
    <span>' exit the application</span>
    <span>Me</span>.Close()
<span>End</span> Sub</pre>
</div>
<p>Finally, add the following events to <strong>frmMain</strong> by selecting them from the Event Property window and implementing them with the following code:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>private</span> <span>void</span> frmMain_Resize(<span>object</span> sender, EventArgs e)
{
    <span>// hide the form</span>
    <span>this</span>.Hide();
}

<span>private</span> <span>void</span> frmMain_Load(<span>object</span> sender, EventArgs e)
{
    <span>// start the WCF service</span>
    MyServiceHost.StartService();
}

<span>private</span> <span>void</span> frmMain_FormClosing(<span>object</span> sender, FormClosingEventArgs e)
{
    <span>// stop the WCF service</span>
    MyServiceHost.StopService();
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Private</span> <span>Sub</span> frmMain_Resize(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs) <span>Handles</span> <span>MyBase</span>.Resize
    <span>' hide the form</span>
    <span>Me</span>.Hide()
<span>End</span> <span>Sub</span>

<span>Private</span> <span>Sub</span> frmMain_Load(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs) <span>Handles</span> <span>MyBase</span>.Load
    <span>' start the WCF service</span>
    MyServiceHost.StartService()
<span>End</span> <span>Sub</span>

<span>Private</span> <span>Sub</span> frmMain_FormClosing(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> FormClosingEventArgs) <span>Handles</span> <span>MyBase</span>.FormClosing
    <span>' stop the WCF service</span>
    MyServiceHost.StopService()
<span>End</span> Sub</pre>
</div>
<p>The code above references a class named <strong>MyServiceHost</strong>.&nbsp; This is what starts the WCF host and will be discussed next.</p>
<p>&nbsp;</p>
<h4>Windows Communication Foundation (WCF)</h4>
<p>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.&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).</p>
<p>First, add a reference to the <strong>System.ServiceModel</strong> assembly.&nbsp; Then, add a class to the project named
<strong>WHSMailService</strong>.&nbsp; Open the class and add the following code beneath the generated
<strong>WHSMailService</strong> class implementation:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>internal</span> <span>class</span> MyServiceHost
{
    <span>internal</span> <span>static</span> ServiceHost myServiceHost = <span>null</span>;

    <span>internal</span> <span>static</span> <span>void</span> StartService()
    {
        <span>// Instantiate new ServiceHost </span>
        myServiceHost = <span>new</span> ServiceHost(<span>typeof</span>(WHSMailService));
        myServiceHost.Open();
    }

    <span>internal</span> <span>static</span> <span>void</span> StopService()
    {
        <span>// Call StopService from your shutdown logic (i.e. dispose method)</span>
        <span>if</span> (myServiceHost.State != CommunicationState.Closed)
            myServiceHost.Close();
    }
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Friend</span> <span>Class</span> MyServiceHost
    <span>Friend</span> <span>Shared</span> myServiceHost <span>As</span> ServiceHost = <span>Nothing</span>

    <span>Friend</span> <span>Shared</span> <span>Sub</span> StartService()
        <span>' Instantiate new ServiceHost </span>
        myServiceHost = <span>New</span> ServiceHost(<span>GetType</span>(WHSMailService))
        myServiceHost.Open()
    <span>End</span> <span>Sub</span>

    <span>Friend</span> <span>Shared</span> <span>Sub</span> StopService()
        <span>' Call StopService from your shutdown logic (i.e. dispose method)</span>
        <span>If</span> myServiceHost.State &lt;&gt; CommunicationState.Closed <span>Then</span>
            myServiceHost.Close()
        <span>End</span> <span>If</span>
    <span>End</span> <span>Sub</span>
<span>End</span> <span>Class</span>
</pre>
</div>
<p>This code simply creates a new WCF <strong>ServiceHost</strong> of the type <strong>
WHSMailService</strong> (which we will implement next) and then opens that host so that it may receive incoming connections.&nbsp; We will look at how this connections are configured later in the article.</p>
<p>Remember that the code in the form above above called the <strong>StartService</strong> and
<strong>StopService</strong> methods located here when the main form loads and closes.&nbsp; This very easily allows to immediately start the service host when the application starts and closes the service host when the application exits.</p>
<h4>Contracts and Entities</h4>
<p>A contract is an interface that defines which methods are exposed by the service host that can be consumed by the client application.&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.&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.</p>
<p>Create a new <strong>Class Library</strong> project in the current solution named
<strong>WHSMailCommon</strong>.&nbsp; In this new project, create a directory named <strong>
Contracts</strong> and a directory named <strong>Entities</strong>.</p>
<p>Inside the <strong>Entities</strong> directory, create a new class named <strong>
Folder</strong>.&nbsp; This will represent an Outlook message folder.&nbsp; The class should look like the following:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> System;
<span>using</span> System.Collections.Generic;

<span>namespace</span> WHSMailCommon.Entities
{
    <span>// entity object representing an Folder</span>
    [Serializable]
    <span>public</span> <span>class</span> Folder : IComparable
    {
        <span>private</span> <span>string</span> _entryID;
        <span>private</span> <span>string</span> _name;
        <span>private</span> List&lt;Folder&gt; _folders;
        <span>private</span> <span>int</span> _unreadMessages;
        <span>private</span> <span>int</span> _totalMessages;

        <span>public</span> Folder(<span>string</span> entryID, <span>string</span> name, <span>int</span> unreadMessages, <span>int</span> totalMessages)
        {
            _entryID = entryID;
            _name = name;
            _unreadMessages = unreadMessages;
            _totalMessages = totalMessages;
        }

        <span>// MAPI unique identifier</span>
        <span>public</span> <span>string</span> EntryID
        {
            get { <span>return</span> _entryID; }
            set { _entryID = <span>value</span>; }
        }

        <span>// subfolders of this folder</span>
        <span>public</span> List&lt;Folder&gt; Folders
        {
            get { <span>return</span> _folders; }
            set { _folders = <span>value</span>; }
        }

        <span>public</span> <span>string</span> Name
        {
            get { <span>return</span> _name; }
            set { _name = <span>value</span>; }
        }

        <span>public</span> <span>int</span> UnreadMessages
        {
            get { <span>return</span> <span>this</span>._unreadMessages; }
            set { <span>this</span>._unreadMessages = <span>value</span>; }
        }

        <span>public</span> <span>int</span> TotalMessages
        {
            get { <span>return</span> <span>this</span>._totalMessages; }
            set { <span>this</span>._totalMessages = <span>value</span>; }
        }

        <span>// used so we can sort the folders alphabetically later on</span>
        <span>public</span> <span>int</span> CompareTo(<span>object</span> obj)
        {
            <span>return</span> <span>string</span>.Compare(<span>this</span>.Name, ((Folder)obj).Name);
        }
    }
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> Microsoft.VisualBasic
<span>Imports</span> System
<span>Imports</span> System.Collections.Generic

<span>Namespace</span> WHSMailCommon.Entities
    <span>' entity object representing an Folder</span>
    &lt;Serializable&gt; _
    <span>Public</span> <span>Class</span> Folder
        <span>Implements</span> IComparable
        <span>Private</span> _entryID <span>As</span> <span>String</span>
        <span>Private</span> _name <span>As</span> <span>String</span>
        <span>Private</span> _folders <span>As</span> List(Of Folder)
        <span>Private</span> _unreadMessages <span>As</span> <span>Integer</span>
        <span>Private</span> _totalMessages <span>As</span> <span>Integer</span>

        <span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> entryID <span>As</span> <span>String</span>, <span>ByVal</span> name <span>As</span> <span>String</span>, <span>ByVal</span> unreadMessages <span>As</span> <span>Integer</span>, <span>ByVal</span> totalMessages <span>As</span> <span>Integer</span>)
            _entryID = entryID
            _name = name
            _unreadMessages = unreadMessages
            _totalMessages = totalMessages
        <span>End</span> <span>Sub</span>

        <span>' MAPI unique identifier</span>
        <span>Public</span> <span>Property</span> EntryID() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _entryID
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _entryID = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>' subfolders of this folder</span>
        <span>Public</span> <span>Property</span> Folders() <span>As</span> List(Of Folder)
            <span>Get</span>
                <span>Return</span> _folders
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> List(Of Folder))
                _folders = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> Name() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _name
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _name = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> UnreadMessages() <span>As</span> <span>Integer</span>
            <span>Get</span>
                <span>Return</span> <span>Me</span>._unreadMessages
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Integer</span>)
                <span>Me</span>._unreadMessages = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> TotalMessages() <span>As</span> <span>Integer</span>
            <span>Get</span>
                <span>Return</span> <span>Me</span>._totalMessages
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Integer</span>)
                <span>Me</span>._totalMessages = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>' used so we can sort the folders alphabetically later on</span>
        <span>Public</span> <span>Function</span> CompareTo(<span>ByVal</span> obj <span>As</span> <span>Object</span>) <span>As</span> <span>Integer</span> <span>Implements</span> IComparable.CompareTo
            <span>Return</span> <span>String</span>.Compare(<span>Me</span>.Name, (<span>CType</span>(obj, Folder)).Name)
        <span>End</span> <span>Function</span>
    <span>End</span> <span>Class</span>
<span>End</span> <span>Namespace</span>
</pre>
</div>
<p>This class defines several properties to describe the folder (EntryID, Name, etc.) and additionally implements the
<strong>IComparable </strong>interface's <strong>CompareTo</strong> method&nbsp;so that we can easily sort the folders alphabetically later on.</p>
<p>Next, create a class named <strong>Email</strong>.&nbsp; The code for this class looks like the following:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> System;
<span>using</span> System.Collections.Generic;
<span>using</span> System.Text;

<span>namespace</span> WHSMailCommon.Entities
{
    <span>// entity object representing an Email</span>
    [Serializable]
    <span>public</span> <span>class</span> Email
    {
        <span>private</span> <span>string</span> _entryID;
        <span>private</span> <span>string</span> _from;
        <span>private</span> <span>string</span> _fromName;
        <span>private</span> <span>string</span> _subject;
        <span>private</span> DateTime _received;
        <span>private</span> <span>int</span> _size;
        <span>private</span> <span>string</span> _body;

        <span>public</span> Email(<span>string</span> entryID, <span>string</span> from, <span>string</span> fromName, <span>string</span> subject, DateTime received, <span>int</span> size)
        {
            _entryID = entryID;
            _from = from;
            _fromName = fromName;
            _subject = <span>string</span>.IsNullOrEmpty(subject) ? <span>&quot;(no subject)&quot;</span> : subject;
            _received = received;
            _size = size;
        }

        <span>public</span> Email(<span>string</span> entryID, <span>string</span> from, <span>string</span> fromName, <span>string</span> subject, DateTime received, <span>int</span> size, <span>string</span> body) :
            <span>this</span>(entryID, from, fromName, subject, received, size)
        {
            _body = body;
        }

        <span>// MAPI unique ID</span>
        <span>public</span> <span>string</span> EntryID
        {
            get { <span>return</span> _entryID; }
            set { _entryID = <span>value</span>; }
        }

        <span>// email address of sender</span>
        <span>public</span> <span>string</span> From
        {
            get { <span>return</span> _from; }
            set { _from = <span>value</span>; }
        }

        <span>// name of sender</span>
        <span>public</span> <span>string</span> FromName
        {
            get { <span>return</span> _fromName; }
            set { _fromName = <span>value</span>; }
        }

        <span>public</span> <span>string</span> Subject
        {
            get { <span>return</span> _subject; }
            set { _subject = <span>value</span>; }
        }

        <span>public</span> <span>string</span> Body
        {
            get { <span>return</span> _body; }
            set { _body = <span>value</span>; }
        }

        <span>public</span> DateTime Received
        {
            get { <span>return</span> _received; }
            set { _received = <span>value</span>; }
        }

        <span>public</span> <span>int</span> Size
        {
            get { <span>return</span> _size; }
            set { _size = <span>value</span>; }
        }
    }
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> Microsoft.VisualBasic
<span>Imports</span> System
<span>Imports</span> System.Collections.Generic
<span>Imports</span> System.Text

<span>Namespace</span> WHSMailCommon.Entities
    <span>' entity object representing an Email</span>
    &lt;Serializable&gt; _
    <span>Public</span> <span>Class</span> Email
        <span>Private</span> _entryID <span>As</span> <span>String</span>
        <span>Private</span> _from <span>As</span> <span>String</span>
        <span>Private</span> _fromName <span>As</span> <span>String</span>
        <span>Private</span> _subject <span>As</span> <span>String</span>
        <span>Private</span> _received <span>As</span> DateTime
        <span>Private</span> _size <span>As</span> <span>Integer</span>
        <span>Private</span> _body <span>As</span> <span>String</span>

        <span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> entryID <span>As</span> <span>String</span>, <span>ByVal</span> From <span>As</span> <span>String</span>, <span>ByVal</span> fromName <span>As</span> <span>String</span>, <span>ByVal</span> subject <span>As</span> <span>String</span>, <span>ByVal</span> received <span>As</span> DateTime, <span>ByVal</span> size <span>As</span> <span>Integer</span>)
            _entryID = entryID
            _from = From
            _fromName = fromName
            <span>If</span> <span>String</span>.IsNullOrEmpty(subject) <span>Then</span>
                _subject = <span>&quot;(no subject)&quot;</span>
            <span>Else</span>
                _subject = subject
            <span>End</span> <span>If</span>
            _received = received
            _size = size
        <span>End</span> <span>Sub</span>

        <span>Public</span> <span>Sub</span> <span>New</span>(<span>ByVal</span> entryID <span>As</span> <span>String</span>, <span>ByVal</span> From <span>As</span> <span>String</span>, <span>ByVal</span> fromName <span>As</span> <span>String</span>, <span>ByVal</span> subject <span>As</span> <span>String</span>, <span>ByVal</span> received <span>As</span> DateTime, <span>ByVal</span> size <span>As</span> <span>Integer</span>, <span>ByVal</span> body <span>As</span> <span>String</span>)
            <span>Me</span>.<span>New</span>(entryID, From, fromName, subject, received, size)
            _body = body
        <span>End</span> <span>Sub</span>

        <span>' MAPI unique ID</span>
        <span>Public</span> <span>Property</span> EntryID() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _entryID
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _entryID = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>' email address of sender</span>
        <span>Public</span> <span>Property</span> From() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _from
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _from = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>' name of sender</span>
        <span>Public</span> <span>Property</span> FromName() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _fromName
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _fromName = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> Subject() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _subject
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _subject = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> Body() <span>As</span> <span>String</span>
            <span>Get</span>
                <span>Return</span> _body
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)
                _body = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> Received() <span>As</span> DateTime
            <span>Get</span>
                <span>Return</span> _received
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> DateTime)
                _received = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>

        <span>Public</span> <span>Property</span> Size() <span>As</span> <span>Integer</span>
            <span>Get</span>
                <span>Return</span> _size
            <span>End</span> <span>Get</span>
            <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Integer</span>)
                _size = value
            <span>End</span> <span>Set</span>
        <span>End</span> <span>Property</span>
    <span>End</span> <span>Class</span>
<span>End</span> <span>Namespace</span>
</pre>
</div>
<p>This class simply contains properties to describe an email message.</p>
<p>You will note that both of these classes have the <strong>[Serializable]</strong> attribute attached to them.&nbsp; When objects are passed through WCF, they are serialized at the source and deserialized at the destination.&nbsp; By marking the objects with the
<strong>[Serializable]</strong> attribute, the .NET CLR can do this for us automatically&nbsp; since we are not using any complex data types in our entities.</p>
<p>With our entities out of the way, we can define our contract.&nbsp;&nbsp;Inside&nbsp;the <strong>
Contracts</strong>&nbsp;directory, create a new <strong>Interface</strong> file named <strong>
IWHSMailService</strong>.</p>
<p>This interface/contract will define three methods:&nbsp; one method to return a tree of objects which represent the folder tree in Outlook (<strong>GetFolders</strong>), one method to return a list of messages inside that folder (<strong>GetMessages</strong>),
 and one method to return the contents of a specific message (<strong>GetMessages</strong>).&nbsp; The interface will look like the following:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> System.Collections.Generic;
<span>using</span> System.ServiceModel;
<span>using</span> WHSMailCommon.Entities;

<span>namespace</span> WHSMailCommon.Contracts
{
    <span>// list of methods of the WHSMailService service</span>
    [ServiceContract()]
    <span>public</span> <span>interface</span> IWHSMailService
    {
        [OperationContract]
        List&lt;Folder&gt; GetFolders();

        [OperationContract]
        List&lt;Email&gt; GetMessages(<span>string</span> entryID, <span>int</span> numPerPage, <span>int</span> pageNum);

        [OperationContract]
        Email GetMessage(<span>string</span> entryID);
    }
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> Microsoft.VisualBasic
<span>Imports</span> System.Collections.Generic
<span>Imports</span> System.ServiceModel
<span>Imports</span> WHSMailCommon.Entities

<span>Namespace</span> WHSMailCommon.Contracts
    <span>' list of methods of the WHSMailService service</span>
    &lt;ServiceContract()&gt; _
    <span>Public</span> <span>Interface</span> IWHSMailService
        &lt;OperationContract&gt; _
        <span>Function</span> GetFolders() <span>As</span> List(Of Folder)

        &lt;OperationContract&gt; _
        <span>Function</span> GetMessages(<span>ByVal</span> entryID <span>As</span> <span>String</span>, <span>ByVal</span> numPerPage <span>As</span> <span>Integer</span>, <span>ByVal</span> pageNum <span>As</span> <span>Integer</span>) <span>As</span> List(Of Email)

        &lt;OperationContract&gt; _
        <span>Function</span> GetMessage(<span>ByVal</span> entryID <span>As</span> <span>String</span>) <span>As</span> Email
    <span>End</span> <span>Interface</span>
<span>End</span> <span>Namespace</span>
</pre>
</div>
<p>As with the entities, this interface is also decorated with several attributes.&nbsp; First, any WCF contract interface must be tagged with the
<strong>[ServiceContract()]</strong> attribute to define it as a contract to WCF.&nbsp; Additionally, all methods which will be exposed for consumption by a client must be marked with the
<strong>[OperationContract]</strong> attribute.</p>
<p>The implementation and description of these methods will come later when we write the contract implementation.</p>
<h4></h4>
<h4>Configuration</h4>
<p>The final thing to setup on the WCF server is the configuration file.&nbsp; The service can very easily be configured using an application configuration file.&nbsp; Add an
<strong>Application Configuration</strong> file to the project named <strong>App.config</strong>.&nbsp; Set the contents of the file to the following:</p>
<div>
<pre><span>&lt;?</span><span>xml</span> <span>version</span><span>=&quot;1.0&quot;</span> <span>encoding</span><span>=&quot;utf-8&quot;</span> ?<span>&gt;</span>
<span>&lt;</span><span>configuration</span><span>&gt;</span>
    <span>&lt;</span><span>system.serviceModel</span><span>&gt;</span>
        <span>&lt;</span><span>bindings</span><span>&gt;</span>
            <span>&lt;</span><span>netTcpBinding</span><span>&gt;</span>
                <span>&lt;</span><span>binding</span> <span>name</span><span>=&quot;NewBinding0&quot;</span><span>&gt;</span>
                    <span>&lt;</span><span>security</span> <span>mode</span><span>=&quot;None&quot;</span> <span>/&gt;</span>
                <span>&lt;/</span><span>binding</span><span>&gt;</span>
            <span>&lt;/</span><span>netTcpBinding</span><span>&gt;</span>
        <span>&lt;/</span><span>bindings</span><span>&gt;</span>
        <span>&lt;</span><span>services</span><span>&gt;</span>
            <span>&lt;</span><span>service</span> <span>name</span><span>=&quot;WHSMailHost.WHSMailService&quot;</span><span>&gt;</span>
                <span>&lt;</span><span>endpoint</span> <span>address</span><span>=&quot;net.tcp://localhost:12345/IWHSMailService&quot;</span>
                    <span>binding</span><span>=&quot;netTcpBinding&quot;</span> <span>bindingConfiguration</span><span>=&quot;NewBinding0&quot;</span>
                    <span>contract</span><span>=&quot;WHSMailCommon.Contracts.IWHSMailService&quot;</span> <span>/&gt;</span>
            <span>&lt;/</span><span>service</span><span>&gt;</span>
        <span>&lt;/</span><span>services</span><span>&gt;</span>
    <span>&lt;/</span><span>system.serviceModel</span><span>&gt;</span>
<span>&lt;/</span><span>configuration</span><span>&gt;</span></pre>
</div>
<p>The <strong>&lt;services&gt;</strong> section defines the services that the WCF host will enable.&nbsp; This creates a single
<strong>&lt;service&gt;</strong> named <strong>WHSMailHost.WHSMailService</strong>, which is the full name of the service class that we will implement shortly.&nbsp; Inside the
<strong>&lt;service&gt;</strong> tag an endpoint is defined.&nbsp; And endpoint is essentially the &quot;port&quot; on which the client connects.&nbsp; The endpoint defined here is using the
<strong>net.tcp</strong> protocol and is set to listen on the <strong>localhost</strong> on port
<strong>12345</strong> at the name <strong>IWHSMailService</strong>.&nbsp; The next thing defined is a binding.&nbsp; This sets protocol by which the service will communicate, its configuration,&nbsp;and the contract it implements.&nbsp; The binding configuration named
<strong>NewBinding0</strong> (a default name) can be found above inside the <strong>
&lt;bindings&gt;</strong> tag.&nbsp; The only configuration item that is specified is that security will be turned off for communication between the client and server.&nbsp; Given that these two machines will be connecting to each other on your own local network, security
 is not a great concern.&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.</p>
<p>There are around several billion other options, protocols, bindings, etc. etc. etc. that can be configured here.&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.&nbsp; Also
 note that you can configure WCF with a windows UI by selecting the <strong>Service Configuration Editor</strong> application installed with the Windows SDK.&nbsp; You'll find this in the
<strong>Microsoft Windows SDK</strong> program group off your Start menu.</p>
<h3>Outlook and MAPI</h3>
<p>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.).&nbsp; We will be using MAPI to get the data
 we require from Outlook for our application.</p>
<p>Earlier we created a contract named <strong>IWHSMailService</strong>.&nbsp; This contract will be implemented by the
<strong>WHSMailService</strong> class that was also created earlier.&nbsp; To do this, set a reference to the project's
<strong>WHSMailCommon</strong> assembly.&nbsp; Then, bring the <strong>Contracts</strong> and
<strong>Entities</strong> namespaces into the <strong>WHSMailService</strong> class with the following:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> WHSMailCommon.Contracts;
<span>using</span> WHSMailCommon.Entities;</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> WHSMailCommon.Contracts
<span>Imports</span> WHSMailCommon.Entities</pre>
</div>
<p>Then, setup the class to implement the interface as follows:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>public</span> <span>class</span> WHSMailService : IWHSMailService</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Public</span> <span>Class</span> WHSMailService
    <span>Implements</span> IWHSMailService
</pre>
</div>
<p>Visual Studio will then create the 3 methods that must be implemented according to the interface (<strong>GetFolders</strong>,
<strong>GetMessages</strong>, <strong>GetMessage</strong>).&nbsp; We will fill those in shortly.&nbsp; But first, we must implement our constructor.&nbsp; When WCF calls the service, a new instance of the object will be created on each call.&nbsp; Therefore, it is easy to setup
 any initialization code for the service in the default constructor method.&nbsp; In this case, we will initialize the MAPI layer and logon to the default instance.</p>
<p>First, set a reference to the <strong>Microsoft Outlook XX.0 Object Library</strong> which you will find under the COM tab assuming Outlook is installed as per the instructions above.&nbsp; Note that the version will depend on what version of Outlook you have
 installed on your local machine.&nbsp; I'm using Outlook 2007, so version 12 is what the sample code above is referencing.&nbsp; If you are using a different version, reference the appropriate version before continuing.</p>
<p>Once the reference is set, bring the namespace into the <strong>WHSMailService</strong> class with the following line which will import the namespace and setup an alias named
<strong>Outlook</strong> to save some typing:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> Outlook = Microsoft.Office.Interop.Outlook;</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> Outlook = Microsoft.Office.Interop.Outlook</pre>
</div>
<p>Now the constructor can be implemented.&nbsp; We need to get an instance of the Outlook
<strong>ApplicationClass</strong>.&nbsp; From there we can get an instance of the <strong>
MAPI</strong> namespace.&nbsp; All methods that we will be using hang off that namespace object.&nbsp; The code for the constructor follows:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>private</span> <span>readonly</span> Outlook.NameSpace _nameSpace = <span>null</span>;

<span>public</span> WHSMailService()
{
    <span>// get an instance of the MAPI namespace and login</span>
    Outlook.Application app = <span>new</span> Outlook.ApplicationClass();
    _nameSpace = app.GetNamespace(<span>&quot;MAPI&quot;</span>);
    _nameSpace.Logon(<span>null</span>, <span>null</span>, <span>false</span>, <span>false</span>);
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Private</span> <span>ReadOnly</span> _nameSpace <span>As</span> Outlook.<span>NameSpace</span> = <span>Nothing</span>

<span>Public</span> <span>Sub</span> <span>New</span>()
    <span>' get an instance of the MAPI namespace and login</span>
    <span>Dim</span> app <span>As</span> Outlook.Application = <span>New</span> Outlook.ApplicationClass()
    _nameSpace = app.GetNamespace(<span>&quot;MAPI&quot;</span>)
    _nameSpace.Logon(<span>Nothing</span>, <span>Nothing</span>, <span>False</span>, <span>False</span>)
<span>End</span> <span>Sub</span>
</pre>
</div>
<p>With a handle to the namespace, we can write our <strong>GetFolders</strong> method.&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 <strong>
CompareTo</strong> method of the <strong>IComparable</strong> interface we implemented earlier).</p>
<p><strong>C#</strong></p>
<div>
<pre><span>public</span> List&lt;Folder&gt; GetFolders()
{
    List&lt;Folder&gt; list = <span>new</span> List&lt;Folder&gt;();

    <span>// get the inbox and then go up one level...that *should* be the root of the default store</span>
    Outlook.MAPIFolder root = (Outlook.MAPIFolder)_nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent;

    <span>// add root folder</span>
    Folder folder = <span>new</span> Folder(root.EntryID, root.Name, root.UnReadItemCount, root.Items.Count);
    list.Add(folder);

    <span>// Enumerate the sub-folders</span>
    EnumerateFolders(root.Folders, folder);

    <span>return</span> list;
}

<span>private</span> <span>void</span> EnumerateFolders(Outlook.Folders folders, Folder rootFolder)
{
    <span>foreach</span>(Outlook.MAPIFolder f <span>in</span> folders)
    {
        <span>// ensure it's a folder that contains mail messages (i.e. no contacts, appointments, etc.)</span>
        <span>if</span>(f.DefaultItemType == Outlook.OlItemType.olMailItem)
        {
            <span>if</span>(rootFolder.Folders == <span>null</span>)
                rootFolder.Folders = <span>new</span> List&lt;Folder&gt;();

            <span>// add the current folder and enumerate all sub-folders</span>
            Folder subFolder = <span>new</span> Folder(f.EntryID, f.Name, f.UnReadItemCount, f.Items.Count);
            rootFolder.Folders.Add(subFolder);
            <span>if</span>(f.Folders.Count &gt; 0)
                <span>this</span>.EnumerateFolders(f.Folders, subFolder);
        }
    }

    <span>// alphabetize the list (Folder implements IComparable)</span>
    rootFolder.Folders.Sort();
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Public</span> <span>Function</span> GetFolders() <span>As</span> List(Of Folder) <span>Implements</span> IWHSMailService.GetFolders
    <span>Dim</span> list <span>As</span> List(Of Folder) = <span>New</span> List(Of Folder)()

    <span>' get the inbox and then go up one level...that *should* be the root of the default store</span>
    <span>Dim</span> root <span>As</span> Outlook.MAPIFolder = <span>CType</span>(_nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent, Outlook.MAPIFolder)

    <span>' add root folder</span>
    <span>Dim</span> folder <span>As</span> Folder = <span>New</span> Folder(root.EntryID, root.Name, root.UnReadItemCount, root.Items.Count)
    list.Add(folder)

    <span>' Enumerate the sub-folders</span>
    EnumerateFolders(root.Folders, folder)

    <span>Return</span> list
<span>End</span> <span>Function</span>

<span>Private</span> <span>Sub</span> EnumerateFolders(<span>ByVal</span> folders <span>As</span> Outlook.Folders, <span>ByVal</span> rootFolder <span>As</span> Folder)
    <span>For</span> <span>Each</span> f <span>As</span> Outlook.MAPIFolder <span>In</span> folders
        <span>' ensure it's a folder that contains mail messages (i.e. no contacts, appointments, etc.)</span>
        <span>If</span> f.DefaultItemType = Outlook.OlItemType.olMailItem <span>Then</span>
            <span>If</span> rootFolder.Folders <span>Is</span> <span>Nothing</span> <span>Then</span>
                rootFolder.Folders = <span>New</span> List(Of Folder)()
            <span>End</span> <span>If</span>

            <span>' add the current folder and enumerate all sub-folders</span>
            <span>Dim</span> subFolder <span>As</span> Folder = <span>New</span> Folder(f.EntryID, f.Name, f.UnReadItemCount, f.Items.Count)
            rootFolder.Folders.Add(subFolder)
            <span>If</span> f.Folders.Count &gt; 0 <span>Then</span>
                <span>Me</span>.EnumerateFolders(f.Folders, subFolder)
            <span>End</span> <span>If</span>
        <span>End</span> <span>If</span>
    <span>Next</span> f

    <span>' alphabetize the list (Folder implements IComparable)</span>
    rootFolder.Folders.Sort()
<span>End</span> Sub</pre>
</div>
<p>This code will return a generic hierarchal list of our <strong>Folder</strong> entity objects which&nbsp;will be displayed in the web application.&nbsp; Note that one of the items assigned to the
<strong>Folder</strong> entity is the <strong>EntryID</strong> property from the <strong>
MAPIFolder</strong> object.&nbsp; All MAPI items, be they email messages, folders, appointments, etc. have a unique identifier which is stored in the
<strong>EntryID</strong> field.&nbsp; We will need this unique value later on to retrieve messages from that folder.</p>
<p>Next, let's implement the <strong>GetMessages</strong> method.&nbsp; This method will return a list of messages (minus the bodies) from&nbsp;the folder specified using the
<strong>GetFolderFromID</strong> method, sorted by the received date with the most current first.&nbsp; It will also handle paging so that the entire folder is not returned at once.</p>
<p><strong>C#</strong></p>
<div>
<pre><span>public</span> List&lt;Email&gt; GetMessages(<span>string</span> entryID, <span>int</span> numPerPage, <span>int</span> pageNum)
{
    List&lt;Email&gt; list = <span>new</span> List&lt;Email&gt;();

    Outlook.MAPIFolder f;

    <span>// if no ID specified, open the inbox</span>
    <span>if</span>(<span>string</span>.IsNullOrEmpty(entryID))
        f = _nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
    <span>else</span>
        f = _nameSpace.GetFolderFromID(entryID, <span>&quot;&quot;</span>);

    <span>// to handle the sorting, one needs to cache their own instance of the items object</span>
    Outlook.Items items = f.Items;

    <span>// sort descending by received time</span>
    items.Sort(<span>&quot;[ReceivedTime]&quot;</span>, <span>true</span>);

    <span>// pull in the correct number of items based on number of items per page and current page number</span>
    <span>for</span>(<span>int</span> i = (numPerPage*pageNum)&#43;1; i &lt;= (numPerPage*pageNum)&#43;numPerPage &amp;&amp; i &lt;= items.Count; i&#43;&#43;)
    {
        <span>// ensure it's a mail message</span>
        Outlook.MailItem mi = (items[i] <span>as</span> Outlook.MailItem);
        <span>if</span>(mi != <span>null</span>)
            list.Add(<span>new</span> Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size));
    }

    <span>return</span> list;
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Public</span> <span>Function</span> GetMessages(<span>ByVal</span> entryID <span>As</span> <span>String</span>, <span>ByVal</span> numPerPage <span>As</span> <span>Integer</span>, <span>ByVal</span> pageNum <span>As</span> <span>Integer</span>) <span>As</span> List(Of Email) <span>Implements</span> IWHSMailService.GetMessages
    <span>Dim</span> list <span>As</span> List(Of Email) = <span>New</span> List(Of Email)()

    <span>Dim</span> f <span>As</span> Outlook.MAPIFolder

    <span>' if no ID specified, open the inbox</span>
    <span>If</span> <span>String</span>.IsNullOrEmpty(entryID) <span>Then</span>
        f = _nameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
    <span>Else</span>
        f = _nameSpace.GetFolderFromID(entryID, <span>&quot;&quot;</span>)
    <span>End</span> <span>If</span>

    <span>' to handle the sorting, one needs to cache their own instance of the items object</span>
    <span>Dim</span> items <span>As</span> Outlook.Items = f.Items

    <span>' sort descending by received time</span>
    items.Sort(<span>&quot;[ReceivedTime]&quot;</span>, <span>True</span>)

    <span>' pull in the correct number of items based on number of items per page and current page number</span>
    <span>Dim</span> i <span>As</span> <span>Integer</span> = (numPerPage*pageNum)&#43;1
    <span>Do</span> <span>While</span> i &lt;= (numPerPage*pageNum)&#43;numPerPage <span>AndAlso</span> i &lt;= items.Count
        <span>' ensure it's a mail message</span>
        <span>Dim</span> mi <span>As</span> Outlook.MailItem = (<span>TryCast</span>(items(i), Outlook.MailItem))
        <span>If</span> <span>Not</span> mi <span>Is</span> <span>Nothing</span> <span>Then</span>
            list.Add(<span>New</span> Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size))
        <span>End</span> <span>If</span>
        i &#43;= 1
    <span>Loop</span>

    <span>Return</span> list
<span>End</span> <span>Function</span>
</pre>
</div>
<p>The method takes a string parameter named <strong>entryID</strong> which is the unique identifier of the folder (from the code above) from which to return the messages.&nbsp; If no ID is specified, messages are returned from the Inbox.&nbsp; This code also handles
 paging by indexing into the array of <strong>Items</strong> of the <strong>MAPIFolder</strong> object at the specified position and counting out
<strong>numPerPage</strong> records to be returned.&nbsp; A list of <strong>Email</strong> entity objects is returned from this method to be displayed on the web interface.</p>
<p>Finally, let's implement the <strong>GetMessage</strong> method.&nbsp; This will return a specific message based on the MAPI
<strong>EntryID</strong> using the <strong>GetItemFromID</strong> method and format the body for plain text or HTML display.</p>
<p><strong>C#</strong></p>
<div>
<pre><span>public</span> Email GetMessage(<span>string</span> entryID)
{
    <span>// pull the message</span>
    Outlook.MailItem mi = (_nameSpace.GetItemFromID(entryID, <span>&quot;&quot;</span>) <span>as</span> Outlook.MailItem);

    <span>if</span> (mi != <span>null</span>)
    {
        <span>string</span> body;

        <span>// if it's a plain format message, wrap it in &lt;pre&gt; tags for nice output</span>
        <span>if</span>(mi.BodyFormat == Outlook.OlBodyFormat.olFormatPlain)
            body = <span>&quot;&lt;pre&gt;&quot;</span> &#43; mi.Body &#43; <span>&quot;&lt;/pre&gt;&quot;</span>;
        <span>else</span>
            body = mi.HTMLBody;

        <span>return</span> <span>new</span> Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size, body);
    }
    <span>else</span>
        <span>return</span> <span>null</span>;
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Public</span> <span>Function</span> GetMessage(<span>ByVal</span> entryID <span>As</span> <span>String</span>) <span>As</span> Email <span>Implements</span> IWHSMailService.GetMessage
    <span>' pull the message</span>
    <span>Dim</span> mi <span>As</span> Outlook.MailItem = (<span>TryCast</span>(_nameSpace.GetItemFromID(entryID, <span>&quot;&quot;</span>), Outlook.MailItem))

    <span>If</span> <span>Not</span> mi <span>Is</span> <span>Nothing</span> <span>Then</span>
        <span>Dim</span> body <span>As</span> <span>String</span>

        <span>' if it's a plain format message, wrap it in &lt;pre&gt; tags for nice output</span>
        <span>If</span> mi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain <span>Then</span>
            body = <span>&quot;&lt;pre&gt;&quot;</span> &amp; mi.Body &amp; <span>&quot;&lt;/pre&gt;&quot;</span>
        <span>Else</span>
            body = mi.HTMLBody
        <span>End</span> <span>If</span>

        <span>Return</span> <span>New</span> Email(mi.EntryID, mi.SenderEmailAddress, mi.SenderName, mi.Subject, mi.ReceivedTime, mi.Size, body)
    <span>Else</span>
        <span>Return</span> <span>Nothing</span>
    <span>End</span> <span>If</span>
<span>End</span> <span>Function</span>
</pre>
</div>
<p>With these three methods in place, we can get our folders, get messages in those folders, and get a specific message from a folder.&nbsp; Now we can switch our attention to the web-based &quot;client&quot; application which will plug into WHS.</p>
<p>&nbsp;</p>
<h3>ASP.NET &quot;Client&quot;</h3>
<p>The client we are going to produce is going to be a very simple 3-paned screen much like Outlook&nbsp;with folders on the left, messages on the top right, and message text on the bottom right.</p>
<p>Create a new&nbsp;<strong>ASP.NET Web Application</strong> named <strong>WHSMailWeb
</strong>(if you are using the Express editions of Visual Studio, you will need to do this in Visual Web Developer Express).&nbsp; Set a reference to the&nbsp;<strong>WHSMailCommon</strong> assembly along with the
<strong>System.ServiceModel</strong> assembly.&nbsp; Again, if you are in Express, you will have to set the reference to
<strong>WHSMailCommon</strong> in the other project's bin directory.</p>
<p>First, let's configure the ASP.NET application so it can properly call our WCF service running on the host machine.&nbsp; Open the
<strong>web.config</strong> file and add the following after the end <strong>&lt;/system.web&gt;</strong> tag and before the end
<strong>&lt;/configuration&gt;</strong> tab:</p>
<div>
<pre><span>&lt;</span><span>system.serviceModel</span><span>&gt;</span>
    <span>&lt;</span><span>bindings</span><span>&gt;</span>
        <span>&lt;</span><span>netTcpBinding</span><span>&gt;</span>
            <span>&lt;</span><span>binding</span> <span>name</span><span>=&quot;NewBinding0&quot;</span> <span>maxReceivedMessageSize</span><span>=&quot;1048576&quot;</span><span>&gt;</span>
                <span>&lt;</span><span>readerQuotas</span> <span>maxStringContentLength</span><span>=&quot;1048576&quot;</span> <span>/&gt;</span>
                <span>&lt;</span><span>security</span> <span>mode</span><span>=&quot;None&quot;</span> <span>/&gt;</span>
            <span>&lt;/</span><span>binding</span><span>&gt;</span>
        <span>&lt;/</span><span>netTcpBinding</span><span>&gt;</span>
    <span>&lt;/</span><span>bindings</span><span>&gt;</span>
    <span>&lt;</span><span>client</span><span>&gt;</span>
        <span>&lt;</span><span>endpoint</span> <span>address</span><span>=&quot;net.tcp://SERVERNAME:12345/IWHSMailService&quot;</span>
            <span>binding</span><span>=&quot;netTcpBinding&quot;</span> <span>bindingConfiguration</span><span>=&quot;NewBinding0&quot;</span>
            <span>contract</span><span>=&quot;WHSMailCommon.Contracts.IWHSMailService&quot;</span> <span>name</span><span>=&quot;WHSMailService&quot;</span> <span>/&gt;</span>
    <span>&lt;/</span><span>client</span><span>&gt;</span>
<span>&lt;/</span><span>system.serviceModel</span><span>&gt;</span></pre>
</div>
<p>This looks very similar to the configuration information from our host service.&nbsp; An endpoint is defined which points to the host server.&nbsp;
<strong>YOU WILL NEED TO CHANGE THE &quot;SERVERNAME&quot; HOST TO THE NAME OR IP ADDRESS OF THE MACHINE THAT WILL RUN THE HOST SERVICE WE CREATED ABOVE!</strong></p>
<p>You will see the same setup for the binding and contract.&nbsp; The <strong>name</strong> parameter will be used by the code a bit later so WCF knows how to contact the host to instantiate the remote object.</p>
<p>The one thing that is different here is the&nbsp;<strong>netTcpBinding</strong> configuration.&nbsp; The security mode is set to
<strong>none</strong> as it was before, but we have the addition of the <strong>maxReceivedMessageSize</strong> and
<strong>maxStringContentLength</strong>.&nbsp; Both of these are set at 1 megabyte to allow that much data to be transferred from the host to the client.&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.</p>
<p>Next, add a page to the project named <strong>BasePage</strong>.&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.</p>
<p>Open the code-behind file for <strong>BasePage</strong> and add the following code:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> System;
<span>using</span> System.ServiceModel;
<span>using</span> WHSMailCommon.Contracts;

<span>namespace</span> WHSMailWeb
{
    <span>public</span> <span>partial</span> <span>class</span> BasePage : System.Web.UI.Page
    {
        ChannelFactory&lt;IWHSMailService&gt; _factory = <span>null</span>;
        <span>private</span> IWHSMailService _channel = <span>null</span>;

        <span>protected</span> <span>void</span> Page_Init(<span>object</span> sender, EventArgs e)
        {
            <span>// create a channel factory and then instantiate a proxy channel</span>
            _factory = <span>new</span> ChannelFactory&lt;IWHSMailService&gt;(<span>&quot;WHSMailService&quot;</span>);
            _channel = _factory.CreateChannel();
        }

        <span>protected</span> <span>void</span> Page_Unload(<span>object</span> sender, EventArgs e)
        {
            <span>try</span>
            {
                _factory.Close();
            }
            <span>catch</span>
            {
                <span>// for the moment, we don't really care what happens here...if it fails, so be it</span>
            }
        }

        <span>public</span> IWHSMailService WHSMailService
        {
            get { <span>return</span> _channel; }
        }
    
    }
}
</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> Microsoft.VisualBasic
<span>Imports</span> System
<span>Imports</span> System.ServiceModel
<span>Imports</span> WHSMailCommon.Contracts

<span>Namespace</span> WHSMailWeb
    <span>Public</span> Partial <span>Class</span> BasePage
        <span>Inherits</span> System.Web.UI.Page
        <span>Private</span> _factory <span>As</span> ChannelFactory(Of IWHSMailService) = <span>Nothing</span>
        <span>Private</span> _channel <span>As</span> IWHSMailService = <span>Nothing</span>

        <span>Protected</span> <span>Sub</span> Page_Init(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
            <span>' create a channel factory and then instantiate a proxy channel</span>
            _factory = <span>New</span> ChannelFactory(Of IWHSMailService)(<span>&quot;WHSMailService&quot;</span>)
            _channel = _factory.CreateChannel()
        <span>End</span> <span>Sub</span>

        <span>Protected</span> <span>Sub</span> Page_Unload(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
            <span>Try</span>
                _factory.Close()
            <span>Catch</span>
                <span>' for the moment, we don't really care what happens here...if it fails, so be it</span>
            <span>End</span> <span>Try</span>
        <span>End</span> <span>Sub</span>

        <span>Public</span> <span>ReadOnly</span> <span>Property</span> WHSMailService() <span>As</span> IWHSMailService
            <span>Get</span>
                <span>Return</span> _channel
            <span>End</span> <span>Get</span>
        <span>End</span> <span>Property</span>

    <span>End</span> <span>Class</span>
<span>End</span> <span>Namespace</span>
</pre>
</div>
<p>This code overrides the page's <strong>Init</strong> and <strong>Unload</strong> methods.&nbsp;
<strong>Page_Init</strong> is called at the beginning of a page request and <strong>
Page_Unload</strong> is called just before the request completes.</p>
<p>The <strong>Page_Init</strong> method here uses WCF to create a <strong>ChannelFactory</strong> object factory that will return proxy objects of type
<strong>IWHSMailService</strong>.&nbsp; Recall that this is the interface which defines the contract of our service.&nbsp; The name passed as a parameter to the
<strong>ChannelFactory</strong> constructor must match the name of the service in the configuration file, as discussed earlier.</p>
<p>Next, a channel object is created by calling <strong>CreateChannel</strong> from the
<strong>ChannelFactory</strong>.&nbsp; This is what returns the fake, proxy object defined by our contract.&nbsp; A property named
<strong>WHSMailService</strong> at the bottom of the class exposes this so that the inherited pages can easily use the object to call the host service.&nbsp; We'll see this a bit later.</p>
<p>The <strong>Page_Unload</strong> method simply closes the factory object and very poorly handles any exceptions that may occur when doing so.&nbsp; An error on close isn't critical to this application, but that is certainly not always the case.</p>
<p>Now we will implement the default page.&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.&nbsp; It does, however, get the job done.</p>
<p>What you do need to know is that the page contains&nbsp;4 <strong>&lt;DIV&gt; </strong>tags:&nbsp; one contains an ASP.NET&nbsp;<strong>TreeView</strong> object (the left-most pane), one contains an ASP.NET
<strong>GridView</strong> object (the top-right pane), one contains 2 ASP.NET <strong>
LinkButton</strong>'s which implement a Next/Back paging scheme (the middle-right pane), &nbsp;and the last contains a table to display some header information, and a
<strong>&lt;DIV&gt;</strong> to display the message contents.</p>
<p>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):</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/webmail_3.png"><img height="490" alt="webmail" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/webmail_thumb_3.png" width="487" border="0"></a>
</p>
<p>Now let's implement the actual logic for the page.&nbsp; Open the <strong>Default.aspx</strong> page's code behind file.&nbsp; Bring in the
<strong>WHSMailCommon.Entities</strong> namespace as follows:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>using</span> WHSMailCommon.Entities;</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Imports</span> WHSMailCommon.Entities</pre>
</div>
<p>Next, change the <strong>_Default</strong> class to inherit from <strong>BasePage</strong> instead of
<strong>System.Web.UI.Page</strong>:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>public</span> <span>partial</span> <span>class</span> _Default : BasePage</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Public</span> Partial <span>Class</span> _Default
    <span>Inherits</span> BasePage</pre>
</div>
<p>Then, implement the <strong>Page_Load</strong> method.&nbsp; This method will be called after the
<strong>Page_Init</strong> method which is implemented in our parent object and will be called automatically.</p>
<p><strong>C#</strong></p>
<div>
<pre><span>private</span> <span>string</span> _folderEntryID = <span>string</span>.Empty;
<span>private</span> <span>int</span> _pageNum = 0;

<span>protected</span> <span>void</span> Page_Load(<span>object</span> sender, EventArgs e)
{
    <span>// first time in (tvFolders has viewstate enabled</span>
    <span>if</span>(tvFolders.Nodes.Count == 0)
    {
        <span>// get the folder tree</span>
        List&lt;Folder&gt; folderList = <span>this</span>.WHSMailService.GetFolders();

        <span>// add the root node and expand it</span>
        TreeNode node = <span>new</span> TreeNode(folderList[0].Name, folderList[0].EntryID);
        node.Expanded = <span>true</span>;
        tvFolders.Nodes.Add(node);

        <span>// load up the sub-folders</span>
        LoadNode(folderList[0].Folders, node);

        <span>// get the inbox list and bind it to the grid</span>
        List&lt;Email&gt; list = GetMessages();
        BindMessages(list);

        <span>// save off the default page number and folder ID</span>
        ViewState[<span>&quot;PageNum&quot;</span>] = _pageNum;
        ViewState[<span>&quot;FolderID&quot;</span>] = _folderEntryID;
    }

    _pageNum = <span>int</span>.Parse(ViewState[<span>&quot;PageNum&quot;</span>].ToString());
    _folderEntryID = ViewState[<span>&quot;FolderID&quot;</span>].ToString();
}

<span>private</span> <span>void</span> LoadNode(List&lt;Folder&gt; folders, TreeNode node)
{
    <span>foreach</span>(Folder f <span>in</span> folders)
    {
        <span>// add the node with the format of Folder (Unread/Total)</span>
        TreeNode subNode = <span>new</span> TreeNode(f.Name &#43; <span>&quot; (&quot;</span> &#43; f.UnreadMessages &#43; <span>&quot;/&quot;</span> &#43; f.TotalMessages &#43; <span>&quot;)&quot;</span>, f.EntryID);

        <span>// expand and select the inbox</span>
        subNode.Expanded = subNode.Selected = (f.Name == <span>&quot;Inbox&quot;</span>);
        node.ChildNodes.Add(subNode);

        <span>// load the subfolders</span>
        <span>if</span>(f.Folders != <span>null</span>)
            LoadNode(f.Folders, subNode);
    }
}

<span>private</span> List&lt;Email&gt; GetMessages()
{
    <span>// get a group of messages based on the current page number and size</span>
    <span>return</span> <span>this</span>.WHSMailService.GetMessages(_folderEntryID, GridView1.PageSize, _pageNum);
}

<span>private</span> <span>void</span> BindMessages(List&lt;Email&gt; list)
{
    <span>// load the grid</span>
    GridView1.DataSource = list;
    GridView1.DataBind();

    <span>// save off the new page number</span>
    ViewState[<span>&quot;PageNum&quot;</span>] = _pageNum;
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Private</span> _folderEntryID <span>As</span> <span>String</span> = <span>String</span>.Empty
<span>Private</span> _pageNum <span>As</span> <span>Integer</span> = 0

<span>Protected</span> <span>Sub</span> Page_Load(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
    <span>' first time in (tvFolders has viewstate enabled</span>
    <span>If</span> tvFolders.Nodes.Count = 0 <span>Then</span>
        <span>' get the folder tree</span>
        <span>Dim</span> folderList <span>As</span> List(Of Folder) = <span>Me</span>.WHSMailService.GetFolders()

        <span>' add the root node and expand it</span>
        <span>Dim</span> node <span>As</span> TreeNode = <span>New</span> TreeNode(folderList(0).Name, folderList(0).EntryID)
        node.Expanded = <span>True</span>
        tvFolders.Nodes.Add(node)

        <span>' load up the sub-folders</span>
        LoadNode(folderList(0).Folders, node)

        <span>' get the inbox list and bind it to the grid</span>
        <span>Dim</span> list <span>As</span> List(Of Email) = GetMessages()
        BindMessages(list)

        <span>' save off the default page number and folder ID</span>
        ViewState(<span>&quot;PageNum&quot;</span>) = _pageNum
        ViewState(<span>&quot;FolderID&quot;</span>) = _folderEntryID
    <span>End</span> <span>If</span>

    _pageNum = <span>Integer</span>.Parse(ViewState(<span>&quot;PageNum&quot;</span>).ToString())
    _folderEntryID = ViewState(<span>&quot;FolderID&quot;</span>).ToString()
<span>End</span> <span>Sub</span>

<span>Private</span> <span>Sub</span> LoadNode(<span>ByVal</span> folders <span>As</span> List(Of Folder), <span>ByVal</span> node <span>As</span> TreeNode)
    <span>For</span> <span>Each</span> f <span>As</span> Folder <span>In</span> folders
        <span>' add the node with the format of Folder (Unread/Total)</span>
        <span>Dim</span> subNode <span>As</span> TreeNode = <span>New</span> TreeNode(f.Name &amp; <span>&quot; (&quot;</span> &amp; f.UnreadMessages &amp; <span>&quot;/&quot;</span> &amp; f.TotalMessages &amp; <span>&quot;)&quot;</span>, f.EntryID)

        <span>' expand and select the inbox</span>
        subNode.Selected = (f.Name = <span>&quot;Inbox&quot;</span>)
        subNode.Expanded = subNode.Selected
        node.ChildNodes.Add(subNode)

        <span>' load the subfolders</span>
        <span>If</span> <span>Not</span> f.Folders <span>Is</span> <span>Nothing</span> <span>Then</span>
            LoadNode(f.Folders, subNode)
        <span>End</span> <span>If</span>
    <span>Next</span> f
<span>End</span> <span>Sub</span>

<span>Private</span> <span>Function</span> GetMessages() <span>As</span> List(Of Email)
    <span>' get a group of messages based on the current page number and size</span>
    <span>Return</span> <span>Me</span>.WHSMailService.GetMessages(_folderEntryID, GridView1.PageSize, _pageNum)
<span>End</span> <span>Function</span>

<span>Private</span> <span>Sub</span> BindMessages(<span>ByVal</span> list <span>As</span> List(Of Email))
    <span>' load the grid</span>
    GridView1.DataSource = list
    GridView1.DataBind()

    <span>' save off the new page number</span>
    ViewState(<span>&quot;PageNum&quot;</span>) = _pageNum
<span>End</span> <span>Sub</span>
</pre>
</div>
<p>If the <strong>tvFolders</strong> tree-view has not been filled in, we call our host service's
<strong>GetFolders</strong> method from the <strong>WHSMailService</strong> property as defined above.&nbsp; The method then enumerates through the hierarchical list of folders returned, building the same tree structure that exists in Outlook.&nbsp; The
<strong>Text</strong> property of each <strong>TreeNode</strong> is set to the folder name with a count of messages unread and total count of messages.&nbsp; The
<strong>Value</strong> property of the node is set to the unique MAPI-defined <strong>
EntryID</strong> so that we can later grab that value to return the list of messages from that specific folder.</p>
<p>Next, we call our service's <strong>GetMessages</strong> method to return messages from the Inbox.&nbsp; We pass in the value from the grid view's
<strong>PageSize</strong> property and a member variable named <strong>_pageNum</strong>.&nbsp; This will handle our paging scheme as we discussed earlier.&nbsp; Once that list&nbsp;of messages is returned, is it bound to the data grid for display.</p>
<p>Finally, the default page number and folder entry ID (0 and &quot;&quot; respectively) are stored in the
<strong>ViewState</strong> so they can be assigned back to our member variables on each page request.</p>
<p>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.</p>
<p>Next, we will implement what occurs when a user clicks on a folder in the tree view.&nbsp; We simply pull out the MAPI unique
<strong>EntryID</strong> which is stored in the <strong>Value</strong> field of the selected node, assign it to the local member variable and view state, and then call the
<strong>GetMessages</strong> method from our service to return a list of messages from that folder, just as we did with the inbox above.&nbsp; The code below shows the process:</p>
<p><strong>C#</strong></p>
<div>
<pre><span>protected</span> <span>void</span> tvFolders_SelectedNodeChanged(<span>object</span> sender, EventArgs e)
{
    <span>// new folder, so reset the view</span>
    _pageNum = 0;
    _folderEntryID = <span>this</span>.tvFolders.SelectedNode.Value;
    ViewState[<span>&quot;FolderID&quot;</span>] = _folderEntryID;

    List&lt;Email&gt; list = GetMessages();
    BindMessages(list);
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Protected</span> <span>Sub</span> tvFolders_SelectedNodeChanged(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
    <span>' new folder, so reset the view</span>
    _pageNum = 0
    _folderEntryID = <span>Me</span>.tvFolders.SelectedNode.Value
    ViewState(<span>&quot;FolderID&quot;</span>) = _folderEntryID

    <span>Dim</span> list <span>As</span> List(Of Email) = GetMessages()
    BindMessages(list)
<span>End</span> Sub</pre>
</div>
<p>Next, we can implement the Next/Back link buttons.&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.</p>
<p><strong>C#</strong></p>
<div>
<pre><span>protected</span> <span>void</span> btnPrev_Click(<span>object</span> sender, EventArgs e)
{
    <span>// first page</span>
    <span>if</span>(_pageNum &gt; 0)
        _pageNum--;

    List&lt;Email&gt; list = GetMessages();
    BindMessages(list);
}

<span>protected</span> <span>void</span> btnNext_Click(<span>object</span> sender, EventArgs e)
{
    <span>// next page</span>
    _pageNum&#43;&#43;;
    List&lt;Email&gt; list = GetMessages();

    <span>// if we're out of messages, go back to the previous page</span>
    <span>if</span>(list == <span>null</span> || list.Count == 0)
    {
        _pageNum--;
        list = GetMessages();
    }
    BindMessages(list);
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Protected</span> <span>Sub</span> btnPrev_Click(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
    <span>' first page</span>
    <span>If</span> _pageNum &gt; 0 <span>Then</span>
        _pageNum -= 1
    <span>End</span> <span>If</span>

    <span>Dim</span> list <span>As</span> List(Of Email) = GetMessages()
    BindMessages(list)
<span>End</span> <span>Sub</span>

<span>Protected</span> <span>Sub</span> btnNext_Click(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)
    <span>' next page</span>
    _pageNum &#43;= 1
    <span>Dim</span> list <span>As</span> List(Of Email) = GetMessages()

    <span>' if we're out of messages, go back to the previous page</span>
    <span>If</span> list <span>Is</span> <span>Nothing</span> <span>OrElse</span> list.Count = 0 <span>Then</span>
        _pageNum -= 1
        list = GetMessages()
    <span>End</span> <span>If</span>
    BindMessages(list)
<span>End</span> Sub</pre>
</div>
<p>And finally, we need to implement what happens when the user selects a message from the top pane.&nbsp; If you look at the HTML for the
<strong>Default</strong> page, you will see that the Subject field is bound to a <strong>
LinkButton</strong> control in the grid view via a <strong>TemplateField</strong> (the rest of the fields are standard
<strong>BoundField</strong>s.&nbsp; The <strong>LinkButton</strong> sets the <strong>CommandArgument</strong> property to the unique
<strong>EntryID</strong> of that message as defined by MAPI.&nbsp; So, all we need to do is listen on the server for the
<strong>LinkButton</strong>'s <strong>Command</strong> event, grab the unique ID and call our service's&nbsp;<strong>GetMessage</strong> method&nbsp;with that ID to return the message itself.&nbsp;
</p>
<p><strong>C#</strong></p>
<div>
<pre><span>protected</span> <span>void</span> btnLink_Command(<span>object</span> sender, CommandEventArgs e)
{
    Email email = <span>this</span>.WHSMailService.GetMessage(e.CommandArgument.ToString());

    <span>// fill out the header with some basic info</span>
    lblFrom.Text = email.FromName &#43; <span>&quot;&amp;nbsp;(&quot;</span> &#43; email.From &#43; <span>&quot;)&quot;</span>;
    lblSubject.Text = email.Subject;
    lblReceived.Text = email.Received.ToString();

    <span>// when a message is selected, write out the content</span>
    msgContent.InnerHtml = email.Body;
}</pre>
</div>
<p><strong>VB</strong></p>
<div>
<pre><span>Protected</span> <span>Sub</span> btnLink_Command(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> CommandEventArgs)
    <span>Dim</span> email <span>As</span> Email = <span>Me</span>.WHSMailService.GetMessage(e.CommandArgument.ToString())

    <span>' fill out the header with some basic info</span>
    lblFrom.Text = email.FromName &amp; <span>&quot;&amp;nbsp;(&quot;</span> &amp; email.From &amp; <span>&quot;)&quot;</span>
    lblSubject.Text = email.Subject
    lblReceived.Text = email.Received.ToString()

    <span>' when a message is selected, write out the content</span>
    msgContent.InnerHtml = email.Body
<span>End</span> <span>Sub</span>
</pre>
</div>
<p>The <strong>Email</strong> entity is retrieved, its properties are set to the labels in the header, and the message content is assigned to the
<strong>InnerHtml</strong> property of the content holding <strong>&lt;DIV&gt;</strong>.</p>
<p>Voila!&nbsp; A very simple mail reader.</p>
<p>That's it for code.&nbsp; Now we need to deploy the applications and configure Windows Home Server.</p>
<p>&nbsp;</p>
<h3>Deployment</h3>
<h4><strong>WHSMailHost</strong></h4>
<p>If you are deploying to a machine that is not your development machine, install the
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en" target="_blank">
.NET Framework 3.0 runtime</a> on the machine to which you will be running the host service.&nbsp; Then, copy the
<strong>WHSMailHost.exe</strong>, <strong>WHSMailHost.exe.config</strong>, and <strong>
WHSMailCommon.dll</strong>&nbsp;files to the machine running Outlook that will be connected to by the web application.&nbsp;&nbsp;You may want to create a shortcut in the Startup group so it will launch when you log into Windows.</p>
<p>Next, open Outlook and select <strong>Trust Center</strong> from the <strong>Tools</strong> menu.&nbsp; Choose
<strong>Programmatic Access</strong> and set&nbsp;the option to <strong>Never warn me about suspicious activity</strong>.&nbsp; Unfortunately this must be disabled, otherwise Outlook will prompt you every time the host process attempts to retrieve any data.&nbsp; There is
 no way to bypass this on an application-by-application basis, so we have to turn it off for all applications.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/trustcenter_3.png"><img height="266" alt="trustcenter" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/trustcenter_thumb_3.png" width="490" border="0"></a>
</p>
<p>If you are running firewall software on the PC, ensure that port 12345 will allow traffic to pass through.&nbsp; You may also change port 12345 to a different port, but you must change it in the configuration files for both applications.</p>
<p>Finally, note that Outlook does not need to remain open to use this application. You do, however,&nbsp;need to be logged into the machine&nbsp;with the host running.</p>
<h4>WHSMailWeb</h4>
<p>On your Windows Home Server machine, install the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en" target="_blank">
.NET Framework 3.0 Runtime</a>.&nbsp; This is needed to use WCF.&nbsp; Next, create a new directory named
<strong>mail</strong> (or anything you wish, but it is assumed it is named mail) in the
<strong>c:\inetpub</strong> directory.&nbsp; Copy all .aspx pages, web.config, icon.png and the bin directory to the
<strong>mail</strong> directory.&nbsp; You could also share out the <strong>mail</strong> directory and use Visual Studio's
<strong>Publish</strong> command to automatically copy the files to that share.&nbsp; Then, open the
<strong>Internet Information Services (IIS) Manager</strong> application from the
<strong>Administrative Tools</strong> group on the Start menu.&nbsp; Open <strong>Web Sites</strong> and then&nbsp;<strong>Default Web Site</strong> in the left pane.&nbsp; Right-click on
<strong>Default Web Site</strong> and select <strong>New</strong> -&gt; <strong>Virtual Directory...</strong> from the context menu.&nbsp; When prompted, use the following values:</p>
<table cellspacing="0" cellpadding="2" width="223" border="1">
<tbody>
<tr>
<td valign="top" width="93"><strong>Alias</strong></td>
<td valign="top" width="128">mail</td>
</tr>
<tr>
<td valign="top" width="95"><strong>Path</strong></td>
<td valign="top" width="128">c:\inetpub\mail</td>
</tr>
<tr>
<td valign="top" width="97"><strong>Permissions</strong></td>
<td valign="top" width="128">Read, Run Scripts</td>
</tr>
</tbody>
</table>
<p>The next part is a bit tricky.&nbsp; We want to integrate with the security already provided by Windows Home Server.&nbsp; The WHS
<strong>remote</strong> website uses Forms security from ASP.NET.&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.&nbsp; Additionally, if the
<strong>mail</strong> URL is used directly, you should be prompted for your login credentials.</p>
<p>To achieve this, open the <strong>web.config</strong> file from <strong>c:\inetpub\remote
</strong>in Notepad.&nbsp; In the XML, between the start and end <strong>&lt;system.web&gt;</strong> tags you will find the configuration for the Forms-based authentication used by WHS.&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.&nbsp; The easiest way to achieve this is to copy all of the the text&nbsp;between the two
<strong>&lt;system.web&gt;</strong> tags.&nbsp; Next, open the web.config file from the <strong>
mail</strong> directory that you just copied over and&nbsp;paste the text&nbsp;between the two lines informing you to do so.&nbsp; Finally, we need to update the
<strong>loginUrl</strong> and <strong>defaultRedirect</strong> paths in the <strong>
forms</strong> and <strong>customErrors</strong> keys.&nbsp; Add <strong>/remote/</strong> to the beginning of each to make them
<strong>/remote/login.aspx</strong> and <strong>/remote/error.aspx</strong>.&nbsp; Be sure that the
<strong>SERVERNAME</strong> item in the endpoint configuration is updated to the name/IP address of the machine running the host process.</p>
<p>With the files copied and edited, ensure that permissions on the file are propagated from the root
<strong>mail</strong> directory to the files inside.</p>
<p>Finally, open the <strong>websites.xml</strong> file in the <strong>/remote</strong> directory and add the following XML before the end
<strong>&lt;/WebSites&gt;</strong> tag:</p>
<div>
<pre><span>&lt;</span><span>WebSite</span> <span>name</span><span>=&quot;Outlook Webmail&quot;</span> <span>uri</span><span>=&quot;/mail&quot;</span> <span>imageUrl</span><span>=&quot;/mail/icon.png&quot;</span> <span>absolute</span><span>=&quot;false&quot;</span><span>&gt;&lt;/</span><span>WebSite</span><span>&gt;</span></pre>
</div>
<p>With the configuration done, we need to enable web site connectivity in WHS.&nbsp; Double-click the Windows Home Server Console icon on the desktop.&nbsp; When it loads, click the
<strong>Settings</strong> button in the top right corner.&nbsp; When the <strong>Settings</strong> dialog appears, select
<strong>Remote Access</strong> in the left pane and then click the <strong>Turn On</strong> button in the right pane, assuming web site connectivity is off.&nbsp; If it already enabled, skip this step.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/whssettings_3.png"><img height="353" alt="whssettings" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/whssettings_thumb_3.png" width="490" border="0"></a>
</p>
<p>With all that done, create a user account for yourself in WHS so that you can login remotely.&nbsp; That's it!</p>
<h3>Running the Application</h3>
<p>Ensure the <strong>WHSMailHost</strong> application is running on the PC with Outlook installed.&nbsp; Then, browse to your Windows Home Server's default website.&nbsp; After logging in, you should see a link on the right side of the screen named
<strong>Outlook Webmail</strong>.&nbsp; </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/web_3.png"><img height="239" alt="web" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4320362/web_thumb_3.png" width="490" border="0"></a>
</p>
<p>Click that to start our application and if everything is working, you should see the web page as shown above.</p>
<h3>Troubleshooting</h3>
<p>If the web page displays an error message, open the <strong>web.config</strong> file in the
<strong>mail</strong> directory on your Windows Home Server.&nbsp; Look for the <strong>
&lt;customErrors&gt;</strong> tag and change the <strong>mode</strong> parameter to <strong>
Off</strong>.&nbsp; This should allow you to see the actual error that is occurring and provide more information as to the status of the application.</p>
<h3>Conclusion</h3>
<p>Phew!&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.&nbsp; Currently the application is read-only and provides only minimal functionality.&nbsp; It's
 a great starting point to create a full-fledged webmail client interface.&nbsp; The project is hosted on CodePlex so I'm hoping to see you readers implement additional features and functionality that you find useful.</p>
<h3>Additional Information</h3>
<p>Here are a few links with additional information on the items discussed here:</p>
<ul>
<li><a href="http://msdn2.microsoft.com/en-us/library/bb425866.aspx" target="_blank">Windows Home Server SDK Documentation</a>
</li><li><a href="http://msdn2.microsoft.com/en-us/netframework/aa663324.aspx" target="_blank">Windows Communication Foundation (WCF) Site</a>
</li><li><a href="http://msdn2.microsoft.com/en-us/library/bb187379.aspx" target="_blank">Outlook 2007 Primary Interop Assembly Reference</a></li></ul>
<h3>Bio</h3>
<p>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 &quot;coding for fun&quot; for as long as he can remember.&nbsp; Outside the world of .NET and&nbsp;business applications, Brian enjoys developing&nbsp;both hardware and software projects in the areas of gaming, robotics, and&nbsp;whatever else strikes his fancy for the next ten minutes.&nbsp;He
 rarely passes up an opportunity to dive into a C/C&#43;&#43;&nbsp;or assembly language project.&nbsp; You can reach Brian via his blog at
<a href="http://www.brianpeek.com/">http://www.brianpeek.com/</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:d5ae34d3a6754ac885ec9e7600d2e120">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Outlook-Webmail-Add-in-for-Windows-Home-Server</comments>
      <itunes:summary>





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.



Brian Peek
ASPSOFT, Inc.

Difficulty: Intermediate
Time Required: 2-3 hours
Cost: Free
Software: Windows Home Server,&amp;nbsp;Microsoft
 Outlook 2000/XP/2003/2007 (not Outlook Express/Windows Mail),&amp;nbsp;Visual Basic or Visual C# Express Editions,
Visual Web Developer Express Edition,

Microsoft .NET Framework 3.0 runtime, Outlook/Office Primary Interop Assemblies (more on this below),&amp;nbsp;Windows SDK
 (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.)
Hardware: None
Download: CodePlex Project




Introduction
Windows Home Server&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. 
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. 
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&#39;m away from home for work or pleasure,&amp;nbsp;it&#39;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;we</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Outlook-Webmail-Add-in-for-Windows-Home-Server</link>
      <pubDate>Fri, 10 Aug 2007 08:33:56 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Outlook-Webmail-Add-in-for-Windows-Home-Server</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/4320362_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/4320362_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Brian Peek</dc:creator>
      <itunes:author>Brian Peek</itunes:author>
      <slash:comments>20</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Outlook-Webmail-Add-in-for-Windows-Home-Server/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>utility</category>
      <category>Web</category>
      <category>Web Services</category>
      <category>Windows</category>
      <category>windows miscellaneous</category>
      <category>web miscellaneous</category>
    </item>
  <item>
      <title>Amazon Mobile: Book Shopping from your Smartphone</title>
      <description><![CDATA[<span id="c4fmetadata">
<table cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td><span class="entry_description">This article walks the reader through the development of a Windows Mobile 5.0 application that interacts with Amazon's E-Commerce Service (ECS). I cover set up of the development environment and much of the code that is needed.
 Readers can download the C# or VB.NET source code that accompanies the article.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Will Danford</div>
<div class="entry_company"><a href="http://www.claritycon.com">Clarity Consulting</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Greater than $200</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://www.microsoft.com/windowsmobile/activesync/activesync42.mspx">ActiveSync 4.2</a>
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9655156b-356b-4a2c-857c-e62f50ae9a55&amp;DisplayLang=en">
.NET Compact Framework</a> <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738a-4b97-8910-5cd29ab5f8d9&amp;DisplayLang=en">
Windows Mobile 5.0 SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">Motorola Q</span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/AmazonMobileCS.zip">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/AmazonMobileVB.zip">VB Download</a>
</li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p></p>
<h3>Introduction</h3>
<p><b></b></p>
<p>In this article I'll examine part of Amazon's web service functionality and use the new Pocket Outlook API to create a useful application for the Windows Mobile 5.0 Smartphone. The current version of the application lets the user search Amazon's inventory,
 view book details, create and edit a cart, and checkout from the device. A Pocket Outlook task is used to store the cart's checkout link.
</p>
<h3><a></a>Development Environment</h3>
<p>I wrote Amazon Mobile using Visual Studio 2005 Professional and a Motorola Q Smartphone running Windows Mobile 5.0. Windows Mobile devices use Microsoft's
<a href="http://www.microsoft.com/windowsmobile/activesync/activesync42.mspx">ActiveSync</a> software to synchronize with a desktop, so you'll need to have it installed to set up the environment on the phone. Next you'll need the
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9655156b-356b-4a2c-857c-e62f50ae9a55&amp;DisplayLang=en">
.NET Compact Framework</a>, since this application is written in managed code.&nbsp; Lastly, download the appropriate software development kit (SDK) for your platform. I installed the
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738a-4b97-8910-5cd29ab5f8d9&amp;DisplayLang=en">
Windows Mobile 5.0 SDK for Smartphone</a> because I am writing code for the Q. If you are using a Pocket PC device you should download and install the
<a href="http://www.microsoft.com/downloads/info.aspx?na=22&amp;p=5&amp;SrcDisplayLang=en&amp;SrcCategoryId=8&amp;SrcFamilyId=&amp;u=%2fdownloads%2fdetails.aspx%3fFamilyID%3d83a52af2-f524-4ec5-9155-717cbe5d25ed%26DisplayLang%3den">
Pocket PC version</a>. The rest of this article will assume that you are writing a Smartphone application, but if that is not the case you will find it easy enough to follow along using a Pocket PC device.
</p>
<p>Readers who are not familiar with Amazon's web service may find it helpful to review Peter Bernhardt's introduction in
<a href="http://msdn.microsoft.com/coding4fun/web/services/article.aspx?articleid=912260">
this</a> previous Coding4Fun article. I used <a href="http://www.amazon.com/E-Commerce-Service-AWS-home-page/b/ref=sc_fe_l_2/104-6363289-8583963?ie=UTF8&amp;node=12738641&amp;no=3435361&amp;me=A36L942TSJ2AJA">
ECS version 4.0</a> for this project. You won't have to download an SDK as in version 3.0, but you will need to create an account with Amazon to get a unique access key. Make sure to replace the “Your Access Key Here” string in Constants.cs with your own access
 key before running my code. </p>
<p>Once you've set up your dev environment, start by creating a new project for your application. Select
<i>New &gt; Project</i> from Visual Studio's File menu. You'll find the Device Application template under
<i>Visual C# &gt; Smart Device &gt; Windows Mobile 5.0 Smartphone</i> in the Project Types tree on the left side of the New Project dialog.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig18.gif"><img height="363" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig1_thumb4.gif" width="500"></a>
</p>
<p>Figure 1: The New Project dialog. </p>
<p>Visual Studio will use the default resolution and DPI settings of the current “form factor” to create the form you see in the designer. If you open a project written for a device with a 320x240 screen (such as the project I wrote for this article) before
 changing the settings, the IDE will move or resize the contents of the forms to make them fit the smaller 176x220 resolution. You can prevent this by changing the designer's form factor to match that of the Q. Choose
<i>Tools &gt; Options</i>, and then expand “Device Tools” in the tree on the left side of the dialog and select “Form Factors.” Find “Windows Mobile 5.0 Smartphone” in the menu and edit its properties. Clear the “Enable rotation support” checkbox and make sure
 that both the horizontal and vertical resolutions are set to 131 pixels per inch. Now clear the “Show Skin” checkbox and enter 320 for the screen width and 240 for the screen height. You can save this form factor with a new name, such as “MotoQ,” and make
 it your default if you prefer. </p>
<h3><a></a>Writing the Application</h3>
<p>Now let's get started in the code. First you'll need to add a reference to Amazon's Web Services Definition (Description) Language (WSDL). The web reference wizard will use the WSDL to create a proxy class that you'll use to access the service's functionality.
 Right-click on “Web References” in Solution Explorer, select “Add Web Reference” and enter the address of the
<a href="http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl">
WSDL</a> as shown in the figure below. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig22.gif"><img height="355" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig2_thumb.gif" width="500"></a>
</p>
<p>Figure 2: Feel free to change the unwieldy name that Visual Studio assigns your Web reference.
</p>
<p>Visual Studio has created a startup form that, by default, is the entry and exit point for your application. This form is a great place to accept search criteria from the user and display the results you get back from the web service. Find the Toolbox and
 add a TextBox control to your form to capture the user's input. You'll also need a ListView control to display the results. The softkey menu that's built into the default Smartphone form is a convenient way to let the user start the search. Add a MenuItem
 and handle its click event to call the search method you're about to write. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig32.gif"><img height="259" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig3_thumb.gif" width="336"></a>
</p>
<p>Figure 3: The SearchForm. </p>
<p>Make sure you've set a reference to the namespace created by the WSDL wizard in a using statement at the top of your code. To perform a keyword search against Amazon's product database, start by creating an ItemSearchRequest object and setting a few of its
 properties. ItemSearchRequest is declared as a partial class in the web reference's Reference.cs file, along with all of the other ECS classes. Here is the code I used to set up the search:
</p>
<pre class="csharpcode"><span class="kwrd">Imports</span> AmazonMobile.com.amazon.webservices

...

<span class="kwrd">       Private</span> <span class="kwrd">Sub</span> PerformSearch(<span class="kwrd">ByVal</span> searchText <span class="kwrd">As</span> <span class="kwrd">String</span>)
            <span class="kwrd">Dim</span> aws <span class="kwrd">As</span> <span class="kwrd">New</span> AWSECommerceService()

            <span class="rem">' set up the request</span>
            <span class="kwrd">Dim</span> itemSearchRequest <span class="kwrd">As</span> <span class="kwrd">New</span> ItemSearchRequest()
            itemSearchRequest.Keywords = searchText
            itemSearchRequest.SearchIndex = <span class="str">&quot;Books&quot;</span>
            itemSearchRequest.ResponseGroup = <span class="kwrd">New</span> <span class="kwrd">String</span>() {<span class="str">&quot;ItemAttributes&quot;</span>}
            itemSearchRequest.ItemPage = <span class="str">&quot;1&quot;</span>

            <span class="kwrd">Dim</span> itemSearch <span class="kwrd">As</span> <span class="kwrd">New</span> ItemSearch()
            itemSearch.Request = <span class="kwrd">New</span> ItemSearchRequest(0) {itemSearchRequest}
            itemSearch.SubscriptionId = Constants.AMAZON_ACCESS_KEY</pre>
<pre class="csharpcode">&nbsp;</pre>
<pre class="csharpcode"><span class="kwrd">using</span> AmazonMobile.com.amazon.webservices;

...</pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> PerformSearch(<span class="kwrd">string</span> searchText)
{
    Cursor.Current = Cursors.WaitCursor;
    
    <span class="rem">// clear out old results</span>
    resultsView.Clear();

    AWSECommerceService aws = <span class="kwrd">new</span> AWSECommerceService();
    
    <span class="rem">// set up the request</span>
    ItemSearchRequest itemSearchRequest = <span class="kwrd">new</span> ItemSearchRequest();
    itemSearchRequest.Keywords = searchText;
    itemSearchRequest.SearchIndex = <span class="str">&quot;Books&quot;</span>;
    itemSearchRequest.ResponseGroup = <span class="kwrd">new</span> <span class="kwrd">string</span>[] { <span class="str">&quot;ItemAttributes&quot;</span> };
    itemSearchRequest.ItemPage = <span class="str">&quot;1&quot;</span>;
    
    ItemSearch itemSearch = <span class="kwrd">new</span> ItemSearch();
    itemSearch.Request = <span class="kwrd">new</span> ItemSearchRequest[1] { itemSearchRequest };
    itemSearch.SubscriptionId = Constants.AMAZON_ACCESS_KEY;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Notice that I've set the ResponseGroup property to a string array containing the string “ItemAttributes.” The web service uses the values in this array to determine the subset of fields it should populate in the response object. You'll find a list of all
 possible options in the web service's <a href="http://docs.amazonwebservices.com/AWSEcommerceService/2006-11-14/">
documentation</a>, a helpful guide to the functionality that the service exposes. Now you can ask the web service to perform the search.</p>
<pre class="csharpcode"><span class="rem">// perform the search</span>
ItemSearchResponse itemSearchResponse = aws.ItemSearch(itemSearch);
Items[] itemsResponse = itemSearchResponse.Items;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<pre class="csharpcode"><span class="rem">'perform the search</span>
<span class="kwrd">Dim</span> response <span class="kwrd">As</span> ItemSearchResponse = aws.ItemSearch(itemSearch)
<span class="kwrd">Dim</span> itemsResponse <span class="kwrd">As</span> Items() = response.Items</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Almost every interaction with ECS will follow the straightforward pattern you've just seen. First, create and set the properties of one or more request objects. Next, create the appropriate search object and use its properties to wrap one or more request
 objects, as well as your ECS access key. Finally, pass the search object to the appropriate web service method. The results of your request will be encapsulated by the object that is returned from the web service. You'll use the response object's properties
 to access the information that you want to display. Loop through the response object's Item collection, adding a new ListViewItem to the ListView's Items collection for each of the results. You can use the ListViewItem's Tag property to store the item's Amazon
 Standard Identification Number (ASIN) for future reference. In most cases, a book's ASIN is simply its ISBN.
</p>
<p>The next step is creating a form to lookup any offers that might be associated with a search result. Right-click on the project node in Solution Explorer and select
<i>Add &gt; Windows Form</i> from the context menu. Give your form a name and click “Add” to create it in your project. For the offer form you'll probably want a ListView control to display the results of your lookup operation, as well as a few menu items at the
 bottom of the form for navigation. If you add a back button to the menu to return to the previous form the button's event handler should call the form's Close method.
</p>
<p>In my code I construct an OfferForm using an ASIN string, which simply sets an instance variable to track the book associated with the current instance of the form. Your application will use a book's ASIN to lookup offers. You already know the item's ASIN,
 so you should create an ItemLookupRequest, in this case, instead of the ItemSearchRequest that you used to perform the initial search. You'll need to set the properties of one or more of the request objects and then set the ItemLookup's Request property as
 I did above. Finally, call the ItemLookup method on your instance of the web service and use the resulting ItemLookupResponse object to populate the ListView object. I suggest doing all this in a method that can be called by the form's Load event handler rather
 than the constructor. That way you'll avoid any conflicts that might occur if the form has not finished initializing its controls when you begin setting their properties.
</p>
<p>Next you need a method to create a cart when the user selects an offer and since you don't want to create a new cart every time, you'll also want to be able to add an offer to a cart that already exists. A mechanism for writing information about a cart to
 the file system would be helpful. These are the functions of the Settings and SettingsManager classes that I've created to store the cart's ID and HMAC key. Take a look at the OnAddItem, CreateCart and GetCart methods to see how I implemented add and edit
 operations for the cart. </p>
<p>Amazon cart response objects have a PurchaseURL property that contains a URL string used to access the cart's checkout page. Once you have a cart with at least one item you should provide the user with access to this URL. I wanted to make use of the new
 Pocket Outlook API, so I added a Checkout method that stores the cart's purchase URL in the Body property of a new Pocket Outlook task. The Task class is part of the Microsoft.WindowsMobile.PocketOutlook namespace, so you'll need to add another reference to
 your project. Once you've done so, creating and adding a new task is simple: </p>
<pre class="csharpcode"><span class="kwrd">Imports</span> Microsoft.WindowsMobile.PocketOutlook

...</pre>
<pre class="csharpcode">        <span class="kwrd">Private</span> <span class="kwrd">Sub</span> Checkout()
            <span class="rem">' warn the user that the cart will no longer be accessible</span>
            <span class="kwrd">If</span> MessageBox.Show(Constants.MESSAGE_CHECKOUT_CONFIRMATION, Constants.CAPTION_CHECKOUT, MessageBoxButtons.OKCancel, MessageBoxIcon.None, MessageBoxDefaultButton.Button1) = Windows.Forms.DialogResult.OK <span class="kwrd">Then</span>
                <span class="rem">' Outlook Session implements IDisposable...</span>
                <span class="kwrd">Dim</span> session <span class="kwrd">As</span> <span class="kwrd">New</span> OutlookSession()
                <span class="kwrd">Try</span>
                    <span class="kwrd">Dim</span> task <span class="kwrd">As</span> <span class="kwrd">New</span> Task()
                    task.Body = <span class="kwrd">String</span>.Format(Constants.MESSAGE_TASK_BODY, _purchaseUrl)
                    task.Subject = <span class="kwrd">String</span>.Format(<span class="str">&quot;{0}, {1}&quot;</span>, Constants.CAPTION_CHECKOUT, DateTime.Now.ToLocalTime())
                    task.Complete = <span class="kwrd">False</span>
                    session.Tasks.Items.Add(task)
                <span class="kwrd">Finally</span>
                    session.Dispose()
                <span class="kwrd">End</span> <span class="kwrd">Try</span>

                <span class="rem">' clear the contents of the local cart</span>
                LocalCartReset()
                <span class="rem">' reset the user interface</span>
                OnCartEmpty(Constants.MESSAGE_CHECKOUT_COMPLETED)
            <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">End</span> <span class="kwrd">Sub </span><span class="rem">' Checkout </span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<pre class="csharpcode"><span class="kwrd"></span>&nbsp;</pre>
<pre class="csharpcode"><span class="kwrd">using</span> Microsoft.WindowsMobile.PocketOutlook; 

… 

<span class="kwrd">private</span> <span class="kwrd">void</span> Checkout() 
{ 
    <span class="rem">// warn the user that the cart will no longer be accessible </span>
    <span class="kwrd">if</span> (DialogResult.OK == MessageBox.Show(Constants.MESSAGE_CHECKOUT_CONFIRMATION,
            Constants.CAPTION_CHECKOUT, MessageBoxButtons.OKCancel, MessageBoxIcon.None, 
            MessageBoxDefaultButton.Button1)) 
    { 

        <span class="rem">// Outlook Session implements IDisposable </span>
        <span class="kwrd">using</span> (OutlookSession session = <span class="kwrd">new</span> OutlookSession()) 
        {
            Task task = <span class="kwrd">new</span> Task(); 
            
            task.Body = <span class="kwrd">string</span>.Format(Constants.MESSAGE_TASK_BODY, _purchaseUrl); 
            task.Subject = <span class="kwrd">string</span>.Format(<span class="str">&quot;{0}, {1}&quot;</span>, Constants.CAPTION_CHECKOUT, DateTime.Now); 
            task.Complete = <span class="kwrd">false</span>; 
            
            session.Tasks.Items.Add(task); 
        } 

        <span class="rem">// clear the contents of the local cart </span>
        LocalCartReset(); 

        <span class="rem">// reset the user interface </span>
        OnCartEmpty(Constants.MESSAGE_CHECKOUT_COMPLETED); 
    } 
} 
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>I reset the local cart's contents after storing the task because Amazon recommends that a cart no longer be used once a purchase is submitted. I don't know when my user will complete the transaction, so I make sure that my application can't access the cart
 again by clearing any saved information. It's worth noting that, for performance reasons, Microsoft suggests reusing the OutlookSession object for the life of the application rather than taking the above approach. My code has infrequent need of the task collection,
 however, so I've chosen to release the session's resources instead. </p>
<p>Once you have written the code to create a cart and edit its contents you should go back to your search form and handle the ListView's ItemActivate event. When someone selects an item from the list, your event handler should instantiate a new form to lookup
 offers for the item. In this case, it is best to do this <i>modally</i>, which means that execution in the search form halts until the OfferForm has been closed. Instantiate a new OfferForm and call ShowDialog:
</p>
<pre class="csharpcode"><span class="kwrd">using</span> (OfferForm offerForm = <span class="kwrd">new</span> OfferForm(_asin)) 
{ 
    <span class="rem">// the next line of code shows the OfferForm modally </span>
    offerForm.ShowDialog(); 
} </pre>
<pre class="csharpcode">&nbsp;</pre>
<pre class="csharpcode">Using offerForm <span class="kwrd">As</span> OfferForm = <span class="kwrd">New</span> OfferForm(_asin)
     offerForm.ShowDialog()
<span class="kwrd">End</span> Using</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>When the OfferForm is closed the search form will exit the using statement, calling the Dispose method on the OfferForm to release its resources.
</p>
<h3><a></a>Debugging</h3>
<p>If you have a Motorola Q or any other Windows Mobile 5.0 Smartphone with a landscape resolution, debugging your code is as simple as connecting the device and then selecting “Windows Mobile 5.0 Smartphone Device” from the dropdown in the Debugging toolbar.
 When you start debugging, the IDE will deploy both your code and, depending on your configuration, the .NET Compact Framework to the device through ActiveSync.
</p>
<p>If you don't have the hardware you want to use yet, don't worry. You can use an emulator to create a virtual device for testing your code. The emulator that ships with Visual Studio supports only portrait Smartphone layout, however, so the first thing you'll
 need is Microsoft's <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=eb580a44-cb40-4be1-9ff3-e224bf669cd0&amp;DisplayLang=en">
Emulator Image for Windows Mobile 5.0 Smartphone with 320x240 (Landscape) Screen</a>. Next you'll want to download the Q skin plug-in, which you should be able to find at
<a href="http://www.motocoder.com/">www.motocoder.com</a>, and you may find the <a href="http://developer.motorola.com/docstools/developerguides/">
MOTO Q Developer Guide</a> useful for the installation. Your emulator will not have a network connection when first installed but this
<a href="http://blogs.msdn.com/akhune/archive/2005/11/16/493329.aspx">post</a> will help you get one configured. Select your emulator from the Debug toolbar dropdown and press F5 when you're ready to debug.
</p>
<p>&nbsp; <a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig42.gif">
<img height="454" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1352373/fig4_thumb.gif" width="451"></a>
</p>
<p>Figure 4: Amazon Mobile in action on the Q emulator. </p>
<h3><a></a>Conclusion</h3>
<p>As we've seen, the .NET Compact Framework makes distributed applications such as this one as easy to write for the mobile device as they are for the desktop. With much of the processing and storage done server-side, the scaled down processor and memory of
 the phone aren't a problem for most applications. Check back soon – my next version (v2.0) of Amazon Mobile will hopefully feature the device's camera as an ISBN scanner using the framework's new CameraCaptureDialog class.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:1235501ef3cb4cd6b0839e7600d6e5b5">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Amazon-Mobile-Book-Shopping-from-your-Smartphone</comments>
      <itunes:summary>



&amp;nbsp;
This article walks the reader through the development of a Windows Mobile 5.0 application that interacts with Amazon&#39;s E-Commerce Service (ECS). I cover set up of the development environment and much of the code that is needed.
 Readers can download the C# or VB.NET source code that accompanies the article.



Will Danford
Clarity Consulting

Difficulty: Intermediate
Time Required: 
3-6 hours
Cost: Greater than $200
Software: ActiveSync 4.2

.NET Compact Framework 
Windows Mobile 5.0 SDK
Hardware: Motorola Q
Download: 

C# Download
VB Download







 
Introduction
 
In this article I&#39;ll examine part of Amazon&#39;s web service functionality and use the new Pocket Outlook API to create a useful application for the Windows Mobile 5.0 Smartphone. The current version of the application lets the user search Amazon&#39;s inventory,
 view book details, create and edit a cart, and checkout from the device. A Pocket Outlook task is used to store the cart&#39;s checkout link.
 
Development Environment
I wrote Amazon Mobile using Visual Studio 2005 Professional and a Motorola Q Smartphone running Windows Mobile 5.0. Windows Mobile devices use Microsoft&#39;s
ActiveSync software to synchronize with a desktop, so you&#39;ll need to have it installed to set up the environment on the phone. Next you&#39;ll need the

.NET Compact Framework, since this application is written in managed code.&amp;nbsp; Lastly, download the appropriate software development kit (SDK) for your platform. I installed the

Windows Mobile 5.0 SDK for Smartphone because I am writing code for the Q. If you are using a Pocket PC device you should download and install the

Pocket PC version. The rest of this article will assume that you are writing a Smartphone application, but if that is not the case you will find it easy enough to follow along using a Pocket PC device.
 
Readers who are not familiar with Amazon&#39;s web service may find it helpful to review Peter Bernhardt&#39;s introduction in

this previous Coding4Fun article. I </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Amazon-Mobile-Book-Shopping-from-your-Smartphone</link>
      <pubDate>Sat, 23 Dec 2006 14:32:19 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Amazon-Mobile-Book-Shopping-from-your-Smartphone</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1352373_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1352373_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Will Danford</dc:creator>
      <itunes:author>Will Danford</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Amazon-Mobile-Book-Shopping-from-your-Smartphone/RSS</wfw:commentRss>
      <category>Web Services</category>
      <category>windows miscellaneous</category>
    </item>
  <item>
      <title>Extending the Screen Saver Starter Kit with Microsoft Visual Basic Express</title>
      <description><![CDATA[
<p><b>Introduction</b></p>
<p>Visual Studio 2005 Express is the most comprehensive and full- featured interactive development environment (IDE) released to date. As part of the product mix, Microsoft has announced a series of Express editions, which make this power available to anyone
 for almost no investment. In this article, we'll explore the installation of one of the editions—Visual Basic—and then use one of the &quot;Starter Kits&quot; included with each Express edition to build and customise a screen saver.
</p>
<p><b>Installing Visual Basic Express Edition</b></p>
<p><b></b>First, you'll need to install Visual Basic Express Edition (from now on, I'll just refer to it as Visual Basic Express). You can download it from the
<a href="http://msdn.microsoft.com/vstudio/express/vb/download/">Visual Basic Express</a> website.
</p>
<ol>
<li>Run the vbsetup.exe file you downloaded from the Visual Basic Express site. After the installer has copied some setup files to your hard drive, you should see the screen shown in Figure 1. I'd strongly encourage you to check the box that allows the installer
 to gather information and send it to Microsoft. This information is used to make the setup process as seamless as possible.
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/1.gif" width="440" border="0">
</p>
<p><b>Figure 1: Initial screen for Visual Basic Express Edition Setup</b></p>
</li><li>Click the Next button and you will see the End User License Agreement screen. Accept the agreement and click the Next button again.
</li><li>You're now at the screen that allows you to choose which of the optional components (in addition to Visual Basic Express) you want to install. If you've got the disk space (about 1.3 GB for the install process and about 500 MB once the install is complete
 and all of the temporaray installation files have been removed) spare, I'd encourage you to install both the MSDN Express Library 2005 and SQL Server 2005 Express Edition April CTP. The MSDN Express Library is the documentation (tailored for the Express editions)
 and SQL Server 2005 Express is the SQL Server engine (with a few limitations). </li><li>Click the Next button and you'll be prompted for the installation path. Either accept the default or browse to choose another.
</li><li>Click the Next button and the install will begin. Progress will be displayed for each of the components to be installed as shown in Figure 2.
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/2.gif" width="440" border="0">
</p>
<p><b>Figure 2: Setup is progressing</b></p>
</li><li>Along the way, you may well be prompted to restart you machine. If it's not convenient to restart now, you can choose to restart later, but you will have to manually restart the setup process after doing so. If you choose to restart now, the setup process
 will continue seamlessly after you've logged back in. </li><li>Once you've completed the setup process, you will be greeted with the screen shown in Figure 3. At some stage in the next 30 days you'll need to register your copy of Visual Basic Express and you can do it now by clicking on the link in the dialog or do
 it later by choosing Product Activation from the help menu in Visual Basic Express. Either way, registering will give you free access to the online e-book,
<i>Writing Secure Code 2nd ed.</i> by Michael Howard and Davis LeBlanc.
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/3.gif" width="440" border="0">
</p>
<p><b>Figure 3: Setup's done its thing. The rest is up to you.</b></p>
</li><li>The final setup step is to start Visual Basic Express. Choose Start, All Programs, Visual Basic 2005 Express Edition.
</li></ol>
<p><b>Building a Screen Saver using the Starter Kit</b> </p>
<p>All of the Visual Studio Express Editions come with one or more Starter Kits—pre-configured applications from which you can learn, and which you can adjust. Visual Basic Express comes with a Movie Database tracking application and a Screen Saver. These applications
 demonstrate best practices in coding and also showcase a number of the great new features in the language, the framework and the development environment. There are also a number of other starter kits being developed, both by Microsoft and by members of the
 developer community. </p>
<p>In this article we'll concentrate on the Screen Saver. First we'll explore the functionality that comes with the application as it ships, and then we'll make a couple of adjustments to personalize it and to demonstrate another very powerful feature: calling
 a web services. </p>
<p><b>Creating a new project</b> </p>
<p>Click the New Project button on the main toolbar or choose File, New Project from the menu. In the dialog box, choose a name for your project (I've called mine
<b>mySS</b> if you're typing along) and a location. Make sure you've selected the Screen Saver starter kit as shown in Figure 4.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/5.gif"><img height="295" alt="Click here for 
larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/5.gif" width="485" border="0"></a>
</p>
<p><b>Figure 4: Let's start at the very beginning (click image to zoom)</b> </p>
<p>Visual Basic Express goes away and creates a new project based on the Screen Saver Starter Kit and then opens it in the IDE. The file that you see open is the documentation explaining how the application works and what to do to build and install it.
</p>
<p><b>Building the screen saver</b> </p>
<p>Press the F5 key to build and run the Screen Saver application. If you're connected to the Internet, you'll get an image (probably of a chess board) and a list of articles from the MSDN Visual Basic RSS feed. The currently highlighted article will have a
 description or précis displayed on the right-hand side of the screen. </p>
<p><b>Installing your creation to your desktop</b> </p>
<p>To install your screen saver, follow the instructions in the documentation, that is:
</p>
<ol>
<li>If you haven't already done so, load the Starter Kit into Visual Basic. </li><li>On the File menu, click <b>Save All</b>. </li><li>If you are requested to enter a location to save the project, select a directory or accept the default location. Make a note of where the project is saved; by default it will be in a directory under
<b>\My Documents\Visual Studio 2005\Projects</b>. </li><li>On the <b>Build</b> menu, click <b>Build Solution</b>. This creates an executable file for the screen saver.
</li><li>Open up the directory specified in step 3 containing the saved project. </li><li>Open the <b>bin</b> subdirectory. You will see two files: <b>ssNews.scr</b> and
<b>ssNews.scr.config</b>. </li><li>Copy these two files to your Windows directory. If you are using Windows XP, this is \Windows\System32 in your system drive. If you are using Windows 2000, it is \WinNT\System32.
</li><li>Open <b>Control Panel</b>, click <b>Appearance and Themes</b> if using the <b>
Category View</b>, and open the <b>Display Properties</b> dialog box. </li><li>Click the <b>Screen Saver</b> tab. </li><li>Click the <b>Screen Saver</b> drop-down list, and select <b>News</b>. </li><li>Click the <b>Preview</b> button.<br>
The screen saver launches. Press any key to stop it. </li><li>Click the <b>Settings</b> button to see the screen saver options. Try changing the background image or the RSS feed.
</li><li>Click <b>OK</b>. </li></ol>
<p><b>Make your Screen Saver do what you want it to do</b></p>
<p><b></b>It's all very well having the Screen Saver do what the designer of the Starter Kit wanted it to, but it's much more fun if you get it what you want it to do.
</p>
<p><b>Getting images based on a keyword or at random</b></p>
<p><b></b>I decided that instead of picking up a set of images from a folder on my hard drive, I'd rather the screen saver selected a number of images from the web at random. I looked for a web service that would do this for me in the public directory of Web
 Services at Web Methods. I found one called getRandomGoogleSearch. This web service takes a single parameter (a string) and returns a URL pointing to an image related to that string. If the string passed is empty, it chooses a random English word and uses
 that as the seed word. </p>
<p>The other important piece of information (apart form the description of the functionality) in the directory is the URL of the Web Services Description Language (WSDL) for this service. This is the metatdata in XML format that tells an application calling
 the service all about what information is required and what's returned. In this case, the WSDL is at
<a href="http://www.ghettodriveby.com/soap/?wsdl">http://www.ghettodriveby.com/soap/?wsdl</a>.
</p>
<p>To get Visual Basic Express to be able to use this web service, right click on the references node in the Project Explorer pane and choose Add Web Reference. In the dialog, enter the WSDL URL and click the Go button. Once the WSDL has been retrieved, either
 accept the default name for the service or choose a new (possibly shorter) name. I chose GoogleImage.
</p>
<p>Clicking the Add Reference button will generate all of the reference code to enable your application to treat the web service as just another component. This will all come together in a little while when I show you the code used to get the image.
</p>
<p><b>Storing information between sessions<br>
</b></p>
<p><b></b>One of the things that's got significantly easier with Visual Studio 2005 is the persistence of settings and configuration between sessions of an application. In our case, we want to save the keyword for which images are retrieved and the total number
 of images we want to load into the screen saver cache. </p>
<p>To set up these settings, expand the Properties node in the Solution Explorer and double-click on the settings.settings file. You will see a grid with all of the settings like the one shown in Figure 5. Add a user-level
<code>string</code> setting called Keyword and leave its value blank. Add a user-level
<code>int</code> setting called <code>ImageCount</code> and set its default value to 5.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/7.gif"><img height="191" alt="Click here for 
larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/7.gif" width="485" border="0"></a>
</p>
<p><b>Figure 5: Saving settings is easier than ever before (click image to zoom) </b>
</p>
<p>We now need to adjust the mechanism for the user to adjust and save these settings. In the Solution Explorer, double-click on the OptionsForm.vb file to open the options form in the designer. We'll leave the top half of the form alone—we're not changing
 the RSS reader functionality. Down at the bottom, though, we'll need to change the panel's caption, as well as the caption for the TextBox to reflect its new functionality as a keyword, rather than a path holder. Finally (from a UI point of view), we need
 to add a control to adjust the image count. The other thing that needs to happen on this form is that we need to get rid of the two controls at the bottom used for selecting a folder.
</p>
<p>Let's do this in reverse order. Deleting the folder controls is easy. Click on them to select them and press the delete key. They're gone. Drag a label onto the form below the TextBox and change its
<code>text</code> property to <code>ImageCount</code>. Below the label, place a numeric UpDown control and change its name to something more meaningful than the default. I chose
<code>ImageCountUpDown</code>. Notice that as you drag controls around, guides appear helping you align controls. Change the text label above the TextBox to Background image keyword. You should end up with something that looks a bit like Figure 6.
</p>
<p><img height="340" alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1017196/8.gif" width="350" border="0">
</p>
<p><b>Figure 6: UI Changes for the Options Dialog</b> </p>
<p>Now it's time to adjust the code that's used to save the settings. Right-click on the form and choose View Code. The first thing we want to do is rename the textbox that used to be called
<code>backgroundImageFolderTextBox</code>. Locate the line of code in the <b>OptionsForm()</b> constructor that reads:
</p>
<pre class="csharpcode">backgroundImageKeywordTextBox.Text = Settings.[<span class="kwrd">Default</span>].Keyword<br></pre>
<p>and right-click on the name of the TextBox. Choose Refactor, Rename. In the dialog, change the name to
<code>backgroundImageKeywordTextBox</code>. Click OK and then OK again in the preview changes dialog. Changing the name of the control in this way will update all the references to the control including in the auto- generated designer code.
</p>
<p>When the form loads, the values that are currently set are used to populate the controls on the form. Change the code in the constructor method (called
<b>OptionsForm()</b>) to: </p>
<pre class="csharpcode">backgroundImageKeywordTextBox.Text = Settings.[<span class="kwrd">Default</span>].Keyword<br>ImageCountUpDown.Value = Settings.[<span class="kwrd">Default</span>].ImageCount<br>rssFeedTextBox.Text = Settings.[<span class="kwrd">Default</span>].RssFeedUri</pre>
<p>Notice how we can just use the <b>Properties.Settings.Default</b> construct to get at the settings. The type and value of the setting is taken care of automatically for us.
</p>
<p>Now update the <b>UpdateApply</b> and <b>ApplyChanges</b> methods to read: </p>
<pre class="csharpcode"></pre>
<pre class="csharpcode"> <span class="rem">' Update the apply button to be active only if changes </span><br> <span class="rem">' have been made since apply was last pressed</span><br><span class="kwrd">Private</span> <span class="kwrd">Sub</span> UpdateApply()<br>    <span class="kwrd">If</span> Settings.[<span class="kwrd">Default</span>].Keyword &lt;&gt; backgroundImageKeywordTextBox.Text <span class="kwrd">OrElse</span> _<br>        Settings.[<span class="kwrd">Default</span>].ImageCount &lt;&gt; ImageCountUpDown.Value <span class="kwrd">OrElse</span> _<br>        Settings.[<span class="kwrd">Default</span>].RssFeedUri &lt;&gt; rssFeedTextBox.Text <span class="kwrd">Then</span><br>        applyButton.Enabled = <span class="kwrd">True</span><br>    <span class="kwrd">Else</span><br>        applyButton.Enabled = <span class="kwrd">False</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br><br><span class="rem">' Apply all the changes since apply button was last pressed</span><br><span class="kwrd">Private</span> <span class="kwrd">Sub</span> ApplyChanges()<br>    Settings.[<span class="kwrd">Default</span>].Keyword = backgroundImageKeywordTextBox.Text<br>    Settings.[<span class="kwrd">Default</span>].ImageCount = <span class="kwrd">CInt</span>(ImageCountUpDown.Value)<br>    Settings.[<span class="kwrd">Default</span>].RssFeedUri = rssFeedTextBox.Text<br>    Settings.[<span class="kwrd">Default</span>].Save()<br><span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note that I had to cast the value from the UpDown control from its native <code>
Decimal</code> to an <code>int</code> to save it back to the <code>ImageCount</code> setting.
</p>
<p>Finally, we need to add a handler to the <b>ValueChanged</b> event for the UpDown control so we can enable the Apply button when the value changes. Go back to the designer view for the options form and select the UpDown control. In the properties window,
 click on the Events button (the yellow bolt of lightning) and then doube-click on
<b>ValueChanged</b>. All of the wiring will be hooked up to handle the event, you just need to add the call to the
<b>UpdateApply</b> method in the event handling method. </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> ImageCountUpDown_ValueChanged(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, _<br>        <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> EventArgs) <span class="kwrd">Handles</span> ImageCountUpDown.ValueChanged<br>    UpdateApply()<br><span class="kwrd">End</span> <span class="kwrd">Sub</span><br></pre>
<pre></pre>
<p>That's it: all the heavy lifting has been done by the .NET Framework. </p>
<p><b>Loading images for each keyword</b></p>
<p><b></b>Now that we've updated the options dialog, it's time to move onto the form that displays the screen saver itself. This form works by loading images into a list when it starts up and cycling through those images while the screen saver is active. We're
 not going to change the structure of the screen saver very much. We're just going to change the way it loads images so that, instead of getting them from a folder on the local disk, it gets them from the Internet.
</p>
<p>In the Solution Explorer, right-click on ScreenSaverForm.vb and choose View Code. Choose
<b>LoadBackGroundImage</b> from the drop-down box on the right-hand side of the code window. This will take you to the code for this method. This is the only method we need to change on this form.
</p>
<p>Since we're not loading images from folders, I've done away with the code calling the
<b>LoadImagesFromFolder</b> method (as well as the method itself). I then declare a local variable to hold the
<code>imageURL</code> returned from the call to the web service. Next, because calling over the web is fraught with uncertainty, I wrap the next block of code in a
<code>try...catch</code> block to handle any exceptions that might occur. </p>
<p>Creating an instance of the object that will call the web service is very straightforward: just declare a local variable and assign a new
<b>GoogleImage.RandomGoogleSearchService</b> object to it. While I'm about it I create a
<b>WebClient</b> object that I'll use to go out to the web and grab the image itself (the web service only returns a URL, not the binary data that makes up the image).
</p>
<p>Next I loop until I've got as many images loaded as the user has asked for in the settings, and each time I call the web service. Note that the web service actually returns a data object with two properties:
<code>image</code> (the image URL) and <code>word</code> (the word used to select the image).
</p>
<p>If the image URL isn't empty, I try looking it up and retrieving the binary data. If successful, I create an image object from the stream of bits and add that image to the list of background images.
</p>
<p>Finally, if, for some reason, no images were loaded, I call the <b>LoadDefaultBackgroundImages</b> method that was pat of the original application. The full code listing for the updated method is shown below.
</p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> LoadBackgroundImage()<br>    <span class="rem">' Initialize the background images.</span><br>    backgroundImages = <span class="kwrd">New</span> List(Of Image)()<br>    currentImageIndex = 0<br><br>    <span class="kwrd">Dim</span> imageURL <span class="kwrd">As</span> <span class="kwrd">String</span><br><br>    <span class="kwrd">Try</span><br>        <span class="kwrd">Dim</span> oWS <span class="kwrd">As</span> GoogleImage.RandomGoogleSearchService = _<br>            <span class="kwrd">New</span> GoogleImage.RandomGoogleSearchService()<br><br>        <span class="kwrd">Dim</span> webClient <span class="kwrd">As</span> System.Net.WebClient = <span class="kwrd">New</span> System.Net.WebClient()<br><br>        <span class="kwrd">While</span> backgroundImages.Count &lt; Settings.[<span class="kwrd">Default</span>].ImageCount<br>            <span class="rem">' call the web service to look up a random image</span><br>            imageURL = oWS.getRandomGoogleSearch(Settings.[<span class="kwrd">Default</span>].Keyword).image<br>            <span class="kwrd">If</span> imageURL &lt;&gt; <span class="kwrd">String</span>.Empty <span class="kwrd">Then</span><br>                <span class="kwrd">Try</span><br>                    Using imageStream <span class="kwrd">As</span> Stream = webClient.OpenRead(imageURL)<br>                        <span class="kwrd">Dim</span> image <span class="kwrd">As</span> Image = Drawing.Image.FromStream(imageStream)<br>                        backgroundImages.Add(image)<br>                    <span class="kwrd">End</span> Using<br>                <span class="kwrd">Catch</span> generatedExceptionName <span class="kwrd">As</span> System.Net.WebException<br>                    <span class="rem">' probably a 404 (not found error);</span><br>                <span class="kwrd">Catch</span> generatedExceptionName <span class="kwrd">As</span> Exception<br>                    <span class="kwrd">Throw</span><br>                <span class="kwrd">End</span> <span class="kwrd">Try</span><br>            <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">End</span> <span class="kwrd">While</span><br>    <span class="kwrd">Catch</span><br>        <span class="rem">' ignore any other exceptions and get on with the images</span><br>    <span class="kwrd">End</span> <span class="kwrd">Try</span><br><br>    <span class="rem">' If no images were loaded, load the defaults</span><br>    <span class="kwrd">If</span> backgroundImages.Count = 0 <span class="kwrd">Then</span><br>        LoadDefaultBackgroundImages()<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> <span class="kwrd">Sub</span><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style></pre>
<p>That's it! We've finished tweaking the screen saver. Press F5 and check that it runs. Follow the instructions in the section above to put it into your list of Windows Screen Savers.
</p>
<p><b>Next Steps</b></p>
<p><b></b>You may have noticed one or two things that could be done better here. Why, for example, have an image count at all; why not just grab an image form the Internet each time you need a new one? The form seems to take a long time to load. Perhaps loading
 a single image and displaying that while you load the others in the background would be better. Wouldn't it be nice to display the word that was used to retrieve the image at the same time that the image is displayed? I'm sure you can think of some others.
</p>
<p>Well, what are you waiting for? Make changes, try stuff, delve into the window paint code. Above all have fun.
</p>
<p><b>Conclusion</b></p>
<p><b></b>The Visual Studio Express Editions put the power of the .NET Framework in to the hands of just about anyone. The starter kits that come with the Express Editions are great place to, well, start. There's a wealth of information both in the product
 itself and online. There's never been a better time to get into writing powerful and dynamic Windows applications and web sites.
</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/windows+miscellaneous/RSS&WT.dl=0&WT.entryid=Entry:RSSView:0db0db5298084aa8ac369e7600d9045d">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/Extending-the-Screen-Saver-Starter-Kit-with-Microsoft-Visual-Basic-Express</comments>
      <itunes:summary>
Introduction 
Visual Studio 2005 Express is the most comprehensive and full- featured interactive development environment (IDE) released to date. As part of the product mix, Microsoft has announced a series of Express editions, which make this power available to anyone
 for almost no investment. In this article, we&#39;ll explore the installation of one of the editions—Visual Basic—and then use one of the &amp;quot;Starter Kits&amp;quot; included with each Express edition to build and customise a screen saver.
 
Installing Visual Basic Express Edition 
First, you&#39;ll need to install Visual Basic Express Edition (from now on, I&#39;ll just refer to it as Visual Basic Express). You can download it from the
Visual Basic Express website.
 

Run the vbsetup.exe file you downloaded from the Visual Basic Express site. After the installer has copied some setup files to your hard drive, you should see the screen shown in Figure 1. I&#39;d strongly encourage you to check the box that allows the installer
 to gather information and send it to Microsoft. This information is used to make the setup process as seamless as possible.

 
Figure 1: Initial screen for Visual Basic Express Edition Setup 
Click the Next button and you will see the End User License Agreement screen. Accept the agreement and click the Next button again.
You&#39;re now at the screen that allows you to choose which of the optional components (in addition to Visual Basic Express) you want to install. If you&#39;ve got the disk space (about 1.3 GB for the install process and about 500 MB once the install is complete
 and all of the temporaray installation files have been removed) spare, I&#39;d encourage you to install both the MSDN Express Library 2005 and SQL Server 2005 Express Edition April CTP. The MSDN Express Library is the documentation (tailored for the Express editions)
 and SQL Server 2005 Express is the SQL Server engine (with a few limitations). Click the Next button and you&#39;ll be prompted for the installation path. Either accep</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/Extending-the-Screen-Saver-Starter-Kit-with-Microsoft-Visual-Basic-Express</link>
      <pubDate>Tue, 07 Nov 2006 11:54:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/Extending-the-Screen-Saver-Starter-Kit-with-Microsoft-Visual-Basic-Express</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1017196_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1017196_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/Extending-the-Screen-Saver-Starter-Kit-with-Microsoft-Visual-Basic-Express/RSS</wfw:commentRss>
      <category>Windows</category>
      <category>windows miscellaneous</category>
    </item>    
</channel>
</rss>