<?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</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Kevin-Marshall/Posts/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</title>
      <link>http://channel9.msdn.com/Niners/c4f.Kevin-Marshall/Posts</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/Niners/c4f.Kevin-Marshall/Posts</link>
    <language>en</language>
    <pubDate>Thu, 20 Jun 2013 06:38:07 GMT</pubDate>
    <lastBuildDate>Thu, 20 Jun 2013 06:38:07 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>3</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Facebook Outlook Add-in</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">Facebook is a social utility that connects people with friends and others who work, study and live around them. Using the
<a href="http://www.codeplex.com/FacebookToolkit">Facebook Developer Toolkit</a>, you can combine the data stored on Facebook with contacts already stored in Outlook via a custom form region. Additionally, using VSTO and the Outlook object model, you can monitor
 incoming RSS feeds for posts that match interests of your friends on Facebook.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Kevin Marshall</div>
<div class="entry_company"><a href="http://www.claritycon.com/Coding4Fun">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">
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">Outlook 2007,
<a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=85E0C3CE-3FA1-453A-8CE9-AF6CA20946C3&amp;displaylang=en">
Microsoft SQL Server 2005 Compact Edition</a> <a href="http://www.microsoft.com/downloads/details.aspx?familyid=5E86CAB3-6FD6-4955-B979-E1676DB6B3CB&amp;displaylang=en">
Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System</a> <a href="http://www.codeplex.com/FacebookToolkit">
Facebook Developer Toolkit </a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/338597_FBOutlook.zip">Download</a></div>
<div class="entry_details">&nbsp;</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>As Facebook becomes more widely used by corporate users a.k.a older people like me, I thought it would be cool if I could link Facebook data into Outlook.&nbsp; Originally I wanted to&nbsp;build something similar to the
<a href="http://www.plaxo.com/downloads?t=2faq2" target="_blank">Plaxo Toolbar for Outlook</a>&nbsp;to sync Facebook contact info with my Outlook contacts, but unfortunately &nbsp;the
<a href="http://developers.facebook.com/documentation.php" target="_blank">Facebook API</a> doesn't allow you to retrieve contact info. (If anyone from Facebook is reading this, contact info in the API would be awesome <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' />
</p>
<p>So what does the Facebook Outlook Add-in do? Two things.&nbsp; First, you can synchronize Facebook data available via the API like Favorite TV Shows, Movies, etc. to an Outlook contact by linking a contact with his/her Facebook ID (The ID appears in the url&nbsp;on
 profile pages i.e. <a title="http://www.facebook.com/profile.php?id=828485692" href="http://www.facebook.com/profile.php?id=828485692">
http://www.facebook.com/profile.php?id=828485692</a>).&nbsp; After a contact is linked to his/her Facebook profile, profile data is then displayed on a custom region in the Outlook contact form (Figure 1).&nbsp; The data is stored in a local SQL Server 2005 Compact Edition
 DB and periodically refreshed from Facebook.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_7.png" target="_blank"><img height="507" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_thumb_7.png" width="480" border="0"></a>
</p>
<p><strong>Figure 1</strong>: Custom Contact Region</p>
<p>&nbsp;</p>
<p>The second feature is RSS feed monitoring for articles that match interests of your Facebook friends.&nbsp; For example, I subscribe to
<a href="http://www.pitchforkmedia.com/rss/record_reviews" target="_blank">Pitchfork's record review</a>&nbsp;and one of my friends on Facebook likes Iron &amp; Wine.&nbsp; If Pitchfork reviews a new Iron &amp; Wine album, the add-in will flag the post for follow-up&nbsp;to notify&nbsp;me
 that my friend might be interested in that post.&nbsp; A custom region on the RSS post displays which friends matched and why (Figure 2).&nbsp; In a class I once attended on relationship management (business relationships and networking....not dating.&nbsp; I think my girlfriend
 already manages me quite well), the speaker mentioned that it's important to keep relationships fresh.&nbsp; If I see an article that is potentially interesting to one of my contacts, it's a good excuse to email them and keep the relationship current.&nbsp; Normally
 I'd have to remember what everyone likes, but Facebook allows me to be lazy.</p>
<p>&nbsp;</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_6.png" target="_blank"><img height="216" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_thumb_6.png" width="480" border="0"></a>
</p>
<p><strong>Figure 2</strong>: Custom RSS Post Region</p>
<p>&nbsp;</p>
<h3></h3>
<h3>Getting Started</h3>
<p>If you'd like to follow along at home and debug the source code, you first need to install
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=85E0C3CE-3FA1-453A-8CE9-AF6CA20946C3&amp;displaylang=en" target="_blank">
Microsoft SQL Server 2005 Compact Edition</a> and the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=5E86CAB3-6FD6-4955-B979-E1676DB6B3CB&amp;displaylang=en" target="_blank">
Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System</a>.&nbsp; Also, when building Outlook add-ins, there are several registry entries that need to be created.&nbsp; To debug the source code for this article you must run all of the .reg files in the
 &quot;RegistryEntries&quot; folder inside &quot;src\FBOutlookCS&quot; or &quot;src\FBOutlookVB&quot;.&nbsp; </p>
<p>If you just want to try out the add-in without messing around with the source code, first install
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=85E0C3CE-3FA1-453A-8CE9-AF6CA20946C3&amp;displaylang=en" target="_blank">
Microsoft SQL Server 2005 Compact Edition</a> then run &quot;setup.exe&quot; in the &quot;install&quot; folder from the downloaded code of this article.</p>
<p>&nbsp;</p>
<h3>Creating a Custom From&nbsp;Region in Outlook</h3>
<p>I previously posted another add-in article on Coding4Fun, <a href="http://blogs.msdn.com/coding4fun/archive/2006/11/20/1111248.aspx" target="_blank">
Collecting Outlook 2007 Statistics Using VSTO 2005 SE</a>.&nbsp; The steps I used to create&nbsp;this add-in are basically the same.&nbsp; One difference this time was instead of adding registry entries to point to the custom region's manifest file, the registry entry just
 points to the actual add-in (Figure 3).&nbsp; The add-in then dynamically loads the proper custom region from the project's resources based on the which form was requested.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_5.png" target="_blank"><img height="196" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_thumb_5.png" width="480" border="0"></a>
</p>
<p><strong>Figure 3</strong>: Registry Settings</p>
<p>&nbsp;</p>
<p><strong>C#</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>/// &lt;summary&gt;</span></pre>
<pre><span>   2:</span> <span>/// Implemented from the FormRegionStartup interface, GetFormRegionManifest is called when the</span></pre>
<pre><span>   3:</span> <span>/// Form Region manifest information is requested by Outlook.  This can happen from a number of</span></pre>
<pre><span>   4:</span> <span>/// trigger points in Outlook.  Once the manifest information is loaded, Outlook will not ask for </span></pre>
<pre><span>   5:</span> <span>/// this information again during the same Outlook session.</span></pre>
<pre><span>   6:</span> <span>/// &lt;/summary&gt;</span></pre>
<pre><span>   7:</span> <span>/// &lt;param name=&quot;FormRegionName&quot;&gt;Name of the form region, as provided by the registry key&lt;/param&gt;</span></pre>
<pre><span>   8:</span> <span>/// &lt;param name=&quot;LCID&quot;&gt;Language ID for the Office UI language&lt;/param&gt;</span></pre>
<pre><span>   9:</span> <span>/// &lt;returns&gt;A string value containing the XML contents of the form region manifest&lt;/returns&gt;</span></pre>
<pre><span>  10:</span> <span>public</span> <span>object</span> GetFormRegionManifest(<span>string</span> FormRegionName, <span>int</span> LCID)</pre>
<pre><span>  11:</span> {</pre>
<pre><span>  12:</span>     <span>switch</span> (FormRegionName)</pre>
<pre><span>  13:</span>     {</pre>
<pre><span>  14:</span>         <span>case</span> CONTACT_REGION:</pre>
<pre><span>  15:</span>             <span>return</span> Properties.Resources.FacebookContactRegionManifest;</pre>
<pre><span>  16:</span> &nbsp;</pre>
<pre><span>  17:</span>         <span>case</span> RSS_REGION:</pre>
<pre><span>  18:</span>             <span>return</span> Properties.Resources.FacebookRSSRegionManifest;</pre>
<pre><span>  19:</span> &nbsp;</pre>
<pre><span>  20:</span>         <span>default</span>:</pre>
<pre><span>  21:</span>             <span>return</span> <span>null</span>;</pre>
<pre><span>  22:</span>     }</pre>
<pre><span>  23:</span> }</pre>
</div>
</div>
<p><strong>VB.NET</strong></p>
<div>
<div>
<pre><span>   1:</span> Public Function GetFormRegionManifest(ByVal FormRegionName As String, ByVal LCID As Integer) As Object Implements Microsoft.Office.Interop.Outlook._FormRegionStartup.GetFormRegionManifest</pre>
<pre><span>   2:</span>     Select Case FormRegionName</pre>
<pre><span>   3:</span>         Case CONTACT_REGION</pre>
<pre><span>   4:</span>             Return My.Resources.facebookcontactregionmanifest</pre>
<pre><span>   5:</span> &nbsp;</pre>
<pre><span>   6:</span>         Case RSS_REGION</pre>
<pre><span>   7:</span>             Return My.Resources.facebookrssregionmanifest</pre>
<pre><span>   8:</span> &nbsp;</pre>
<pre><span>   9:</span>         Case Else</pre>
<pre><span>  10:</span>             Return Nothing</pre>
<pre><span>  11:</span>     End Select</pre>
<pre><span>  12:</span> End Function</pre>
</div>
</div>
<p>&nbsp;</p>
<h3>Synchronizing Data with Facebook</h3>
<p>Facebook has a REST API for retrieving work &amp; school history, photos, events and personal info (Basically everything except contact info).&nbsp; When building your own Facebook application, you must first get an
<a href="http://developers.facebook.com/get_started.php" target="_blank">API key</a>.&nbsp; There are a variety of ways to call the Facebook web services.&nbsp; You could use XSD, Linq, or the
<a href="http://www.codeplex.com/FacebookToolkit" target="_blank">.NET Facebook Developer Toolkit</a>.&nbsp; I chose the Facebook Developer Toolkit&nbsp;which has a strongly typed object model for Facebook data, simplifies web service calls, handles authentication /
 session management and is a pleasure to use.&nbsp; Plus I helped build the&nbsp;toolkit&nbsp;so I&nbsp;was looking for a chance to promote it&nbsp;<img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' /></p>
<p>After adding a reference to the toolkit, you can retrieve Facebook data and store it in a SQL Server Compact DB with just a few lines of code.</p>
<p><strong>C#</strong></p>
<div>
<div>
<pre><span>   1:</span> _fbService = <span>new</span> Facebook.Components.FacebookService();</pre>
<pre><span>   2:</span> _fbService.ApplicationKey = APP_KEY;</pre>
<pre><span>   3:</span> _fbService.Secret = SECRET;</pre>
<pre><span>   4:</span> &nbsp;</pre>
<pre><span>   5:</span> Collection&lt;Facebook.Entity.User&gt; users = _fbService.GetUserInfo(facebookID);</pre>
<pre><span>   6:</span> &nbsp;</pre>
<pre><span>   7:</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter fbTA =</pre>
<pre><span>   8:</span>     <span>new</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter();</pre>
<pre><span>   9:</span> &nbsp;</pre>
<pre><span>  10:</span> fbTA.Insert(facebookID, users[0].AboutMe,</pre>
<pre><span>  11:</span>     users[0].Interests, users[0].Activities, users[0].Movies,</pre>
<pre><span>  12:</span>     users[0].TVShows, users[0].Books, entryID);</pre>
</div>
</div>
<p>&nbsp;</p>
<p><strong>VB.NET</strong></p>
<div>
<div>
<pre><span>   1:</span> _fbService = <span>New</span> Facebook.Components.FacebookService()</pre>
<pre><span>   2:</span> _fbService.ApplicationKey = API_KEY</pre>
<pre><span>   3:</span> _fbService.Secret = SECRET</pre>
<pre><span>   4:</span> &nbsp;</pre>
<pre><span>   5:</span> <span>Dim</span> users <span>As</span> Collection(Of Facebook.Entity.User) = </pre>
<pre><span>   6:</span>     _fbService.GetUserInfo(facebookID)</pre>
<pre><span>   7:</span> &nbsp;</pre>
<pre><span>   8:</span> <span>Dim</span> fbTA <span>As</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter = </pre>
<pre><span>   9:</span>     <span>New</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter()</pre>
<pre><span>  10:</span> &nbsp;</pre>
<pre><span>  11:</span> fbTA.Update(facebookID, users[0].AboutMe,</pre>
<pre><span>  12:</span>     users[0].Interests, users[0].Activities, users[0].Movies,</pre>
<pre><span>  13:</span>     users[0].TVShows, users[0].Books, entryID, entryID);</pre>
</div>
</div>
<h3>&nbsp;</h3>
<p>The table adapters used in the code above were generated from a dataset linked to the database.&nbsp; The SQL Server Compact DB is a lightweight database that can be deployed in a single file.&nbsp; The database doesn't run any services like SQL Express and is a svelte
 35KB when empty. </p>
<h3><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_8.png" target="_blank"><img height="240" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_thumb_8.png" width="209" border="0"></a>
</h3>
<p><strong>Figure 4</strong>: Facebook Local DB Dataset</p>
<p>&nbsp;</p>
<p>Based on a user configurable setting, the add-in will periodically synchronize all Facebook data for each contact.&nbsp; The sync process is controlled through a timer and the actual synchronization runs asynchronously on a background thread to keep the Outlook
 UI responsive.&nbsp; If the UI freezes, it's probably that other add-in you installed.</p>
<p><strong>C#</strong></p>
<div>
<div>
<pre><span>   1:</span> /// &lt;summary&gt;</pre>
<pre><span>   2:</span> /// Begins the sync timer</pre>
<pre><span>   4:</span> <span>private</span> void InitializeSyncTimer()</pre>
<pre><span>   5:</span> {</pre>
<pre><span>   6:</span>     _syncTimer = <span>new</span> Timer();</pre>
<pre><span>   7:</span>     _syncTimer.Enabled = <span>true</span>;</pre>
<pre><span>   8:</span>     _syncTimer.Interval = SyncIntervalInMiliseconds;</pre>
<pre><span>   9:</span>     _syncTimer.Start();</pre>
<pre><span>  10:</span> }</pre>
<pre><span>  11:</span> &nbsp;</pre>
<pre><span>  12:</span> /// &lt;summary&gt;</pre>
<pre><span>  13:</span> /// <span>Event</span> handler <span>for</span> the sync interval timer.  Starts the sync <span>to</span> facebook async</pre>
<pre><span>  14:</span> /// &lt;/summary&gt;</pre>
<pre><span>  15:</span> /// &lt;param name=<span>&quot;sender&quot;</span>&gt;&lt;/param&gt;</pre>
<pre><span>  16:</span> /// &lt;param name=<span>&quot;e&quot;</span>&gt;&lt;/param&gt;</pre>
<pre><span>  17:</span> <span>private</span> void syncTimer_Tick(<span>object</span> sender, EventArgs e)</pre>
<pre><span>  18:</span> {</pre>
<pre><span>  19:</span>     StartBackgroundSync();</pre>
<pre><span>  20:</span>     _syncTimer.Interval = SyncIntervalInMiliseconds;</pre>
<pre><span>  21:</span> }</pre>
<pre><span>  22:</span> &nbsp;</pre>
<pre><span>  23:</span> /// &lt;summary&gt;</pre>
<pre><span>  24:</span> /// Starts an asynchronous sync of facebook <span>friend</span> data</pre>
<pre><span>  25:</span> /// &lt;/summary&gt;</pre>
<pre><span>  26:</span> <span>private</span> void StartBackgroundSync()</pre>
<pre><span>  27:</span> {</pre>
<pre><span>  28:</span>     System.Threading.Thread syncThread = <span>new</span> System.Threading.Thread(<span>new</span> System.Threading.ThreadStart(SyncUsersWithFacebook));</pre>
<pre><span>  29:</span>     syncThread.IsBackground = <span>true</span>;</pre>
<pre><span>  30:</span>     syncThread.SetApartmentState(System.Threading.ApartmentState.STA);</pre>
<pre><span>  31:</span>     syncThread.Start();</pre>
<pre><span>  32:</span> }</pre>
<pre><span>  33:</span> &nbsp;</pre>
<pre><span>  34:</span> /// &lt;summary&gt;</pre>
<pre><span>  35:</span> /// Synchronizes facebook data of facebook <span>friend</span> data <span>to</span> the sql compact db</pre>
<pre><span>  36:</span> /// &lt;/summary&gt;</pre>
<pre><span>  37:</span> <span>private</span> void SyncUsersWithFacebook()</pre>
<pre><span>  38:</span> {</pre>
<pre><span>  39:</span>     FBSync.Instance.SyncUsersWithFacebookAsync();</pre>
<pre><span>  40:</span> }</pre>
</div>
</div>
<p>&nbsp;</p>
<p><strong>VB.NET</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>   2:</span> <span>''' Begins the sync timer</span></pre>
<pre><span>   3:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>   4:</span> <span>Private</span> <span>Sub</span> InitializeSyncTimer()</pre>
<pre><span>   5:</span>     _syncTimer = <span>New</span> Timer()</pre>
<pre><span>   6:</span>     _syncTimer.Enabled = <span>True</span></pre>
<pre><span>   7:</span>     _syncTimer.Interval = SyncIntervalInMiliseconds</pre>
<pre><span>   8:</span>     _syncTimer.Start()</pre>
<pre><span>   9:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  10:</span> &nbsp;</pre>
<pre><span>  11:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  12:</span> <span>''' Event handler for the sync interval timer.  Starts the sync to facebook async</span></pre>
<pre><span>  13:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  14:</span> <span>''' &lt;param name=&quot;sender&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  15:</span> <span>''' &lt;param name=&quot;e&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  16:</span> <span>Private</span> <span>Sub</span> syncTimer_Tick(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> EventArgs)</pre>
<pre><span>  17:</span>     StartBackgroundSync()</pre>
<pre><span>  18:</span>     _syncTimer.Interval = SyncIntervalInMiliseconds</pre>
<pre><span>  19:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  20:</span> &nbsp;</pre>
<pre><span>  21:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  22:</span> <span>''' Starts an asynchronous sync of facebook friend data</span></pre>
<pre><span>  23:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  24:</span> <span>Private</span> <span>Sub</span> StartBackgroundSync()</pre>
<pre><span>  25:</span>     <span>Dim</span> syncThread <span>As</span> System.Threading.Thread = <span>New</span> System.Threading.Thread(<span>New</span> System.Threading.ThreadStart(<span>AddressOf</span> SyncUsersWithFacebook))</pre>
<pre><span>  26:</span>     syncThread.IsBackground = <span>True</span></pre>
<pre><span>  27:</span>     syncThread.SetApartmentState(System.Threading.ApartmentState.STA)</pre>
<pre><span>  28:</span>     syncThread.Start()</pre>
<pre><span>  29:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  30:</span> &nbsp;</pre>
<pre><span>  31:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  32:</span> <span>''' Synchronizes facebook data of facebook friend data to the sql compact db</span></pre>
<pre><span>  33:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  34:</span> <span>Private</span> <span>Sub</span> SyncUsersWithFacebook()</pre>
<pre><span>  35:</span>     FBSync.Instance.SyncUsersWithFacebookAsync()</pre>
<pre><span>  36:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  37:</span> &nbsp;</pre>
</div>
</div>
<p>&nbsp;</p>
<h3>Searching Posts for Keywords</h3>
<p>To monitor incoming RSS posts first you need to wire up&nbsp;the ItemAdd events on each sub-folder of the RSS feeds folder in Outlook.&nbsp; There are thousands more events that you can handle in addition to ItemAdd.&nbsp; My goal is to keep writing Coding4Fun articles
 until I use them all.&nbsp; </p>
<p>You also need to wire up an event for adding sub-folders to the RSS feed folder (so you can dynamically add more event handlers for the previously mentioned ItemAdd events)&nbsp; That way if a new feed is added to Outlook, the add-in will know to monitor it.&nbsp;
 A code snippet might illustrate better what is happening.</p>
<p><strong>C#</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>/// &lt;summary&gt;</span></pre>
<pre><span>   2:</span> <span>private</span> Outlook.MAPIFolder _rssFeedRootFolder;</pre>
<pre><span>   3:</span> <span>private</span> Outlook.Folders _rssFeedFolders;</pre>
<pre><span>   4:</span> &nbsp;</pre>
<pre><span>   5:</span> _rssFeedFolders.FolderAdd &#43;=</pre>
<pre><span>   6:</span>     <span>new</span> Microsoft.Office.Interop.Outlook.FoldersEvents_FolderAddEventHandler(_rssFeedFolders_FolderAdd);</pre>
<pre><span>   7:</span> &nbsp;</pre>
<pre><span>   8:</span> <span>foreach</span> (Outlook.Folder rssFolder <span>in</span> _rssFeedFolders)</pre>
<pre><span>   9:</span> {</pre>
<pre><span>  10:</span>     AddRSSFolderHandlers(rssFolder.Items);</pre>
<pre><span>  11:</span> }</pre>
<pre><span>  12:</span> &nbsp;</pre>
<pre><span>  13:</span> <span>/// Add a handler to a RSS folder to watch incoming posts</span></pre>
<pre><span>  14:</span> <span>/// &lt;/summary&gt;</span></pre>
<pre><span>  15:</span> <span>/// &lt;param name=&quot;items&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  16:</span> <span>private</span> <span>void</span> AddRSSFolderHandlers(Outlook.Items items)</pre>
<pre><span>  17:</span> {</pre>
<pre><span>  18:</span>     _rssFolderItems.Add(items);</pre>
<pre><span>  19:</span>     _rssFolderItems[_rssFolderItems.Count - 1].ItemAdd &#43;=</pre>
<pre><span>  20:</span>         <span>new</span> Microsoft.Office.Interop.Outlook.ItemsEvents_ItemAddEventHandler(Items_ItemAdd);</pre>
<pre><span>  21:</span>     _rssFolderItems[_rssFolderItems.Count - 1].ItemRemove &#43;=</pre>
<pre><span>  22:</span>         <span>new</span> Microsoft.Office.Interop.Outlook.ItemsEvents_ItemRemoveEventHandler(Items_ItemRemove);</pre>
<pre><span>  23:</span> }</pre>
<pre><span>  24:</span> &nbsp;</pre>
<pre><span>  25:</span> <span>void</span> _rssFeedFolders_FolderAdd(Microsoft.Office.Interop.Outlook.MAPIFolder Folder)</pre>
<pre><span>  26:</span> {</pre>
<pre><span>  27:</span>     AddRSSFolderHandlers(Folder.Items);</pre>
<pre><span>  28:</span> }</pre>
</div>
</div>
<p>&nbsp;</p>
<p><strong>VB.NET</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>Private</span> _rssFeedRootFolder <span>As</span> Outlook.MAPIFolder</pre>
<pre><span>   2:</span> <span>Private</span> _rssFeedFolders <span>As</span> Outlook.Folders</pre>
<pre><span>   3:</span> &nbsp;</pre>
<pre><span>   4:</span> <span>AddHandler</span> _rssFeedFolders.FolderAdd, <span>AddressOf</span> _rssFeedFolders_FolderAdd</pre>
<pre><span>   5:</span> &nbsp;</pre>
<pre><span>   6:</span> <span>For</span> <span>Each</span> rssFolder <span>As</span> Outlook.Folder <span>In</span> _rssFeedFolders</pre>
<pre><span>   7:</span>     AddRSSFolderHandlers(rssFolder.Items)</pre>
<pre><span>   8:</span> <span>Next</span> rssFolder</pre>
<pre><span>   9:</span> &nbsp;</pre>
<pre><span>  10:</span> <span>Private</span> <span>Sub</span> _rssFeedFolders_FolderAdd(<span>ByVal</span> Folder <span>As</span> Microsoft.Office.Interop.Outlook.MAPIFolder)</pre>
<pre><span>  11:</span>     AddRSSFolderHandlers(Folder.Items)</pre>
<pre><span>  12:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  13:</span> &nbsp;</pre>
<pre><span>  14:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  15:</span> <span>''' Add a handler to a RSS folder to watch incoming posts</span></pre>
<pre><span>  16:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  17:</span> <span>''' &lt;param name=&quot;items&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  18:</span> <span>Private</span> <span>Sub</span> AddRSSFolderHandlers(<span>ByVal</span> items <span>As</span> Outlook.Items)</pre>
<pre><span>  19:</span>     _rssFolderItems.Add(items)</pre>
<pre><span>  20:</span>     <span>AddHandler</span> _rssFolderItems(_rssFolderItems.Count - 1).ItemAdd, <span>AddressOf</span> Items_ItemAdd</pre>
<pre><span>  21:</span>     <span>AddHandler</span> _rssFolderItems(_rssFolderItems.Count - 1).ItemRemove, <span>AddressOf</span> Items_ItemRemove</pre>
<pre><span>  22:</span> <span>End</span> Sub</pre>
</div>
</div>
<p>&nbsp;</p>
<p>When a new RSS post comes into Outlook, the ItemAdd event fires and the add-in launches a search of the post on a background thread.&nbsp; Searching of a post involves looping through each stored Facebook profile and tokenizing the personal info fields into keywords
 based on commas.&nbsp; As your&nbsp;list of friend's grows, there might be a more a efficient way of storing keywords and searching posts.&nbsp; I'm shy so I only have a handful of friends on Facebook.&nbsp;
</p>
<p>Another feature is the ability to exclude certain keywords (Figure 5).&nbsp; Suppose someone likes the rapper &quot;Common&quot;, but that word might appear in unrelated posts.&nbsp; In the add-in settings you can add words to an exclusion list to prevent false matches.&nbsp; Obviously
 the searching function is pretty simple, but it works for the purposes of this sample.</p>
<p>&nbsp;</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_9.png" target="_blank"><img height="240" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/4660479/image_thumb_9.png" width="166" border="0"></a>
</p>
<p><strong>Figure 5: </strong>Add-in Settings</p>
<p>&nbsp;</p>
<p>Below are some snippets of code for searching incoming posts.</p>
<p><strong>C#</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>void</span> Items_ItemAdd(<span>object</span> Item)</pre>
<pre><span>   2:</span> {</pre>
<pre><span>   3:</span>     Outlook.PostItem post = Item <span>as</span> Outlook.PostItem;</pre>
<pre><span>   4:</span> &nbsp;</pre>
<pre><span>   5:</span>     <span>if</span> (post != <span>null</span>)</pre>
<pre><span>   6:</span>     {</pre>
<pre><span>   7:</span>         System.Threading.Thread syncThread = <span>new</span> System.Threading.Thread(<span>new</span> System.Threading.ParameterizedThreadStart(SearchPostAsync));</pre>
<pre><span>   8:</span>         syncThread.IsBackground = <span>true</span>;</pre>
<pre><span>   9:</span>         syncThread.SetApartmentState(System.Threading.ApartmentState.STA);</pre>
<pre><span>  10:</span>         syncThread.Start(post);</pre>
<pre><span>  11:</span>     }</pre>
<pre><span>  12:</span> }</pre>
<pre><span>  13:</span> &nbsp;</pre>
<pre><span>  14:</span> <span>/// &lt;summary&gt;</span></pre>
<pre><span>  15:</span> <span>/// Begins async search of an incoming post</span></pre>
<pre><span>  16:</span> <span>/// &lt;/summary&gt;</span></pre>
<pre><span>  17:</span> <span>/// &lt;param name=&quot;item&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  18:</span> <span>private</span> <span>void</span> SearchPostAsync(<span>object</span> item)</pre>
<pre><span>  19:</span> {</pre>
<pre><span>  20:</span>     Outlook.PostItem post = item <span>as</span> Outlook.PostItem;</pre>
<pre><span>  21:</span> &nbsp;</pre>
<pre><span>  22:</span>     <span>if</span> (post != <span>null</span>)</pre>
<pre><span>  23:</span>     {</pre>
<pre><span>  24:</span>         PostSearcher ps = <span>new</span> PostSearcher();</pre>
<pre><span>  25:</span>         ps.SearchPost(post, _contacts);</pre>
<pre><span>  26:</span>     }</pre>
<pre><span>  27:</span> }</pre>
<pre><span>  28:</span> &nbsp;</pre>
<pre><span>  29:</span> <span>public</span> <span>void</span> SearchPost(Outlook.PostItem postItem, Outlook.Items contacts)</pre>
<pre><span>  30:</span> {</pre>
<pre><span>  31:</span> &nbsp;</pre>
<pre><span>  32:</span>    FacebookDBDataSetTableAdapters.FacebookDataTableAdapter fdTA = </pre>
<pre><span>  33:</span>        <span>new</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter();</pre>
<pre><span>  34:</span> &nbsp;</pre>
<pre><span>  35:</span>    FacebookDBDataSet.FacebookDataDataTable fdDT = fdTA.GetData();</pre>
<pre><span>  36:</span> &nbsp;</pre>
<pre><span>  37:</span>    List&lt;<span>string</span>&gt; entryIDs = <span>new</span> List&lt;<span>string</span>&gt;();</pre>
<pre><span>  38:</span>    <span>string</span> keyword = <span>string</span>.Empty;</pre>
<pre><span>  39:</span> &nbsp;</pre>
<pre><span>  40:</span>    <span>//look through each facebook friend associated with an outlook contact</span></pre>
<pre><span>  41:</span>    <span>//and search the incoming post to match keywords</span></pre>
<pre><span>  42:</span>    <span>foreach</span> (FacebookDBDataSet.FacebookDataRow row <span>in</span> fdDT.Rows)</pre>
<pre><span>  43:</span>    {</pre>
<pre><span>  44:</span>        <span>if</span> (IsKeywordFound(row.FavoriteTVShows, postItem, <span>out</span> keyword))</pre>
<pre><span>  45:</span>        {</pre>
<pre><span>  46:</span>            entryIDs.Add(row.EntryID);</pre>
<pre><span>  47:</span> &nbsp;</pre>
<pre><span>  48:</span> &nbsp;</pre>
<pre><span>  49:</span>            <span>continue</span>;</pre>
<pre><span>  50:</span>        }</pre>
<pre><span>  51:</span>     <span>//more code</span></pre>
<pre><span>  52:</span>     }</pre>
<pre><span>  53:</span> &nbsp;</pre>
<pre><span>  54:</span>     <span>//more code</span></pre>
<pre><span>  55:</span> }</pre>
<pre><span>  56:</span> &nbsp;</pre>
<pre><span>  57:</span> <span>private</span> <span>bool</span> IsKeywordFound(<span>string</span> keywords, Outlook.PostItem postItem, <span>out</span> <span>string</span> matchedKeyword)</pre>
<pre><span>  58:</span> {</pre>
<pre><span>  59:</span>     <span>bool</span> isFound = <span>false</span>;</pre>
<pre><span>  60:</span>     matchedKeyword = <span>string</span>.Empty;</pre>
<pre><span>  61:</span> &nbsp;</pre>
<pre><span>  62:</span>     <span>if</span> (!String.IsNullOrEmpty(keywords))</pre>
<pre><span>  63:</span>     {</pre>
<pre><span>  64:</span>         <span>string</span>[] keywordList = keywords.Split(<span>','</span>);</pre>
<pre><span>  65:</span> &nbsp;</pre>
<pre><span>  66:</span>         <span>//take the tokenized facebook data and search the post for matching keywords</span></pre>
<pre><span>  67:</span>         <span>//not the most sophisticated search, can be improved in later versions</span></pre>
<pre><span>  68:</span>         <span>foreach</span> (<span>string</span> keyword <span>in</span> keywordList)</pre>
<pre><span>  69:</span>         {</pre>
<pre><span>  70:</span>             <span>string</span> keywordSearch = keyword.ToUpperInvariant().Trim();</pre>
<pre><span>  71:</span>             <span>if</span> (postItem.Body.ToUpperInvariant().Contains(keywordSearch) || postItem.Subject.ToUpperInvariant().Contains(keywordSearch))</pre>
<pre><span>  72:</span>             {</pre>
<pre><span>  73:</span>                 <span>//exclude and keywords that the user has added to the settings screen to exclude</span></pre>
<pre><span>  74:</span>                 <span>if</span> (!Properties.Settings.Default.ExcludeList.ToUpperInvariant().Contains(keywordSearch))</pre>
<pre><span>  75:</span>                 {</pre>
<pre><span>  76:</span>                     isFound = <span>true</span>;</pre>
<pre><span>  77:</span>                     matchedKeyword = keyword;</pre>
<pre><span>  78:</span>                     <span>break</span>;</pre>
<pre><span>  79:</span>                 }</pre>
<pre><span>  80:</span>             }</pre>
<pre><span>  81:</span>         }</pre>
<pre><span>  82:</span>     }</pre>
<pre><span>  83:</span> &nbsp;</pre>
<pre><span>  84:</span>     <span>return</span> isFound;</pre>
<pre><span>  85:</span> }</pre>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>VB.NET</strong></p>
<div>
<div>
<pre><span>   1:</span> <span>Private</span> <span>Sub</span> Items_ItemAdd(<span>ByVal</span> Item <span>As</span> <span>Object</span>)</pre>
<pre><span>   2:</span>     <span>Dim</span> post <span>As</span> Outlook.PostItem = <span>TryCast</span>(Item, Outlook.PostItem)</pre>
<pre><span>   3:</span> &nbsp;</pre>
<pre><span>   4:</span>     <span>If</span> <span>Not</span> post <span>Is</span> <span>Nothing</span> <span>Then</span></pre>
<pre><span>   5:</span>         <span>Dim</span> syncThread <span>As</span> System.Threading.Thread = <span>New</span> System.Threading.Thread(<span>New</span> System.Threading.ParameterizedThreadStart(<span>AddressOf</span> SearchPostAsync))</pre>
<pre><span>   6:</span>         syncThread.IsBackground = <span>True</span></pre>
<pre><span>   7:</span>         syncThread.SetApartmentState(System.Threading.ApartmentState.STA)</pre>
<pre><span>   8:</span>         syncThread.Start(post)</pre>
<pre><span>   9:</span>     <span>End</span> <span>If</span></pre>
<pre><span>  10:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  11:</span> &nbsp;</pre>
<pre><span>  12:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  13:</span> <span>''' Begins async search of an incoming post</span></pre>
<pre><span>  14:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  15:</span> <span>''' &lt;param name=&quot;item&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  16:</span> <span>Private</span> <span>Sub</span> SearchPostAsync(<span>ByVal</span> item <span>As</span> <span>Object</span>)</pre>
<pre><span>  17:</span>     <span>Dim</span> post <span>As</span> Outlook.PostItem = <span>TryCast</span>(item, Outlook.PostItem)</pre>
<pre><span>  18:</span> &nbsp;</pre>
<pre><span>  19:</span>     <span>If</span> <span>Not</span> post <span>Is</span> <span>Nothing</span> <span>Then</span></pre>
<pre><span>  20:</span>         <span>Dim</span> ps <span>As</span> PostSearcher = <span>New</span> PostSearcher()</pre>
<pre><span>  21:</span>         ps.SearchPost(post, _contacts)</pre>
<pre><span>  22:</span>     <span>End</span> <span>If</span></pre>
<pre><span>  23:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  24:</span> &nbsp;</pre>
<pre><span>  25:</span> <span>Public</span> <span>Sub</span> SearchPost(<span>ByVal</span> postItem <span>As</span> Outlook.PostItem, <span>ByVal</span> contacts <span>As</span> Outlook.Items)</pre>
<pre><span>  26:</span> &nbsp;</pre>
<pre><span>  27:</span>     <span>Dim</span> fdTA <span>As</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter = </pre>
<pre><span>  28:</span>         <span>New</span> FacebookDBDataSetTableAdapters.FacebookDataTableAdapter()</pre>
<pre><span>  29:</span> &nbsp;</pre>
<pre><span>  30:</span>     <span>Dim</span> fdDT <span>As</span> FacebookDBDataSet.FacebookDataDataTable = fdTA.GetData()</pre>
<pre><span>  31:</span> &nbsp;</pre>
<pre><span>  32:</span>     <span>Dim</span> entryIDs <span>As</span> List(Of <span>String</span>) = <span>New</span> List(Of <span>String</span>)()</pre>
<pre><span>  33:</span>     <span>Dim</span> keyword <span>As</span> <span>String</span> = <span>String</span>.Empty</pre>
<pre><span>  34:</span> &nbsp;</pre>
<pre><span>  35:</span>     <span>'look through each facebook friend associated with an outlook contact</span></pre>
<pre><span>  36:</span>     <span>'and search the incoming post to match keywords</span></pre>
<pre><span>  37:</span>     <span>For</span> <span>Each</span> row <span>As</span> FacebookDBDataSet.FacebookDataRow <span>In</span> fdDT.Rows</pre>
<pre><span>  38:</span>         <span>If</span> IsKeywordFound(row.FavoriteTVShows, postItem, keyword) <span>Then</span></pre>
<pre><span>  39:</span>             entryIDs.Add(row.EntryID)</pre>
<pre><span>  40:</span> &nbsp;</pre>
<pre><span>  41:</span>             Continue <span>For</span></pre>
<pre><span>  42:</span>         <span>End</span> <span>If</span></pre>
<pre><span>  43:</span>         <span>'more code.....</span></pre>
<pre><span>  44:</span>     <span>Next</span> row</pre>
<pre><span>  45:</span> &nbsp;</pre>
<pre><span>  46:</span> <span>'more code.....</span></pre>
<pre><span>  47:</span> <span>End</span> <span>Sub</span></pre>
<pre><span>  48:</span> &nbsp;</pre>
<pre><span>  49:</span> <span>''' &lt;summary&gt;</span></pre>
<pre><span>  50:</span> <span>''' search the post for a keyword string</span></pre>
<pre><span>  51:</span> <span>''' &lt;/summary&gt;</span></pre>
<pre><span>  52:</span> <span>''' &lt;param name=&quot;keywords&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  53:</span> <span>''' &lt;param name=&quot;postItem&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  54:</span> <span>''' &lt;param name=&quot;matchedKeyword&quot;&gt;&lt;/param&gt;</span></pre>
<pre><span>  55:</span> <span>''' &lt;returns&gt;&lt;/returns&gt;</span></pre>
<pre><span>  56:</span> <span>Private</span> <span>Function</span> IsKeywordFound(<span>ByVal</span> keywords <span>As</span> <span>String</span>, <span>ByVal</span> postItem <span>As</span> Outlook.PostItem, &lt;System.Runtime.InteropServices.Out()&gt; <span>ByRef</span> matchedKeyword <span>As</span> <span>String</span>) <span>As</span> <span>Boolean</span></pre>
<pre><span>  57:</span>     <span>Dim</span> isFound <span>As</span> <span>Boolean</span> = <span>False</span></pre>
<pre><span>  58:</span>     matchedKeyword = <span>String</span>.Empty</pre>
<pre><span>  59:</span> &nbsp;</pre>
<pre><span>  60:</span>     <span>If</span> (<span>Not</span> <span>String</span>.IsNullOrEmpty(keywords)) <span>Then</span></pre>
<pre><span>  61:</span>         <span>Dim</span> keywordList <span>As</span> <span>String</span>() = keywords.Split(<span>&quot;,&quot;</span>c)</pre>
<pre><span>  62:</span> &nbsp;</pre>
<pre><span>  63:</span>         <span>'take the tokenized facebook data and search the post for matching keywords</span></pre>
<pre><span>  64:</span>         <span>'not the most sophisticated search, can be improved in later versions</span></pre>
<pre><span>  65:</span>         <span>For</span> <span>Each</span> keyword <span>As</span> <span>String</span> <span>In</span> keywordList</pre>
<pre><span>  66:</span>             <span>Dim</span> keywordSearch <span>As</span> <span>String</span> = keyword.ToUpperInvariant().Trim()</pre>
<pre><span>  67:</span>             <span>If</span> postItem.Body.ToUpperInvariant().Contains(keywordSearch) <span>OrElse</span> postItem.Subject.ToUpperInvariant().Contains(keywordSearch) <span>Then</span></pre>
<pre><span>  68:</span>                 <span>'exclude and keywords that the user has added to the settings screen to exclude</span></pre>
<pre><span>  69:</span>                 <span>If</span> (<span>Not</span> My.Settings.ExcludeList.ToUpperInvariant().Contains(keywordSearch)) <span>Then</span></pre>
<pre><span>  70:</span>                     isFound = <span>True</span></pre>
<pre><span>  71:</span>                     matchedKeyword = keyword</pre>
<pre><span>  72:</span>                     <span>Exit</span> <span>For</span></pre>
<pre><span>  73:</span>                 <span>End</span> <span>If</span></pre>
<pre><span>  74:</span>             <span>End</span> <span>If</span></pre>
<pre><span>  75:</span>         <span>Next</span> keyword</pre>
<pre><span>  76:</span>     <span>End</span> <span>If</span></pre>
<pre><span>  77:</span> &nbsp;</pre>
<pre><span>  78:</span>     <span>Return</span> isFound</pre>
<pre><span>  79:</span> <span>End</span> Function</pre>
</div>
</div>
<p>&nbsp;</p>
<h3>Creating the Installer</h3>
<p>When you create a new Outlook Add-in project, Visual Studio creates a setup project along with it.&nbsp; The default setup project needs a little tweaking before you can distribute to your friends to install. Chris Castillo wrote an excellent
<a href="http://blogs.msdn.com/chcast/archive/2007/03/28/creating-visio-add-ins-with-vsto-2005-se.aspx" target="_blank">
post</a> on building setup projects for office add-ins.&nbsp; A few minor challenges are granting full trust, installing / checking&nbsp;additional prerequisites like VSTO 2005 SE&nbsp;for Office 2007 / PIAs&nbsp;and creating the right registry entries.&nbsp;&nbsp;If something doesn't work
 with the installer in this project, I blame him <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif?v=c9' alt='Smiley' />&nbsp; </p>
<p>&nbsp;</p>
<h3>Conclusion</h3>
<p>The add-in for this article is just one example of the fun things you can do with some of the API blocks that are being created by the Visual Studio Express team and others.&nbsp; The Facebook toolkit in particular can be used to create applications within Facebook
 on the web or in stand-alone desktop applications like this add-in.&nbsp; I plan on adding this code into the Facebook Developer Toolkit project on CodePlex as a sample at some point so anyone can help expand this add-in.&nbsp; Some future things I think would be cool
 to add are photo album exporting, more sophisticated keyword searching, syncing of contact info and email synchronization.&nbsp; Some of those are dependent on the API changing and may not be possible.</p>
<p>If you'd like to contact me, feel free to send me a message or add me as a friend on
<a href="http://www.facebook.com/profile.php?id=828485692" target="_blank">Facebook</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Kevin-Marshall/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:a488bc92e83a43a29d179e7600d2a4d7">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Facebook-Outlook-Add-in</comments>
      <itunes:summary>



&amp;nbsp;
Facebook is a social utility that connects people with friends and others who work, study and live around them. Using the
Facebook Developer Toolkit, you can combine the data stored on Facebook with contacts already stored in Outlook via a custom form region. Additionally, using VSTO and the Outlook object model, you can monitor
 incoming RSS feeds for posts that match interests of your friends on Facebook.



Kevin Marshall
Clarity Consulting

Difficulty: Intermediate
Time Required: 
6-10 hours
Cost: Free
Software: Outlook 2007,
Visual Basic or Visual C# Express Editions,

Microsoft SQL Server 2005 Compact Edition 
Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System 
Facebook Developer Toolkit 
Hardware: 
Download: Download
&amp;nbsp;





As Facebook becomes more widely used by corporate users a.k.a older people like me, I thought it would be cool if I could link Facebook data into Outlook.&amp;nbsp; Originally I wanted to&amp;nbsp;build something similar to the
Plaxo Toolbar for Outlook&amp;nbsp;to sync Facebook contact info with my Outlook contacts, but unfortunately &amp;nbsp;the
Facebook API doesn&#39;t allow you to retrieve contact info. (If anyone from Facebook is reading this, contact info in the API would be awesome 
 
So what does the Facebook Outlook Add-in do? Two things.&amp;nbsp; First, you can synchronize Facebook data available via the API like Favorite TV Shows, Movies, etc. to an Outlook contact by linking a contact with his/her Facebook ID (The ID appears in the url&amp;nbsp;on
 profile pages i.e. 
http://www.facebook.com/profile.php?id=828485692).&amp;nbsp; After a contact is linked to his/her Facebook profile, profile data is then displayed on a custom region in the Outlook contact form (Figure 1).&amp;nbsp; The data is stored in a local SQL Server 2005 Compact Edition
 DB and periodically refreshed from Facebook. 

 
Figure 1: Custom Contact Region 
&amp;nbsp; 
The second feature is RSS feed monitoring for articles that match interests of your Facebook fri</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Facebook-Outlook-Add-in</link>
      <pubDate>Fri, 31 Aug 2007 01:37:04 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Facebook-Outlook-Add-in</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/4660479_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/4660479_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Kevin Marshall</dc:creator>
      <itunes:author>Kevin Marshall</itunes:author>
      <slash:comments>7</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Facebook-Outlook-Add-in/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Collecting Outlook 2007 Statistics Using VSTO 2005 SE</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">&nbsp;</td>
<td class=""><span class="entry_description">This article demonstrates how you can create an Outlook add-in using
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5012A573-0D84-4E39-983C-CA22F2107B07&amp;displaylang=en">
VSTO 2005 SE</a> to listen to outlook events, store data about outlook usage, and produce reports on that usage in a custom form and a form region.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Kevin Marshall, Clarity Consulting, Inc.</div>
<div class="entry_company"><a href="http://blogs.claritycon.com/blogs/kevin_marshall/default.aspx">Clarity Blogs</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://office.microsoft.com/en-us/products/default.aspx">Office 2007</a>
<a href="http://msdn.microsoft.com/vstudio/express/">Visual Studio Express</a> <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5012A573-0D84-4E39-983C-CA22F2107B07&amp;displaylang=en">
VSTO 2005 SE</a> <a href="http://msdn2.microsoft.com/en-us/library/ms788695.aspx">
Outlook Add-in Templates</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/source/OutlookStats.zip">Download</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>Outlook is used by many people everyday, but few people probably realize the wealth of data that can be learned from how they use Outlook. How long does it take you to respond to emails on average? How many hours do you spend in meetings per week? Using
 Visual Studio Tools for Office Second Edition (VSTO 2005 SE) and Office 2007, you can easily find the answers to these questions and more by building an add-in for Outlook. This article demonstrates how you can listen to outlook events, store data about outlook
 usage, and produce reports on that usage in a custom form and new to VSTO 2005 SE, a form region.</p>
<p>&nbsp;</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image011.png"><img height="240" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb3.png" width="317" border="0"></a>
</p>
<p>&nbsp;</p>
<h3>What is VSTO 2005 SE?</h3>
<p>VSTO 2005 SE is a free add-on to Visual Studio 2005 that enables developers to build applications targeting the 2007 Office system. Developers can create Office-based solutions using the professional development environment of Visual Studio 2005 and the
 new programming model features of Office 2007 like the ribbon bar and custom form regions.
</p>
<h3>Creating an Outlook Add-in Project</h3>
<p>After installing VSTO 2005 SE and the Outlook Add-in template, you can begin creating an Outlook 2007 add-in. Create a new project, then select Office Outlook 2007 Add-in from the My Templates group and click OK.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image012.png"><img height="184" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb4.png" width="320" border="0"></a>
</p>
<p>&nbsp;</p>
<p>The newly created project will have several files. Connect.cs is the main file which contains two methods,
<b>InitializeAddin</b> and <b>ShutdownAddin</b> which provide you a starting point for interfacing with Outlook.
</p>
<h3>Initializing the Add-in</h3>
<p>The InitializeAddin method is called whenever your add-in is loaded into memory. For our add-in, we will do three things during start up:
</p>
<ul>
<li>Create an instance of our EventTracker class. This is the main class that handles all of the logic for processing incoming appointment and mail items.
</li><li>Load existing Outlook data via the EventTracker. </li><li>Add a menu item to the Outlook toolbar. The menu item is used to pop up the report window.</li></ul>
<p>&nbsp;</p>
<p><strong>&nbsp;Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> InitalizeAddin()
{
   <span class="rem">//Initialize report menu item</span>
   <span class="kwrd">this</span>.InitializeMenu();

   <span class="rem">// Initialize the event tracker object.</span>
   _eventTracker = <span class="kwrd">new</span> EventTracker(<span class="kwrd">this</span>.Application);

   ListenToEvents(<span class="kwrd">true</span>);

   _eventTracker.LoadData();
}
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>&nbsp;</p>
<p><strong>&nbsp;Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> InitalizeAddin()

    <span class="rem">'//Initialize report menu item</span>
   InitializeMenu()

    <span class="rem">'// Initialize the event tracker object.</span>
   _eventTracker = <span class="kwrd">New</span> EventTracker(<span class="kwrd">Me</span>.Application)

    ListenToEvents(<span class="kwrd">True</span>)

   _eventTracker.LoadData()
<span class="kwrd">End</span> Sub</pre>
<pre class="csharpcode">&nbsp;</pre>
<p>Top-level menu items can be created the same way in office application. For this add-in, we'll create a new menu “Reports”, with a single menu item to launch the report popup window.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image013.png"><img height="54" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb5.png" width="320" border="0"></a>
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="rem">// Get the Outlook menu bar.</span>
_menuBar = <span class="kwrd">this</span>.Application.ActiveExplorer().CommandBars.ActiveMenuBar;

<span class="rem">// Get the index of the Help menu item on the Outlook menu bar.</span>
_helpMenuIndex = _menuBar.Controls[_MENU_BEFORE].Index;
<span class="rem">// Add the top-level menu right before the Help menu.</span>
_topMenu = </pre>
<blockquote>
<pre class="csharpcode">(Office.CommandBarPopup)_menuBar.Controls.Add(Office.MsoControlType.msoControlPopup,
   Type.Missing, Type.Missing, _helpMenuIndex, <span class="kwrd">true</span>);</pre>
<pre class="csharpcode">_topMenu.Caption = <span class="str">&quot;Reports&quot;</span>;
_topMenu.Visible = <span class="kwrd">true</span>;

<span class="rem">// Add the menu item for loading email reports.</span>
_reports = </pre>
<pre class="csharpcode">   (Office.CommandBarButton)_topMenu.Controls.Add(Office.MsoControlType.msoControlButton, </pre>
<pre class="csharpcode">   Type.Missing, Type.Missing, Type.Missing, t<span class="kwrd">rue</span>);                                                                                   Type.Missing,                                                                                 Type.Missing,                                                                                   Type.Missing,                                                                                    <span class="kwrd">true</span>);

_reports.Caption = <span class="str">&quot;Calendar / Email Reports&quot;</span>;
_reports.Visible = <span class="kwrd">true</span>;
</pre>
</blockquote>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"> <span class="rem">'// Get the Outlook menu bar.</span>
 _menuBar = <span class="kwrd">Me</span>.Application.ActiveExplorer().CommandBars.ActiveMenuBar

 <span class="rem">'// Get the index of the Help menu item on the Outlook menu bar.</span>
_helpMenuIndex = _menuBar.Controls(_MENU_BEFORE).Index

 <span class="rem">'// Add the top-level menu right before the Help menu.</span>
_topMenu = </pre>
<pre class="csharpcode"><span class="kwrd">   CType</span>(_menuBar.Controls.Add(Office.MsoControlType.msoControlPopup, _
      Type.Missing, Type.Missing, _helpMenuIndex, <span class="kwrd">True</span>), Office.CommandBarPopup)</pre>
<pre class="csharpcode"> _topMenu.Caption = <span class="str">&quot;Reports&quot;</span>
 _topMenu.Visible = <span class="kwrd">True</span>

 <span class="rem">' Add the menu item for loading email reports.</span>
_reports = _topMenu.Controls.Add(Office.MsoControlType.msoControlButton, _
         Type.Missing, Type.Missing, Type.Missing, <span class="kwrd">True</span>)
 _reports.Caption = <span class="str">&quot;Calendar / Email Reports&quot;</span>
 _reports.Visible = <span class="kwrd">True</span></pre>
<pre class="csharpcode"><span class="kwrd"></span>&nbsp;</pre>
<pre class="csharpcode"><span class="kwrd"></span>&nbsp;</pre>
<h3>Loading Statistics Based on Existing Outlook Data</h3>
<p>Data to produce reports on Outlook usage is stored in a SQL Express database. When the add-in first loads, it needs to scan the mail and calendar folders to gather statistics on existing items. The EventTracker class handles the initial data load, as well
 as hooking events fired when new items are added to those folders. </p>
<p>The schema for the database has tables for storing information about the three types of items we are reporting statistics: inbox items, sent mail items, and appointment items.
</p>
<pre class="csharpcode"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image01.png"><img height="141" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0.png" width="240" border="0"></a> </pre>
<pre class="csharpcode">&nbsp;</pre>
<p>Since scanning through the folders can take some time if you are like me and keep every email ever received, it's best to start the initial data load on a separate thread. Now Outlook can continue responding to user input, while the add-in does its work.
</p>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> LoadData()
{
   <span class="rem">//create new thread for large inboxes</span>
   Thread thread = <span class="kwrd">new</span> Thread(<span class="kwrd">new</span> ThreadStart(CheckInitialLoad));
   thread.IsBackground = <span class="kwrd">true</span>;
   thread.Start();
}
</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>
<pre class="csharpcode">&nbsp;</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> LoadData()
   <span class="kwrd">Dim</span> thread <span class="kwrd">As</span> Thread = <span class="kwrd">New</span> Thread(<span class="kwrd">AddressOf</span> CheckInitialLoad)
   thread.IsBackground = <span class="kwrd">True</span>
   thread.Start()
<span class="kwrd">End</span> Sub</pre>
<pre class="csharpcode">&nbsp;</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 initial data load raises an to notify other code, like the report popup form, that the data isn't ready to produce reports yet. If the database doesn't contain any exisitng data, then the data load will add records for each exisiting item. Allowing the
 thread to sleep briefly between iterations prevents the data load from interfering with the responsiveness of the main Outlook thread.
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> CheckInitialLoad()
{
   <span class="kwrd">if</span> (!<span class="kwrd">object</span>.Equals(StartDataLoad,<span class="kwrd">null</span>))
   {
      StartDataLoad(<span class="kwrd">this</span>, <span class="kwrd">null</span>);
   }

ReportDBDataSetTableAdapters.SentMailTableAdapter sentItemTA = </pre>
<pre class="csharpcode">   <span class="kwrd">new</span> ReportDBDataSetTableAdapters.SentMailTableAdapter();
ReportDBDataSetTableAdapters.InboxTableAdapter inboxTA = </pre>
<pre class="csharpcode">   <span class="kwrd">new</span> ReportDBDataSetTableAdapters.InboxTableAdapter();
ReportDBDataSetTableAdapters.CalendarTableAdapter calTA = </pre>
<pre class="csharpcode">   <span class="kwrd">new</span> ReportDBDataSetTableAdapters.CalendarTableAdapter();

   <span class="rem">//check to see if calendar stats have been loaded</span>
   <span class="kwrd">if</span> (calTA.GetData().Rows.Count == 0)
   {
      <span class="kwrd">foreach</span> (<span class="kwrd">object</span> item <span class="kwrd">in</span> _calendarItems)
      {
         <span class="kwrd">if</span> (item <span class="kwrd">is</span> Outlook.AppointmentItem)
         {
            AddCalendarItem(item <span class="kwrd">as</span> Outlook.AppointmentItem);
         }
         Thread.Sleep(10);
      }
   }
   <span class="kwrd">if</span> (!<span class="kwrd">object</span>.Equals(StopDataLoad, <span class="kwrd">null</span>))
   {
      StopDataLoad(<span class="kwrd">this</span>, <span class="kwrd">null</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><strong>Visual Basic</strong> </p>
<pre class="csharpcode"> <span class="kwrd">Private</span> <span class="kwrd">Sub</span> CheckInitialLoad()

   <span class="kwrd">RaiseEvent</span> StartDataLoad(<span class="kwrd">Me</span>, <span class="kwrd">Nothing</span>)

   <span class="kwrd">Dim</span> sentItemTA <span class="kwrd">As</span> ReportDBDataSetTableAdapters.SentMailTableAdapter = _</pre>
<pre class="csharpcode">      <span class="kwrd">New </span>ReportDBDataSetTableAdapters.SentMailTableAdapter
   <span class="kwrd">Dim</span> inboxTA <span class="kwrd">As</span> ReportDBDataSetTableAdapters.InboxTableAdapter = _</pre>
<pre class="csharpcode">      <span class="kwrd">New </span>ReportDBDataSetTableAdapters.InboxTableAdapter
   <span class="kwrd">Dim</span> calTA <span class="kwrd">As</span> ReportDBDataSetTableAdapters.CalendarTableAdapter = _</pre>
<pre class="csharpcode">      <span class="kwrd">New </span>ReportDBDataSetTableAdapters.CalendarTableAdapter

   <span class="kwrd">If</span> calTA.GetData.Rows.Count = 0 <span class="kwrd">Then</span>
      <span class="kwrd">For</span> <span class="kwrd">Each</span> item <span class="kwrd">As</span> <span class="kwrd">Object</span> <span class="kwrd">In</span> _calendarItems
         <span class="kwrd">If</span> <span class="kwrd">TypeOf</span> item <span class="kwrd">Is</span> Outlook.AppointmentItem <span class="kwrd">Then</span>
            AddCalendarItem(<span class="kwrd">CType</span>(item, Outlook.AppointmentItem))
         <span class="kwrd">End</span> <span class="kwrd">If</span>
         Thread.Sleep(10)
      <span class="kwrd">Next</span>
   <span class="kwrd">End</span> <span class="kwrd">If</span>
   <span class="kwrd">If</span> inboxTA.GetData.Rows.Count = 0 <span class="kwrd">Then</span>
       <span class="kwrd">For</span> <span class="kwrd">Each</span> item <span class="kwrd">As</span> <span class="kwrd">Object</span> <span class="kwrd">In</span> _inboxItems
          <span class="kwrd">If</span> <span class="kwrd">TypeOf</span> item <span class="kwrd">Is</span> Outlook.MailItem <span class="kwrd">Then</span>
             AddInboxItem(<span class="kwrd">CType</span>(item, Outlook.MailItem))
          <span class="kwrd">End</span> <span class="kwrd">If</span>
          Thread.Sleep(10)
        <span class="kwrd">Next</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> sentItemTA.GetData.Rows.Count = 0 <span class="kwrd">Then</span>
       <span class="kwrd">For</span> <span class="kwrd">Each</span> item <span class="kwrd">As</span> <span class="kwrd">Object</span> <span class="kwrd">In</span> _sentMailItems
          <span class="kwrd">If</span> <span class="kwrd">TypeOf</span> item <span class="kwrd">Is</span> Outlook.MailItem <span class="kwrd">Then</span>
             AddSentMailItem(<span class="kwrd">CType</span>(item, Outlook.MailItem))
          <span class="kwrd">End</span> <span class="kwrd">If</span>
      Thread.Sleep(10)
      <span class="kwrd">Next</span>
   <span class="kwrd">End</span> <span class="kwrd">If</span>

   <span class="kwrd">RaiseEvent</span> StopDataLoad(<span class="kwrd">Me</span>, <span class="kwrd">Nothing</span>)

<span class="kwrd">End</span> Sub</pre>
<pre class="csharpcode">&nbsp;</pre>
<p>By listening to the StartDataLoad and StopDataLoad events, we can display a message to the user if they try to load a report.
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">if</span> (_isDataLoading)
{
MessageBox.Show(<span class="str">&quot;Outlook is currently initializing your folders to </span></pre>
<pre class="csharpcode"><span class="str">   enable reporting for the first time.  Try again in a few minutes.&quot;</span>, 
   <span class="str">&quot;Loading initial data&quot;</span>, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}</pre>
<pre class="csharpcode">&nbsp;</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">If</span> (_isDataLoading) <span class="kwrd">Then</span>

MessageBox.Show(<span class="str">&quot;Outlook is currently initializing your folders to enable reporting for the first time.  Try again in a few minutes.&quot;</span>, <span class="str">&quot;Loading initial data&quot;</span>, MessageBoxButtons.OK, MessageBoxIcon.Warning)</pre>
<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><strong></strong></p>
<h3>Listening for New Items</h3>
<p>After the initial data load, the add-in can just listen for incoming items to keep track of Outlook usage. To listen for incoming items, you can use folder events. To hook into folder events you first need to obtain a reference to an Outlook.MAPIFolder object
 that encapsulates an Outlook folder like Inbox, Sent Mail, or Calendar. In order to get the default Outbox folder call the GetDefaultFolder method of the MAPI namespace object. Then you need to add handlers for the ItemAdd event of the Outlook folders. The
 following code shows how to listen for incoming mail items in the Inbox folder. </p>
<p>&nbsp;</p>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="rem">// Obtain references to the folder objects that fire the events we are interested in.</span>
Outlook.MAPIFolder inbox = </pre>
<pre class="csharpcode">   app.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
<span class="rem">// Store references to the item collection objects.</span>
_inboxItems = inbox.Items;
_inboxItems.ItemAdd &#43;= <span class="kwrd">new</span> Outlook.ItemsEvents_ItemAddEventHandler(InboxFolderItemAdded)
</pre>
<pre class="csharpcode"><span class="rem">/// &lt;summary&gt;</span>
<span class="rem">/// Handles new mail items added to the inbox</span>
<span class="rem">/// &lt;/summary&gt;</span>
<span class="rem">/// &lt;param name=&quot;Item&quot;&gt;Reference to the Outlook object added&lt;/param&gt;</span>
<span class="kwrd">private</span> <span class="kwrd">void</span> InboxFolderItemAdded(<span class="kwrd">object</span> Item)
{
   <span class="kwrd">if</span> (Item <span class="kwrd">is</span> Outlook.MailItem)
   {
      AddInboxItem(Item <span class="kwrd">as</span> Outlook.MailItem);
   }
}
</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">Dim</span> inbox <span class="kwrd">As</span> Outlook.MAPIFolder = _</pre>
<pre class="csharpcode">   app.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
_inboxItems = inbox.Items
<span class="kwrd">AddHandler</span> _inboxItems.ItemAdd, <span class="kwrd">AddressOf</span> InboxFolderItemAdded</pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> InboxFolderItemAdded(<span class="kwrd">ByVal</span> Item <span class="kwrd">As</span> <span class="kwrd">Object</span>)
   <span class="kwrd">If</span> <span class="kwrd">TypeOf</span> Item <span class="kwrd">Is</span> Outlook.MailItem <span class="kwrd">Then</span>
      AddInboxItem(<span class="kwrd">CType</span>(Item, Outlook.MailItem))
   <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Sub</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>
<pre class="csharpcode">&nbsp;</pre>
<p>Appointments and sent mail items can be tracked in a similar manner. Additionally, the Outlook folders support events for removing or changing items.
</p>
<p>Items can easily be stored in the database by using table adapters automatically generated from the dataset. Each item has a table adapter which corresponds to a table in the database.
</p>
<p>Visual C#</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>
<pre class="csharpcode"><span class="rem">/// &lt;summary&gt;</span>
<span class="rem">/// Stores a new message in the database</span>
<span class="rem">/// &lt;/summary&gt;</span>
<span class="rem">/// &lt;param name=&quot;mailItem&quot;&gt;&lt;/param&gt;</span>
<span class="kwrd">private</span> <span class="kwrd">void</span> AddInboxItem(Outlook.MailItem mailItem)
{
ReportDBDataSetTableAdapters.InboxTableAdapter ta = </pre>
<pre class="csharpcode">   <span class="kwrd">new</span> ReportDBDataSetTableAdapters.InboxTableAdapter();

   <span class="rem">//determine if mail was sent to an alias or group address</span>
   <span class="kwrd">bool</span> isAliased = <span class="kwrd">true</span>;
   <span class="kwrd">if</span> (mailItem.To == mailItem.ReceivedOnBehalfOfName || mailItem.CC == mailItem.ReceivedOnBehalfOfName)
   {
      isAliased = <span class="kwrd">false</span>;
   }
   <span class="kwrd">try</span>
   {
      ta.Insert(mailItem.SenderName, </pre>
<pre class="csharpcode">      mailItem.SenderName, mailItem.SentOn, isAliased, <span class="kwrd">null</span>, </pre>
<pre class="csharpcode">      mailItem.Subject, mailItem.EntryID);
   }
   <span class="kwrd">catch</span> (Exception ex)
   {
      System.Diagnostics.Debug.Write(ex);
   }
}
</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><br>
Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> AddInboxItem(<span class="kwrd">ByVal</span> mailItem <span class="kwrd">As</span> Outlook.MailItem)
   <span class="kwrd">Dim</span> ta <span class="kwrd">As</span> ReportDBDataSetTableAdapters.InboxTableAdapter = <span class="kwrd">New</span> ReportDBDataSetTableAdapters.InboxTableAdapter
   <span class="kwrd">Dim</span> isAliased <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">True</span>
   <span class="kwrd">If</span> mailItem.<span class="kwrd">To</span> = mailItem.ReceivedOnBehalfOfName <span class="kwrd">OrElse</span> mailItem.CC = mailItem.ReceivedOnBehalfOfName <span class="kwrd">Then</span>
                isAliased = <span class="kwrd">False</span>
   <span class="kwrd">End</span> <span class="kwrd">If</span>
   <span class="kwrd">Try</span>
      ta.Insert(mailItem.SenderName, mailItem.SenderName, mailItem.SentOn, isAliased, <span class="kwrd">Nothing</span>, mailItem.Subject, mailItem.EntryID)
   <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception
      System.Diagnostics.Debug.Write(ex)
   <span class="kwrd">End</span> <span class="kwrd">Try</span>
<span class="kwrd">End</span> Sub</pre>
<pre class="csharpcode">&nbsp;</pre>
<h3>Producing the Reports</h3>
<p>Now that we a have some data points about our Outlook usage, we can produce reports. The reports are displayed in a datagrid on a form that is launched from the Reports menu. The report popup dialog contains a selector for various report types and a selectable
 date range. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image019.png"><img height="185" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb7.png" width="320" border="0"></a>
</p>
<p>Each report is populated using a method from our table adapters. For example, to get a count of emails sent over a given period, you can use the following code:
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">this</span>.inboxTableAdapter.CountEmailsRecieved(<span class="kwrd">this</span>.reportDBDataSet.Inbox, fromDate, toDate);
<span class="kwrd">this</span>.dataGridView1.Columns.Add(<span class="str">&quot;Emails Recieved&quot;</span>, <span class="str">&quot;Emails Received&quot;</span>);
<span class="kwrd">this</span>.dataGridView1.Columns[<span class="str">&quot;Emails Recieved&quot;</span>].DataPropertyName = <span class="str">&quot;Emails Recieved&quot;</span>;
<span class="kwrd">this</span>.reportDBDataSetBindingSource.DataSource = <span class="kwrd">this</span>.reportDBDataSet.Inbox;</pre>
<pre class="csharpcode">&nbsp;</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Me</span>.InboxTableAdapter.CountEmailsRecieved(<span class="kwrd">Me</span>.ReportDBDataSet.Inbox, fromDate, toDate)
<span class="kwrd">Me</span>.dataGridView1.Columns.Add(<span class="str">&quot;Emails Recieved&quot;</span>, <span class="str">&quot;Emails Received&quot;</span>)
<span class="kwrd">Me</span>.dataGridView1.Columns(<span class="str">&quot;Emails Recieved&quot;</span>).DataPropertyName = <span class="str">&quot;Emails Recieved&quot;</span>
<span class="kwrd">Me</span>.reportDBDataSetBindingSource.DataSource = <span class="kwrd">Me</span>.ReportDBDataSet.Inbox</pre>
<pre class="csharpcode">&nbsp;</pre>
<h3>Creating a Form Region</h3>
<p>Another way you can display data about Outlook usage is a form region. Form regions can be added to any existing Outlook form. You can also control whether the region is shown in the preview pane, the inspector, or on new items. For this add-in, we'll add
 a form region on email messages to show statistics about the recipient / sender.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image018.png"><img height="67" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb6.png" width="320" border="0"></a>
</p>
<p>The first step in creating a new form region is to customize an existing Outlook form. In Outlook, click Tools -&gt; Forms -&gt; Design a Form. Then select Message from the standard forms library. The Outlook form will appear in the design view. On the ribbon
 bar, select the button for creating a new form region. </p>
<pre class="csharpcode">&nbsp;</pre>
<pre class="csharpcode"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image022.png"><img height="222" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb8.png" width="320" border="0"></a> </pre>
<pre class="csharpcode">&nbsp;</pre>
<p>On the form, add a new textbox control. You can't use the regular Outlook textbox though. Right-click the Toolbox window and select Custom Controls. Scroll through the list of controls and select the Microsoft Office Outlook TextBox Control, and then click
 OK. </p>
<pre class="csharpcode"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image025.png"><img height="199" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb9.png" width="320" border="0"></a> </pre>
<pre class="csharpcode">&nbsp;</pre>
<p>Add the textbox to the form to display the Outlook statistics. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image028.png"><img height="116" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/image0_thumb10.png" width="320" border="0"></a>
</p>
<p>Now you can save the form region as an .ofs file and add it to the project as a resource file. In order to connect the form region with our add-in, we need to create a region manifest file and a registry entry. The region manifest is an xml file that defines
 how Outlook displays the region. </p>
<pre class="csharpcode"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">encoding</span><span class="kwrd">=&quot;utf-8&quot;</span> ?<span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">FormRegion</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/office/12/outlook/formregion.xsd&quot;</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">name</span><span class="kwrd">&gt;</span>OutlookStatsRegionCS<span class="kwrd">&lt;/</span><span class="html">name</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">formRegionType</span><span class="kwrd">&gt;</span>adjoining<span class="kwrd">&lt;/</span><span class="html">formRegionType</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">title</span><span class="kwrd">&gt;</span>Outlook Statistics<span class="kwrd">&lt;/</span><span class="html">title</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">showInspectorRead</span><span class="kwrd">&gt;</span>true<span class="kwrd">&lt;/</span><span class="html">showInspectorRead</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">showReadingPane</span><span class="kwrd">&gt;</span>true<span class="kwrd">&lt;/</span><span class="html">showReadingPane</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">showInspectorCompose</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">showInspectorCompose</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">addin</span><span class="kwrd">&gt;</span>OutlookStatsCS.Connect<span class="kwrd">&lt;/</span><span class="html">addin</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">FormRegion</span><span class="kwrd">&gt;</span>
</pre>
<pre class="csharpcode">&nbsp;</pre>
<p>The documentation for the XML Schema for form regions is located <a href="http://www.microsoft.com/downloads/details.aspx?familyid=15805380-f2c0-4b80-9ad1-2cb0c300aef9&amp;displaylang=en">
here</a>. Since the form for composing new mail item shouldn't have usage statistics at the bottom, set the showInspectorCompose property to false.
</p>
<p>To associate the region manifest with Outlook, you need to create a new registry key under HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\FormRegions\IPM.Note called OutlookStatsRegionCS. The value of the key should be the path to the region manifest
 XML file. A sample registry file is included in the project's \Registry folder in the region_registry.reg file.
</p>
<h3>Wiring the Region to the Outlook Add-in</h3>
<p>Because form regions are based on the Microsoft Forms 2.0 types, you need to add a reference in the add-in project to Microsoft Forms 2.0 Object Library. Now you can add a new class to manage that form region, called OutlookStatsRegion.cs.
</p>
<p>The constructor for this class needs a reference to the instance of the form region.
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> OutlookStatsRegion(Outlook.FormRegion region)
{
   _region = region;
   _region.Close &#43;= <span class="kwrd">new</span> Outlook.FormRegionEvents_CloseEventHandler(Region_Close);

   _form = region.Form <span class="kwrd">as</span> Forms.UserForm;

   _txtStats = (Outlook.OlkTextBox)_form.Controls.Item(<span class="str">&quot;txtStats&quot;</span>);
   _txtStats.Text = GetEmailStatistics(region.Item);
}
</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>(<span class="kwrd">ByVal</span> [region] <span class="kwrd">As</span> Outlook.FormRegion)
   _region = [region]
   <span class="kwrd">AddHandler</span> _region.Close, <span class="kwrd">AddressOf</span> Region_Close

   _form = <span class="kwrd">CType</span>([region].Form, Forms.UserForm)

   _txtStats = <span class="kwrd">CType</span>(_form.Controls.Item(<span class="str">&quot;txtStats&quot;</span>), Outlook.OlkTextBox)
   _txtStats.Text = GetEmailStatistics([region].Item)
<span class="kwrd">End</span> <span class="kwrd">Sub</span> 'New</pre>
<pre class="csharpcode">&nbsp;</pre>
<p>Using the reference to the region, we can get access to the mail item, and therefore the sender name and email address need to display the statistics.
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">string</span> GetEmailStatistics(<span class="kwrd">object</span> Item)
{
   <span class="kwrd">string</span> result = <span class="kwrd">string</span>.Empty;

   <span class="kwrd">if</span> (Item <span class="kwrd">is</span> Outlook.MailItem)
   {
      Outlook.MailItem mailItem = Item <span class="kwrd">as</span> Outlook.MailItem;

ReportDBDataSetTableAdapters.InboxTableAdapter inboxTA = <span class="kwrd">new</span> ReportDBDataSetTableAdapters.InboxTableAdapter();

      <span class="kwrd">int</span>? countEmailsReceived = inboxTA.CountEmailsReceivedFrom(mailItem.SenderName);
                
      sb.Append(<span class="str">&quot;Emails received from &quot;</span>);
      sb.Append(mailItem.SenderName);
      sb.Append(<span class="str">&quot;: &quot;</span>);
      sb.Append(countEmailsReceived.Value.ToString());
      sb.Append(<span class="str">&quot;  [&quot;</span>);
      sb.Append(percentTotalReceived);
      sb.AppendLine(<span class="str">&quot;% of total received]&quot;</span>);

      result = sb.ToString();
   }

   <span class="kwrd">return</span> result;
}</pre>
<pre class="csharpcode">&nbsp;</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> GetEmailStatistics(<span class="kwrd">ByVal</span> Item <span class="kwrd">As</span> <span class="kwrd">Object</span>) <span class="kwrd">As</span> <span class="kwrd">String</span>
   <span class="kwrd">Dim</span> result <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty

   <span class="kwrd">If</span> <span class="kwrd">TypeOf</span> Item <span class="kwrd">Is</span> Outlook.MailItem <span class="kwrd">Then</span>
      <span class="kwrd">Dim</span> mailItem <span class="kwrd">As</span> Outlook.MailItem = <span class="kwrd">CType</span>(Item, Outlook.MailItem)
      <span class="kwrd">Dim</span> inboxTA <span class="kwrd">As</span> <span class="kwrd">New</span> ReportDBDataSetTableAdapters.InboxTableAdapter()
      <span class="kwrd">Dim</span> inbox <span class="kwrd">As</span> <span class="kwrd">New</span> ReportDBDataSet.InboxDataTable()
      <span class="kwrd">Dim</span> countEmailsReceived <span class="kwrd">As</span> Nullable(Of <span class="kwrd">Integer</span>) = _</pre>
<pre class="csharpcode">         inboxTA.CountEmailsReceivedFrom(mailItem.SenderName)

      sb.Append(<span class="str">&quot;Emails received from &quot;</span>)
      sb.Append(mailItem.SenderName)
      sb.Append(<span class="str">&quot;: &quot;</span>)
      sb.Append(countEmailsReceived.Value.ToString())
      sb.Append(<span class="str">&quot;  [&quot;</span>)
      sb.Append(percentTotalReceived)

      result = sb.ToString()
   <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">Return</span> result
<span class="kwrd">End</span> <span class="kwrd">Function</span> <span class="rem">'GetEmailStatistics</span>
</pre>
<p>Almost there. Next we have to modify the Connect class to implement the form region interface.
</p>
<p><strong>Visual C#</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Connect : Outlook.FormRegionStartup</pre>
<pre class="csharpcode">&nbsp;</pre>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode">Partial <span class="kwrd">Public</span> <span class="kwrd">Class</span> Connect
<span class="kwrd">   Implements</span> Outlook.FormRegionStartup</pre>
<pre class="csharpcode">&nbsp;</pre>
<p>The two methods defined in this interface are called as Outlook loads an item and prepares to show a form. When Outlook starts to load the user interface for a message class that has a form region registered, it first calls the
<b>GetFormRegionStorage</b> method to load the layout information for the form region.
<b>GetFormRegionStorage</b> should return either a string (which is the path to the .ofs file), an
<b>IStorage</b> instance for the contents of the .ofs file, or a byte array that contains the contents of the .ofs file. Before Outlook displays the form region to the user, it calls the
<b>BeforeFormRegionShow</b> method, and passes a reference to the form region object.</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><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">&nbsp;</pre>
<p><strong>Visual C#</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">object</span> GetFormRegionStorage(<span class="kwrd">string</span> FormRegionName, <span class="kwrd">object</span> Item,
   <span class="kwrd">int</span> LCID, Outlook.OlFormRegionMode FormRegionMode,
   Outlook.OlFormRegionSize FormRegionSize)
{
   <span class="kwrd">if</span> (FormRegionName == <span class="str">&quot;OutlookStatsRegionCS&quot;</span>)
   {
      <span class="rem">// Return the storage only when there are headers</span>
      <span class="kwrd">return</span> Properties.Resources.OutlookStatsRegionCS;
   }

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

<span class="kwrd">public</span> <span class="kwrd">void</span> BeforeFormRegionShow(Outlook.FormRegion FormRegion)
{
   <span class="kwrd">if</span> (FormRegion.InternalName == <span class="str">&quot;OutlookStatsRegionCS&quot;</span>)
   {
      OutlookStatsRegion newRegion = <span class="kwrd">new</span> OutlookStatsRegion(FormRegion);
      newRegion.Closed &#43;= <span class="kwrd">new</span> EventHandler(Region_Closed);

      _openRegions.Add(newRegion);
   }
}
</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></strong>&nbsp;</p>
<p><strong>Visual Basic</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> BeforeFormRegionShow(<span class="kwrd">ByVal</span> FormRegion <span class="kwrd">As</span> Microsoft.Office.Interop.Outlook.FormRegion) <span class="kwrd">Implements</span> Microsoft.Office.Interop.Outlook._FormRegionStartup.BeforeFormRegionShow
   <span class="kwrd">If</span> FormRegion.InternalName = <span class="str">&quot;OutlookStatsRegionVB&quot;</span> <span class="kwrd">Then</span>
      <span class="kwrd">Dim</span> newRegion <span class="kwrd">As</span> <span class="kwrd">New</span> OutlookStatsRegion(FormRegion)
      <span class="kwrd">AddHandler</span> newRegion.Closed, <span class="kwrd">AddressOf</span> Region_Closed

      _openRegions.Add(newRegion)

   <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> <span class="kwrd">Sub</span>

<span class="kwrd">Public</span> <span class="kwrd">Function</span> GetFormRegionStorage(<span class="kwrd">ByVal</span> FormRegionName <span class="kwrd">As</span> <span class="kwrd">String</span>, _</pre>
<pre class="csharpcode">   <span class="kwrd">ByVal</span> Item <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> LCID <span class="kwrd">As</span> <span class="kwrd">Integer</span>, _</pre>
<pre class="csharpcode">   <span class="kwrd">ByVal</span> FormRegionMode <span class="kwrd">As</span> Microsoft.Office.Interop.Outlook.OlFormRegionMode, _</pre>
<pre class="csharpcode">   <span class="kwrd">ByVal</span> FormRegionSize <span class="kwrd">As</span> Microsoft.Office.Interop.Outlook.OlFormRegionSize) <span class="kwrd">As</span> <span class="kwrd">Object</span> <span class="kwrd">Implements</span> Microsoft.Office.Interop.Outlook._FormRegionStartup.GetFormRegionStorage

   <span class="kwrd">If</span> FormRegionName = <span class="str">&quot;OutlookStatsRegionVB&quot;</span> <span class="kwrd">Then</span>
      <span class="kwrd">Return</span> My.Resources.OutlookStatsRegionVB
   <span class="kwrd">End</span> <span class="kwrd">If</span>

   <span class="kwrd">Return</span> <span class="kwrd">Nothing</span>
<span class="kwrd">End</span> Function</pre>
<pre class="csharpcode">&nbsp;</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 last step is to register the add-in with Outlook. The add-in template provided with this article automatically generates a .reg file with the necessary settings to register the COM add-in created by the project with Outlook. Double click the .reg in
 Windows Explorer to register the add-in. Now you can change the debug properties of the project to start Outlook when debugging by setting the Start Action to Start External Program and then browse to the path of Outlook 2007.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/clip_image002114.jpg"><img height="170" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1111248/clip_image002113.jpg" width="240" border="0"></a>
</p>
<h3>Conclusion</h3>
<p>As you can see, VSTO 2005 SE allows developers a powerful tool for customizing Office 2007. New features in VSTO 2005 SE such as the Ribbon bar and custom form regions allow for even better integration than previous versions of VSTO. Outlook events made
 it possible for us to calculate statistics about email and calendar usage. In addition to the reports included in this add-in there is room for future additions. Some possibilities are:
</p>
<ul>
<li>Adding a custom region on contacts to show amount of time spent in meetings with a particular person
</li><li>Tracking the amount of time spent reading / composing emails </li><li>Tracking the amount spent on tasks or the percentage of tasks completed on time</li></ul>
<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><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> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Kevin-Marshall/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:7cfbf75fd5da4ff08f429e7600d80568">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Collecting-Outlook-2007-Statistics-Using-VSTO-2005-SE</comments>
      <itunes:summary>



&amp;nbsp;
This article demonstrates how you can create an Outlook add-in using

VSTO 2005 SE to listen to outlook events, store data about outlook usage, and produce reports on that usage in a custom form and a form region.



Kevin Marshall, Clarity Consulting, Inc.
Clarity Blogs

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Office 2007
Visual Studio Express 
VSTO 2005 SE 
Outlook Add-in Templates
Hardware: 
Download: Download








Outlook is used by many people everyday, but few people probably realize the wealth of data that can be learned from how they use Outlook. How long does it take you to respond to emails on average? How many hours do you spend in meetings per week? Using
 Visual Studio Tools for Office Second Edition (VSTO 2005 SE) and Office 2007, you can easily find the answers to these questions and more by building an add-in for Outlook. This article demonstrates how you can listen to outlook events, store data about outlook
 usage, and produce reports on that usage in a custom form and new to VSTO 2005 SE, a form region. 
&amp;nbsp; 

 
&amp;nbsp; 
What is VSTO 2005 SE?
VSTO 2005 SE is a free add-on to Visual Studio 2005 that enables developers to build applications targeting the 2007 Office system. Developers can create Office-based solutions using the professional development environment of Visual Studio 2005 and the
 new programming model features of Office 2007 like the ribbon bar and custom form regions.
 
Creating an Outlook Add-in Project
After installing VSTO 2005 SE and the Outlook Add-in template, you can begin creating an Outlook 2007 add-in. Create a new project, then select Office Outlook 2007 Add-in from the My Templates group and click OK.
 

 
&amp;nbsp; 
The newly created project will have several files. Connect.cs is the main file which contains two methods,
InitializeAddin and ShutdownAddin which provide you a starting point for interfacing with Outlook.
 
Initializing the Add-in
The InitializeAddin method is cal</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Collecting-Outlook-2007-Statistics-Using-VSTO-2005-SE</link>
      <pubDate>Mon, 20 Nov 2006 19:08:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Collecting-Outlook-2007-Statistics-Using-VSTO-2005-SE</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1111248_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1111248_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Kevin Marshall</dc:creator>
      <itunes:author>Kevin Marshall</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Collecting-Outlook-2007-Statistics-Using-VSTO-2005-SE/RSS</wfw:commentRss>
      <category>Productivity</category>
      <category>Windows</category>
    </item>
  <item>
      <title>Visual Foos 2005</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">&nbsp;</td>
<td class=""><span class="entry_description">In this article, I'm going to cover a few ways to harness the power of Visual Studio 2005, SQL Server 2005, and a free foosball table to create the ultimate break room accessory.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Kevin Marshall, Clarity Consulting Inc.</div>
<div class="entry_company"><a href="http://blogs.claritycon.com/blogs/kevin_marshall/default.aspx">Kevin's Blog</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">Greater than $200</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input">[<a href="http://msdn.com/express/">Visual Studio Express Editions</a>,
<a href="http://www.microsoft.com/sql/default.mspx">SQL Server 2005</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/910302/VisualFoos.zip">Download</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>Late one Friday afternoon, while working at my desk, a coworker asked, &quot;Does anyone want a foosball table? My friend's office is getting rid of one, but we have to pick it up now.&quot; Even if I didn't like foosball, carrying a table a mile through the streets
 of Chicago would have made a great story. I had to get it.
<p>Because we're competitive software developers, we started recording the games in an Excel spreadsheet to track stats. While arguing whether I had lost my last four games or my last five games, I realized there had to be a better way. And so the inspiration
 for the .NET foosball tracker was born. In this article, I'm going to cover a few ways to harness the power of Visual Studio 2005, SQL Server 2005, and a free foosball table to create the ultimate break room accessory.
</p>
<h4>Hacking the Table </h4>
<p>The first step in building the foosball scoreboard application was to wire the table to a spare computer via the I-Pac, a PC interface for arcade buttons purchased from
<a href="http://www.ultimarc.com/ipac1.html">Ultimarc</a>. Using what little carpentry skills were available in our software development consultancy office, we drilled several holes in the table to mount the buttons. The I-Pac translates button presses into
 keystrokes. Each player has a button to select his or her account at the beginning of a game (we have a very competitive woman's division) or to signal that he or she scored a goal. Three other buttons were added for game setup and other special features.
 We used the <b>KeyUp</b> event, so the Visual Basic .NET scoreboard WinForm application could respond to any of the button presses. It's not the most exciting code, but hey, this is just the beginning of the article.
</p>
<p><b>Visual Basic</b> </p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> KeyPressed(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> System.<span class="kwrd">Object</span>,_<br>   <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.Windows.Forms.KeyEventArgs) <span class="kwrd">Handles</span> <span class="kwrd">MyBase</span>.KeyUp<br><br>        <span class="kwrd">Select</span> <span class="kwrd">Case</span> (e.KeyValue)<br>            <span class="kwrd">Case</span> Windows.Forms.Keys.V<br>                <span class="rem">'Home Offense Button</span><br>                <span class="kwrd">If</span> _gameMode = GameModeList.ChoosePlayers <span class="kwrd">Then</span><br>                    homeOffense.ChangePlayer()<br>                <span class="kwrd">ElseIf</span> _gameMode = GameModeList.InGame <span class="kwrd">Then</span><br>                    AddGoal(PlayerList.HomeOffense)<br>                <span class="kwrd">End</span> <span class="kwrd">If</span><br>            <span class="kwrd">Case</span> Windows.Forms.Keys.X<br>                <span class="kwrd">If</span> _gameMode = GameModeList.InGame <span class="kwrd">Then</span><br>                    <span class="rem">'InstantReplay</span><br>                    _instanyReplay.ShowReplay()<br>                <span class="kwrd">Else</span><br>                    StartScreenSaver()<br>                <span class="kwrd">End</span> <span class="kwrd">If</span><br>            <span class="kwrd">Case</span> Windows.Forms.Keys.Menu<br>                <span class="rem">'Undo Button</span><br>                <span class="kwrd">If</span> _gameMode = GameModeList.InGame <span class="kwrd">Then</span><br>                    RemoveLastGoal()<br>                <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">End</span> Select</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><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/910302/VisualFoos1_thumb.gif" border="0">
</p>
<p><b>Figure 1. Foosball Table</b> </p>
<h4>Designing the Scoreboard</h4>
<p>Lucky for us, our break room contains a 30-inch TV with VGA inputs near the foosball table to display the scoreboard application. The scoreboard consists of a form with several picture boxes and labels with transparent backgrounds on a foosball background
 image. Each set of player names and icons is a user control that tracks information such number of goals scored. Using the new table adapters in Visual Studio 2005, it's easy to bind the controls to a data table. The following code loads player attributes
 such as the player image and sounds from SQL Server. </p>
<p><b>Visual Basic</b><code>&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> LoadPlayer()<br>        <br>        playerName.DisplayMember = _playerDT.NicknameColumn.ColumnName<br><br>        <span class="kwrd">Dim</span> tauntsTA <span class="kwrd">As</span> <span class="kwrd">New</span> FoosDataTableAdapters.TauntsTableAdapter()<br>        <span class="kwrd">Dim</span> tauntsDT <span class="kwrd">As</span> <span class="kwrd">New</span> FoosData.TauntsDataTable()<br>          _taunts = <span class="kwrd">New</span> Collection<br><br>        tauntsTA.FillByPlayerID(tauntsDT, _playerID)<br>        <span class="kwrd">For</span> <span class="kwrd">Each</span> row <span class="kwrd">As</span> FoosData.TauntsRow <span class="kwrd">In</span> tauntsDT<br>            _taunts.Add(row.Item(<span class="str">&quot;SoundClip&quot;</span>))<br>        <span class="kwrd">Next</span> row<br><br>        <span class="kwrd">Dim</span> dr <span class="kwrd">As</span> DataRow() = _playerDT.<span class="kwrd">Select</span>(<span class="str">&quot;PlayerID = &quot;</span> &amp; _playerID)<br>        <span class="kwrd">If</span> <span class="kwrd">Not</span> dr(0).Item(<span class="str">&quot;Avatar&quot;</span>) <span class="kwrd">Is</span> DBNull.Value <span class="kwrd">Then</span><br>            <span class="kwrd">Dim</span> img <span class="kwrd">As</span> <span class="kwrd">Byte</span>()<br>            img = <span class="kwrd">CType</span>(dr(0).Item(<span class="str">&quot;Avatar&quot;</span>), <span class="kwrd">Byte</span>())<br>            playerPic.Image = Image.FromStream(<span class="kwrd">New</span> System.IO.MemoryStream(img))<br>        <span class="kwrd">Else</span><br>            playerPic.Image = My.Resources.Resource.clarityLogo<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>After cycling through a list of employee accounts in the database using the player's button, it's time to play some foosball. Without budget enough to hire Keith Jackson to provide game commentary full-time, we added our own virtual announcer using the
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=1194ed95-7a23-46a0-bbbc-06ef009c053a&amp;DisplayLang=en">
Microsoft Speech API</a>. To make your application speak, all you need to do is add a reference to SpeechLib.dll and declare a new speech object.
</p>
<p><b>Visual Basic</b> </p>
<pre class="csharpcode"><span class="kwrd">Dim</span> voice <span class="kwrd">As</span> <span class="kwrd">New</span> SpVoice<br>voice.Speak(<span class="str">&quot;Whoa Nelly! Welcome to the Clarity Foos League&quot;</span>,_<br>             SpeechVoiceSpeakFlags.SVSFDefault)</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><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/910302/VisualFoos2_thumb.gif" border="0">
</p>
<p><b>Figure 2. Scoreboard</b> </p>
<h4>Taunting Your Opponent</h4>
<p>When playing office foosball, nothing is more important than a witty taunt to demoralize your opponent. When a player scores a goal, he presses the button in his corner, which fires a goal scored event which then triggers several actions. One action is to
 play a random sound clip from the player's personal sound collection retrieved from SQL Server. I'm mostly a C# developer, so the new Visual Basic .NET My Classes was something I wanted to try out. My Classes make it simple to perform dozens of tasks like
 playing any .wav file. </p>
<p><b>Visual Basic</b><code>&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> PlayRandomSoundFile()<br>            randomInt = r.<span class="kwrd">Next</span>(1, _taunts.Count)<br>            My.Computer.Audio.Play(_taunts(randomInt),_<br>            AudioPlayMode.WaitToComplete)<br><span class="kwrd">End</span> Sub</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>
<h4>Let's See That in Instant Replay</h4>
<p>When we first started this project, instant replay was buried in my list of dream features. I never thought I'd actually code half of those and instant replay seemed like it would take longer than my break to do. With a little lunchtime Internet surfing,
 I found this easy-to-use video capture/player ActiveX control from <a href="http://www.fathsoft.com/videocapx.html">
Fath Software</a> called VideoCapX. (Oh, and I nearly tore apart the ceiling while trying to run a 50-ft USB cable through the tiles to the Clarity SkyCam©, but let's keep that from the office admin) In just a few lines of code, I can watch over and over again
 how terrible I am at blocking a pull shot. </p>
<p><b>Visual Basic</b><code>&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> ShowReplay()<br>        <span class="kwrd">Dim</span> vidLength <span class="kwrd">As</span> <span class="kwrd">Double</span><br>        vcx.StopCapture()<br>        vcx.PlayerOpen(FOOS_REPLAY_WMV)<br>        vidLength = vcx.PlayerGetLenMS()<br>        <span class="kwrd">If</span> vidLength &gt; 10000 <span class="kwrd">Then</span><br>            vcx.PlayerSetPos(vidLength - 10000)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        vcx.PlayerSetSize(640, 480)<br>        <span class="kwrd">Me</span>.BringToFront()<br>        My.Computer.Audio.Play(My.Resources.Resource.InstantReplay,_<br>                               AudioPlayMode.WaitToComplete)<br>        vcx.PlayerStart()<br><span class="kwrd">End</span> Sub</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><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/910302/VisualFoos3_thumb.gif" border="0">
</p>
<p><b>Figure 3. Instant Replay</b> </p>
<h4>Archiving the Results</h4>
<p>It's game over and there is an 80 percent chance that I lost in a blowout; time to put that box score in the record books. For those of you keeping score at home, the table adapters make it simple to save the game record to the database.
</p>
<p><b>Visual Basic</b><code>&nbsp; &nbsp;<br>
</code></p>
<pre class="csharpcode">        <span class="kwrd">Dim</span> gameTA <span class="kwrd">As</span> <span class="kwrd">New</span> FoosDataTableAdapters.GameTableAdapter()<br>        gameTA.Insert(homeOffense.playerName, homeOffense.goals, _<br>        homeDefense.playerName, homeDefense.goals, _<br>        visitorOffense.playerName, visitorOffense.goals, _<br>        visitorDefense.playerName, visitorDefense.goals, _<br>        gameStartTime, gameEndTime)</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>With all the game stats recorded in SQL Server, we can produce dozens of reports such as win percentage, total goals scored, shutouts, average goals scored per game, average goals allowed per game, and using a formula based loosely on the BCS (U.S. college
 football) computer rankings, the top overall player. Sadly, I wrote the application and I still can't get my name into the top 10 players.
</p>
<p>These stats are displayed on an arcade-like teaser screen that loads after the application has been idle for a few minutes. The teaser screen cycles through several dozen datasets to provide a different set of stats on the screen.
</p>
<p><b>Visual Basic</b><code><br>
</code></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> LoadStats()<br>        statTimer.Enabled = <span class="kwrd">True</span><br>        <span class="kwrd">Dim</span> statType <span class="kwrd">As</span> <span class="kwrd">Integer</span> = ChooseRandomStatList()<br>        <span class="kwrd">Dim</span> playerDT <span class="kwrd">As</span> <span class="kwrd">New</span> FoosData.PlayerDataTable()<br>        <span class="kwrd">Dim</span> playerTA <span class="kwrd">As</span> <span class="kwrd">New</span> FoosDataTableAdapters.PlayerTableAdapter()<br><br>        <span class="kwrd">Select</span> <span class="kwrd">Case</span> statType<br>            <span class="kwrd">Case</span> 1<br>                playerTA.FillByTop10Winners(playerDT)<br>                statTitle.Text = <span class="str">&quot;Most Wins&quot;</span><br>                ResizeFont(FontSize.Large)<br>            <span class="kwrd">Case</span> 2<br>                playerTA.FillByTop10WinPercentage(playerDT)<br>                statTitle.Text = <span class="str">&quot;Best Win %&quot;</span><br>                ResizeFont(FontSize.Large)<br>            <span class="kwrd">Case</span> 3<br>                playerTA.FillByTop10Foosers(playerDT)<br>                statTitle.Text = <span class="str">&quot;Biggest Foosers&quot;</span><br>                ResizeFont(FontSize.Large)<br>                    …More stats…<br>                <span class="kwrd">End</span> <span class="kwrd">Select</span><br><span class="kwrd">End</span> Sub</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><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/910302/VisualFoos4.gif">
</p>
<p><b>Figure 4. Teaser Screen</b> </p>
<h4>Conclusion</h4>
<p>Visual Basic.NET has dozens of new features that make quickly building an application very easy. In just a few hours I was able to put together an application that has significantly improved the fun of having a foosball table in the office. Unfortunately,
 it still can't make me play better. Maybe next version. Speaking of the next version, on my brand new
<a href="http://blogs.claritycon.com/blogs/kevin_marshall/">blog</a>, I'm going to cover some future additions to Visual Foos 2005 like a Web front-end to view game logs and upload sound files. Some other additions I'd like to develop are a RSS feed of games
 played, pre-game predictions using SQL Server Analysis Services, player identification through RFID readers, and a foosball speed radar. If anyone has any suggestions, I'd love to hear them! Or if you have a foosball table you don't want.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Kevin-Marshall/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:a74cd9d37d0746669c3c9e7600dbab1f">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Visual-Foos-2005</comments>
      <itunes:summary>



&amp;nbsp;
In this article, I&#39;m going to cover a few ways to harness the power of Visual Studio 2005, SQL Server 2005, and a free foosball table to create the ultimate break room accessory.



Kevin Marshall, Clarity Consulting Inc.
Kevin&#39;s Blog

Difficulty: Advanced
Time Required: 
6-10 hours
Cost: Greater than $200
Software: [Visual Studio Express Editions,
SQL Server 2005
Hardware: 
Download: Download







Late one Friday afternoon, while working at my desk, a coworker asked, &amp;quot;Does anyone want a foosball table? My friend&#39;s office is getting rid of one, but we have to pick it up now.&amp;quot; Even if I didn&#39;t like foosball, carrying a table a mile through the streets
 of Chicago would have made a great story. I had to get it.
Because we&#39;re competitive software developers, we started recording the games in an Excel spreadsheet to track stats. While arguing whether I had lost my last four games or my last five games, I realized there had to be a better way. And so the inspiration
 for the .NET foosball tracker was born. In this article, I&#39;m going to cover a few ways to harness the power of Visual Studio 2005, SQL Server 2005, and a free foosball table to create the ultimate break room accessory.
 
Hacking the Table 
The first step in building the foosball scoreboard application was to wire the table to a spare computer via the I-Pac, a PC interface for arcade buttons purchased from
Ultimarc. Using what little carpentry skills were available in our software development consultancy office, we drilled several holes in the table to mount the buttons. The I-Pac translates button presses into
 keystrokes. Each player has a button to select his or her account at the beginning of a game (we have a very competitive woman&#39;s division) or to signal that he or she scored a goal. Three other buttons were added for game setup and other special features.
 We used the KeyUp event, so the Visual Basic .NET scoreboard WinForm application could respond to any of the button presses.</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Visual-Foos-2005</link>
      <pubDate>Tue, 31 Oct 2006 12:07:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Visual-Foos-2005</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/910302_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/910302_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Kevin Marshall</dc:creator>
      <itunes:author>Kevin Marshall</itunes:author>
      <slash:comments>8</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Visual-Foos-2005/RSS</wfw:commentRss>
      <category>SQL</category>
      <category>SQL Server</category>
      <category>Touch</category>
    </item>    
</channel>
</rss>