<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7740113442922996729</id><updated>2011-07-29T12:02:03.907+08:00</updated><category term='Team Build'/><category term='Visual Studio 2005'/><category term='SQL Server'/><category term='Sandcastle'/><category term='ClickOnce'/><category term='Security'/><category term='Blogger'/><category term='IIS'/><category term='Web Service'/><category term='WSS 3.0'/><category term='ASP.NET'/><category term='VSTO'/><category term='Visual Studio 2008'/><category term='WCSF'/><category term='Web Development Server'/><category term='WCF'/><category term='Coding Standards'/><category term='Outlook 2007'/><category term='Web Parts'/><category term='RDC'/><category term='Memory'/><category term='Patterns'/><category term='Documentation'/><category term='SQl Server 2005 Express'/><category term='LLBLGEN'/><category term='.NET'/><category term='Books'/><title type='text'>Adrian's Developer Blog</title><subtitle type='html'>Development notes, observations and links to people smarter than me.&lt;br&gt;
Topics: Visual Studio, .NET, C#, VSTO &amp;amp; Outlook 2007, WSS, ASP.NET, SQL Server...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6146296664685618505</id><published>2009-11-25T23:14:00.004+11:00</published><updated>2009-11-25T23:21:43.803+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Development Server'/><title type='text'>Microsoft Web Development Server Command Line</title><content type='html'>If you ever need to host a web site on your machine (for testing or whatever), you can use the Microsoft Web Development Server (Visual Studio runs this from the IDE) manually via the command line.&lt;br /&gt;&lt;br /&gt;I found this particularly useful to test deployment builds (eg: msdeploy) if you don’t have IIS!&lt;br /&gt;&lt;br /&gt;There appears to be some confusion over where this EXE lives, but on my machine it is here:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;C:\Program Files\Common Files\Microsoft Shared\DevServer\9.0\webdev.webserver.exe&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;All you need to do is give it a port, a file path, and the name of the virtual directory to use.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;"C:\Program Files\Common Files\Microsoft Shared\DevServer\9.0\webdev.webserver.exe" /port:4955 /path:"C:\Build\Test\DotNet\Test.Project.Web" /vpath:/TestProj&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6146296664685618505?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6146296664685618505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6146296664685618505' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6146296664685618505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6146296664685618505'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2009/11/microsoft-web-development-server.html' title='Microsoft Web Development Server Command Line'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-3510297839354943975</id><published>2009-07-14T15:13:00.005+08:00</published><updated>2009-07-14T15:34:39.375+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Security'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>WCF Security Issues With IIS</title><content type='html'>WCF Security shouldn't be that difficult, but I've recently run into some problems that just couldn't be forseen (at least for me).&lt;br /&gt;&lt;br /&gt;I have a WCF Service hosted in IIS - I have set IIS to &lt;span style="font-style: italic;"&gt;Require secure channel (SSL)&lt;/span&gt; traffic and set the virtual directory security to &lt;span style="font-style: italic;"&gt;Integrated Windows authentication&lt;/span&gt; only.&lt;br /&gt;&lt;br /&gt;In my WCF Service web.config, I use the following binding configuration:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;bindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;basichttpbinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="SecureTransport"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt; &lt;span class="attr"&gt;mode&lt;/span&gt;&lt;span class="kwrd"&gt;="Transport"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;transport&lt;/span&gt; &lt;span class="attr"&gt;clientcredentialtype&lt;/span&gt;&lt;span class="kwrd"&gt;="Windows"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;transport&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;basichttpbinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;The security mode of &lt;span style="font-style: italic;"&gt;Transport &lt;/span&gt;is for communication over SSL. The client credential type of &lt;span style="font-style: italic;"&gt;Windows &lt;/span&gt;is for Integrated Windows authentication.&lt;br /&gt;&lt;br /&gt;This should work fine, right? Well, it did on one test box, but on another I had a number of problems, each outline below.&lt;br /&gt;&lt;br /&gt;I would normally use a browser to test the connection first.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Error: Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Even if IIS is configured for Integrated Windows authentication only and your service configuration specifies Windows as the client configuration, you get the following error in your browser:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If this error is returned and Windows Authentication has been enabled in IIS, it means there is an issue with the supported network authentication schemes for the website that the web service is installed under. The most likely cause is that it is configured for NTLM only. We want to specify NTLM and Negotiate.&lt;br /&gt;&lt;br /&gt;The following Microsoft KB article describes how to enable both schemes:&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/215383"&gt;http://support.microsoft.com/kb/215383&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After this has been done IIS will need to be restarted, or the web service application will need restarting (load the web.config file and save without changing anything).&lt;br /&gt;&lt;br /&gt;It would appear that the Windows credential setting in WCF .NET maps directly to the Negotiate scheme in IIS.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);"&gt;Error: Could not establish trust relationship for the SSL/TLS secure channel with authority.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The certificate is not fully trusted. This is likely to be a temporary certficate or a locally issued certficate that the client machine does not trust.&lt;br /&gt;&lt;br /&gt;The following client config change will ignore this particular certficate error:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;settings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;servicePointManager&lt;/span&gt; &lt;span class="attr"&gt;checkCertificateName&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt; &lt;span class="attr"&gt;checkCertificateRevocationList&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;settings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;system.net&gt;&lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Error: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This appears to be an issue with .NET 3.5 SP1 (I say 'appears' as my only reference is a blog entry).&lt;br /&gt;&lt;br /&gt;See this article: &lt;a href="http://msmvps.com/blogs/alvin/archive/2008/11/14/net-3-5-sp1-breaking-change-to-wcf.aspx"&gt;http://msmvps.com/blogs/alvin/archive/2008/11/14/net-3-5-sp1-breaking-change-to-wcf.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The following client configuration change (for each endpoint) resolves this:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;client&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;=... &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;identity&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;servicePrincipalName&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="spn"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;identity&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;client&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Note that the value of servicePrincipalName is not important.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Error: This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This error occurs when there are multiple entries for the Website Identification - it tries to create multiple service base addresses for each endpoint.&lt;br /&gt;&lt;br /&gt;You can specify a filter in the server configuration to resolve this.&lt;br /&gt;&lt;br /&gt;Here is an example:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceHostingEnvironment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;baseAddressPrefixFilters&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;prefix&lt;/span&gt;&lt;span class="kwrd"&gt;="http://tstmachine:80"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;baseAddressPrefixFilters&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;serviceHostingEnvironment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/system.net&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-3510297839354943975?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/3510297839354943975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=3510297839354943975' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3510297839354943975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3510297839354943975'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2009/07/wcf-security-issues-with-iis.html' title='WCF Security Issues With IIS'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-4712539092969188350</id><published>2009-01-22T15:50:00.003+08:00</published><updated>2009-01-22T15:57:11.432+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><title type='text'>Access Violations, Interop and VS2008 SP1</title><content type='html'>After installing SP1 for VS2008 the other day, one of our programs stopped working. In fact, it came up with an AccessViolationException:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;System.AccessViolationException: Attempted to read or write protected&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;memory. This is often an indication that other memory is corrupt.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;    at VariantClear(tagVARIANT* pvarg)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;    at&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:courier new;" &gt;    at ...etc...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was a surprise, because it ran fine before. Or, at least, that is what we thought.&lt;br /&gt;&lt;br /&gt;An examination of the code revealed the exception was being thrown in a foreach() statement. Odd, but the foreach() statement was looping on a COM Interop collection. I've done a little Outlook Add-In development and one thing I've learnt about COM Interop is that it doesn't handle memory the way you would think .NET handles it.&lt;br /&gt;&lt;br /&gt;Basically, there are two thing you need to do:&lt;br /&gt;1) Do NOT use foreach() - these are bad, use for(;;)&lt;br /&gt;2) Be very careful about releasing memory for references to COM objects behind Interop interfaces&lt;br /&gt;&lt;br /&gt;There is a great article regarding this here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/mstehle/archive/2007/12/07/oom-net-part-2-outlook-item-leaks.aspx"&gt;OOM.NET: Part 2 - Outlook Item Leaks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you do any Interop work, you really should read and understand it.&lt;br /&gt;&lt;br /&gt;Back to the code that failed:&lt;br /&gt;&lt;pre class="csharpcode"&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ColIsForeignKey(Table t, Column col)&lt;br /&gt;   {&lt;br /&gt;     &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Key key &lt;span class="kwrd"&gt;in&lt;/span&gt; t.Keys)&lt;br /&gt;     {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (key.Type != SQLDMO_KEY_TYPE.SQLDMOKey_Foreign) &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;br /&gt;       &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; keyCol &lt;span class="kwrd"&gt;in&lt;/span&gt; key.KeyColumns)&lt;br /&gt;       {&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (keyCol.ToLower() == col.Name.ToLower())&lt;br /&gt;         {&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;         }&lt;br /&gt;       }&lt;br /&gt;     }&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now here is the code modified:&lt;br /&gt;&lt;pre class="csharpcode"&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ColIsForeignKey(Table t, Column col)&lt;br /&gt;   {&lt;br /&gt;     SQLDMO.Keys keys = t.Keys;&lt;br /&gt;     &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;     {&lt;br /&gt;       &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 1; i &amp;lt;= keys.Count; i++)&lt;br /&gt;       {&lt;br /&gt;         Key key = keys.Item(i);&lt;br /&gt;         &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;         {&lt;br /&gt;           &lt;span class="kwrd"&gt;if&lt;/span&gt; (key.Type != SQLDMO_KEY_TYPE.SQLDMOKey_Foreign) &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;           Names columns = key.KeyColumns;&lt;br /&gt;           &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;           {&lt;br /&gt;             &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = 1; j &amp;lt;= columns.Count; j++)&lt;br /&gt;             {&lt;br /&gt;               &lt;span class="kwrd"&gt;string&lt;/span&gt; keyCol = columns.Item(j);&lt;br /&gt;               &lt;span class="kwrd"&gt;if&lt;/span&gt; (keyCol.ToLower() == col.Name.ToLower())&lt;br /&gt;               {&lt;br /&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;               }&lt;br /&gt;             }&lt;br /&gt;           }&lt;br /&gt;           &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;           {&lt;br /&gt;             Marshal.ReleaseComObject(columns);&lt;br /&gt;             columns = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;           }&lt;br /&gt;         }&lt;br /&gt;         &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;         {&lt;br /&gt;           Marshal.ReleaseComObject(key);&lt;br /&gt;           key = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;         }&lt;br /&gt;       }&lt;br /&gt;     }&lt;br /&gt;     &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;     {&lt;br /&gt;       Marshal.ReleaseComObject(keys);&lt;br /&gt;       keys = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;     }&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It looks a lot uglier, but you can be sure you're not keeping any nasty&lt;br /&gt;references around the place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-4712539092969188350?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/4712539092969188350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=4712539092969188350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4712539092969188350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4712539092969188350'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2009/01/access-violations-interop-and-vs2008.html' title='Access Violations, Interop and VS2008 SP1'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-11080044952801964</id><published>2008-10-10T14:09:00.005+08:00</published><updated>2008-10-10T14:24:30.501+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><title type='text'>VSTO, Memory Leaks &amp; Reference Management</title><content type='html'>Developing Add-ins for Office calls for some careful handling of references, particularly with references to objects that have an underlying COM reference. &lt;br /&gt;&lt;br /&gt;My previous blog entry &lt;a href="http://adriandev.blogspot.com/2008/01/listening-to-calendar-events-with.html"&gt;Listening to Calendar Events with Outlook 2007 and VSTO&lt;/a&gt; talked about listening to Appointment events, but my code didn't handle references very well. This left some references to Outlook objects hanging and Outlook was showing values that were old.&lt;br /&gt;&lt;br /&gt;I've since update this with some better handling of these references. In particular, the explicit releasing of COM objects via the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Marshal.ReleaseComObject()&lt;/span&gt; method.&lt;br /&gt;&lt;br /&gt;More Reading:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb623945.aspx"&gt;Systematically Releasing Objects&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/mstehle/archive/2007/12/07/oom-net-part-2-outlook-item-leaks.aspx"&gt;OOM.NET: Part 2 - Outlook Item Leaks&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-11080044952801964?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/11080044952801964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=11080044952801964' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/11080044952801964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/11080044952801964'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/10/vsto-memory-leaks-reference-management.html' title='VSTO, Memory Leaks &amp; Reference Management'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-5484604108523736370</id><published>2008-09-05T17:36:00.004+08:00</published><updated>2008-09-17T10:38:38.341+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><title type='text'>Visual Studio Using Huge Amounts of Memory</title><content type='html'>Lately I have been working on a solution with 33 projects on Visual Studio 2008.&lt;br /&gt;&lt;br /&gt;Yeah, I know. That's a lot.&lt;br /&gt;&lt;br /&gt;A lot of them were test projects and it is &lt;a href="http://www.codeplex.com/smartclient"&gt;SCSF&lt;/a&gt;-based, so that is okay, but Visual Studio was chewing up loads of memory. I mean serious amounts, towards the 2GB limit. At this point, my hard disk would thrash at the smallest use of the IDE and be unusable for minutes on end.&lt;br /&gt;&lt;br /&gt;Someone put me on to a &lt;a href="http://www.jetbrains.net/confluence/display/ReSharper/OutOfMemoryException+Fix"&gt;tool from JetBrains&lt;/a&gt;, the guys that did ReSharper - it is supposed to change the way memory is allocated. One of the guys on our project who is using this tool is now using a lot less memory, but whilst mine is better than it was, it still aint that great.&lt;br /&gt;&lt;br /&gt;So it may help.&lt;br /&gt;&lt;br /&gt;Another option is to add &lt;span style="font-family:courier new;"&gt;/3GB /USERVA=3030&lt;/span&gt; to the &lt;span style="font-family:courier new;"&gt;boot.ini&lt;/span&gt; file. Visual Studio is already large address aware (I think), so it should allow more VM use for the &lt;span style="font-family:courier new;"&gt;devenv.exe&lt;/span&gt; process.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 0, 0);"&gt;Update:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;One of the biggest causes of this was DevExpress Refactor! Pro. I'm normally a big fan of this add-in, but uninstalling it saved me enormous amounts of memory. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-5484604108523736370?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/5484604108523736370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=5484604108523736370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5484604108523736370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5484604108523736370'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/09/visual-studio-using-huge-amounts-of.html' title='Visual Studio Using Huge Amounts of Memory'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-136020478853491815</id><published>2008-07-31T13:41:00.003+08:00</published><updated>2008-07-31T13:46:57.411+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Build'/><title type='text'>Including Setup Projects in Team Build</title><content type='html'>Setup (Deployment) projects are not supported by Team Build out of the box. You have to add&lt;br /&gt;additional steps to the &lt;span style="font-weight: bold; font-style: italic;"&gt;TFSBuild.proj &lt;/span&gt;file to build the setup project and copy the files to the output directory.&lt;br /&gt;&lt;br /&gt;The following MSDN article describes this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms404859.aspx"&gt;Walkthrough: Configuring Team Build to Build a Visual Studio Setup Project&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-136020478853491815?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/136020478853491815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=136020478853491815' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/136020478853491815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/136020478853491815'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/07/including-setup-projects-in-team-build.html' title='Including Setup Projects in Team Build'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6983584426576566647</id><published>2008-06-26T09:06:00.003+08:00</published><updated>2008-06-26T09:14:05.178+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><title type='text'>Microsoft Office Developer Show Episode 4 (Harry Miller)</title><content type='html'>Its not everyday you get mentioned in an MSDN video blog:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/vsto/archive/2008/06/11/microsoft-office-developer-show-episode-4-harry-miller.aspx"&gt;http://blogs.msdn.com/vsto/archive/2008/06/11/microsoft-office-developer-show-episode-4-harry-miller.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6983584426576566647?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6983584426576566647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6983584426576566647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6983584426576566647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6983584426576566647'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/06/microsoft-office-developer-show-episode.html' title='Microsoft Office Developer Show Episode 4 (Harry Miller)'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6631539379712618490</id><published>2008-03-31T14:45:00.003+08:00</published><updated>2008-03-31T14:49:58.578+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><title type='text'>PowerCommands for Visual Studio 2008</title><content type='html'>This extremely handy set of extensions for Visual Studio 2008 provides extra functionality to various parts of the IDE.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.msdn.microsoft.com/PowerCommands"&gt;PowerCommands for Visual Studio 2008&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Personally, I think these are the sort of things that should have been provided out of the box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6631539379712618490?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6631539379712618490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6631539379712618490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6631539379712618490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6631539379712618490'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/03/powercommands-for-visual-studio-2008.html' title='PowerCommands for Visual Studio 2008'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-2089159077845766341</id><published>2008-02-27T16:31:00.002+08:00</published><updated>2008-02-27T16:39:33.491+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='LLBLGEN'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='WCSF'/><title type='text'>ObjectContainerDataSource, FormViews and LLBLGen Entities</title><content type='html'>I've always run into issues with databinding in ASP.NET 2. It is nice and straightfoward with basic examples, but there always seems to be some scenario that causes an event to fire at an unexpected time, stuffing things up.&lt;br /&gt;&lt;br /&gt;I am currently using the &lt;a href="http://www.codeplex.com/websf"&gt;Web Client Software Factory&lt;/a&gt; (WCSF) by &lt;a href="http://msdn2.microsoft.com/en-us/practices/default.aspx"&gt;Microsoft patterns &amp;amp; practices&lt;/a&gt; and one of the little gems in this is the &lt;span style="font-weight: bold;"&gt;ObjectContainerDataSource&lt;/span&gt;. This datasource implements data binding in a way that easily integrates with the &lt;a href="http://en.wikipedia.org/wiki/Model_View_Presenter"&gt;MVP&lt;/a&gt; pattern. That is, the Select/Update/Delete events can be passed on and handled by the Presenter. If you are doing web development and are not aware of the WCSF, it is worth checking out.&lt;br /&gt;&lt;br /&gt;This all seems fine, until I wanted to bind to an &lt;a href="http://www.llblgen.com/defaultgeneric.aspx"&gt;LLBLGen&lt;/a&gt; entity (LLBLGen is an easy-to-use and inexpensive O/R mapper). The LLBLGen entity had a &lt;span style="font-style: italic;"&gt;Timestamp &lt;/span&gt;field on it that was used for optimistic concurrency - it was read-only and the optimistic concurrency checking would ensure that the &lt;span style="font-style: italic;"&gt;Timestamp &lt;/span&gt;field had not changed on the database since the entity was fetched.&lt;br /&gt;&lt;br /&gt;On an Update operation I found the &lt;span style="font-weight: bold;"&gt;ObjectContainerDataSource &lt;/span&gt;was creating a new instance of my entity and updating only the properties that were databound in the FormView on my page. No primary keys, no foreign keys, no timestamp fields; by the time I was trying to handle the Update event in the Presenter, I had an instance that supposedly new, with no relationships. Argh!&lt;br /&gt;&lt;br /&gt;I found some related entries in the &lt;a href="http://www.codeplex.com/websf/Thread/List.aspx"&gt;WCSF Discussions&lt;/a&gt;, but no one had a good solution that suited me and my LLBLGen entity.&lt;br /&gt;&lt;br /&gt;One of the good things about the WCSF is that you get code, and the ObjectContainerDataSource is provided in its own project. I've now made some modifications to it that works the way I believe it should. Basically, instead of creating a new instance of the type you are binding to and updating the bound properties on that, the current instance (that is cached on the &lt;span style="font-weight: bold;"&gt;ObjectContainerDataSource &lt;/span&gt;after the Selecting event is called) is used and its properties are updated with the new databound values. This gives you the state of the entity as it was when you fetched it with the exception of the changes made through databinding. This is the behaviour I would have expected initially.&lt;br /&gt;&lt;br /&gt;Note: to get access to the WCSF source, you'll need to install the source separately after you have installed the WCSF. Default folder is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;C:\Program Files\Microsoft Web Client Factory\Source Code\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, the new ExecuteUpdate method in ObjectContainerDataSourceView.cs looks like this:&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues)&lt;br /&gt;{&lt;br /&gt;Guard.CollectionNotNullNorEmpty(keys, String.Format(CultureInfo.CurrentCulture,&lt;br /&gt;  Properties.Resources.NoKeysSpecified), &lt;span class="str"&gt;"keys"&lt;/span&gt;);&lt;br /&gt;Guard.ArgumentNotNull(values, &lt;span class="str"&gt;"values"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;ObjectContainerDataSourceUpdatingEventArgs updatingEventArgs =&lt;br /&gt;    &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjectContainerDataSourceUpdatingEventArgs(DictionaryHelper.GetReadOnlyDictionary(keys),&lt;br /&gt;    values, oldValues);&lt;br /&gt;OnUpdating(updatingEventArgs);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (updatingEventArgs.Cancel)&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;&lt;br /&gt;&lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// -------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// This section has been modified to keep the old instance and&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// update the appropriate fields on it that changed through&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// databinding. If no old instance found, a new instance is&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// created.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; rowsAffected;&lt;br /&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt; newInstance;&lt;br /&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt; oldInstance = FindInstance(keys);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (oldInstance != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;  TypeDescriptionHelper.BuildInstance(values, oldInstance);&lt;br /&gt;  rowsAffected = 1;&lt;br /&gt;  newInstance = oldInstance;&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;  newInstance = CreateInstance();&lt;br /&gt;  TypeDescriptionHelper.BuildInstance(keys, newInstance);&lt;br /&gt;  TypeDescriptionHelper.BuildInstance(values, newInstance);&lt;br /&gt;  rowsAffected = 0;&lt;br /&gt;}&lt;br /&gt;&lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// -------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;OnDataSourceViewChanged(EventArgs.Empty);&lt;br /&gt;&lt;br /&gt;ObjectContainerDataSourceStatusEventArgs updatedEventArgs =&lt;br /&gt;  &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjectContainerDataSourceStatusEventArgs(newInstance, rowsAffected);&lt;br /&gt;OnUpdated(updatedEventArgs);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; rowsAffected;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The Delete operation is affected in a similar manner, so it has also been updated:&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ExecuteDelete(IDictionary keys, IDictionary oldValues)&lt;br /&gt;{&lt;br /&gt;Guard.CollectionNotNullNorEmpty(keys, String.Format(CultureInfo.CurrentCulture,&lt;br /&gt;  Properties.Resources.NoKeysSpecified), &lt;span class="str"&gt;"keys"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;ObjectContainerDataSourceDeletingEventArgs deletingEventArgs =&lt;br /&gt;    &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjectContainerDataSourceDeletingEventArgs(DictionaryHelper.GetReadOnlyDictionary(keys),&lt;br /&gt;    oldValues);&lt;br /&gt;OnDeleting(deletingEventArgs);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (deletingEventArgs.Cancel)&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; rowsAffected;&lt;br /&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt; instance = FindInstance(keys);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (instance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    rowsAffected = 0;&lt;br /&gt;  &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// -------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// This section has been modified to only create a new instance&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// if an old one cannot be found. Moved up from below this if()&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// statement.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;  instance = CreateInstance();&lt;br /&gt;  &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// -------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Data.Remove(instance);&lt;br /&gt;    rowsAffected = 1;&lt;br /&gt;}&lt;br /&gt;TypeDescriptionHelper.BuildInstance(oldValues, instance);&lt;br /&gt;TypeDescriptionHelper.BuildInstance(keys, instance);&lt;br /&gt;OnDataSourceViewChanged(EventArgs.Empty);&lt;br /&gt;&lt;br /&gt;ObjectContainerDataSourceStatusEventArgs deletedEventArgs =&lt;br /&gt;  &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjectContainerDataSourceStatusEventArgs(instance, rowsAffected);&lt;br /&gt;OnDeleted(deletedEventArgs);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; rowsAffected;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;These changes should work with any class, not just LLBLGen entities. For me, retaining the &lt;span style="font-style: italic;"&gt;Timestamp &lt;/span&gt;value was the most important (for optimistic concurrency as I mentioned earlier), and there is no way to set that externally. I am going to go out on a limb here and say that this probably applies to most O/R mappers.&lt;br /&gt;&lt;br /&gt;I'd be glad to here from anyone who has had similar issues or has found a better solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-2089159077845766341?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/2089159077845766341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=2089159077845766341' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2089159077845766341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2089159077845766341'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/02/objectcontainerdatasource-formviews-and.html' title='ObjectContainerDataSource, FormViews and LLBLGen Entities'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-5614965033482898460</id><published>2008-01-30T13:31:00.000+08:00</published><updated>2008-01-30T13:44:08.075+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>Interactive Application Architecture Patterns: MVC, MVP &amp; PAC</title><content type='html'>Found a great article on the comparisons between &lt;strong&gt;Model-View-Controller (MVC)&lt;/strong&gt;, &lt;strong&gt;Model-View-Presenter (MVP)&lt;/strong&gt;, and &lt;strong&gt;Presentation-Abstraction-Control&lt;/strong&gt; &lt;span style="font-weight: bold;"&gt;(PAC)&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ctrl-shift-b.blogspot.com/2007/08/interactive-application-architecture.html"&gt;Interactive Application Architecture Patterns&lt;/a&gt; by Derek Greer&lt;br /&gt;&lt;br /&gt;Particularly useful (for me) is the descriptions of the pattern variations used by the Microsoft Patterns &amp;amp; Practices software factories (i.e.: Smart Client Software Factory and Web Client Software Factory).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-5614965033482898460?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/5614965033482898460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=5614965033482898460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5614965033482898460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5614965033482898460'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/01/interactive-application-architecture.html' title='Interactive Application Architecture Patterns: MVC, MVP &amp; PAC'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-888246097976308308</id><published>2008-01-21T13:23:00.001+08:00</published><updated>2008-09-03T17:56:43.579+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook 2007'/><title type='text'>Outlook 2007: How to determine if you are the owner of an Appointment</title><content type='html'>There doesn't appear to be an easy way to find out if the current user is the owner of an Appointment. Maybe I've something extremely simple, but I just couldn't find that property called &lt;span style="font-style: italic;"&gt;IsOwner&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I basically want to prevent functionality from being available if the user has opened an Appointment that isn't in one of their own calendars (ie: readonly and from someone elses calendar). After looking through the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.office.interop.outlook.mapifolder.store.aspx"&gt;AppointmentItem&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.office.interop.outlook.mapifolder.aspx"&gt;MAPIFolder&lt;/a&gt; properties, I finally found something that was useful: &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.office.interop.outlook.mapifolder.store.aspx"&gt;MAPIFolder.Store&lt;/a&gt;. This property returns a Store object except when the Folder is a shared folder (ie: someone elses). Cool.&lt;br /&gt;&lt;br /&gt;So, I've now created my &lt;span style="font-style: italic;"&gt;IsOwner &lt;/span&gt;&lt;span style=""&gt;method&lt;/span&gt;:&lt;br /&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsOwner(AppointmentItem anAppointment)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (anAppointment.Parent &lt;span class="kwrd"&gt;is&lt;/span&gt; MAPIFolder)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// A Store of null indicates a shared folder (ie: not the current user's).&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        result = (((MAPIFolder)anAppointment.Parent).Store != &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; result;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This, of course, makes the assumption that if the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;is not in a shared folder, it is in a folder that is owner by the current user. I'll need to confirm this, but for now it allows me to move forward.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-888246097976308308?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/888246097976308308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=888246097976308308' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/888246097976308308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/888246097976308308'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/01/outlook-2007-how-to-determine-if-you.html' title='Outlook 2007: How to determine if you are the owner of an Appointment'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-1480705763085485969</id><published>2008-01-11T12:14:00.002+08:00</published><updated>2008-10-15T08:15:53.353+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook 2007'/><title type='text'>Listening to Calendar Events with Outlook 2007 and VSTO</title><content type='html'>I've recently being trying to listen to events from a user's calendars so that I can track when appointments are added, removed and modified, and ran into a couple of problems.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Problem 1: Events intermittently stop firing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I was listening to events on the &lt;span style="font-style: italic;"&gt;MAPIFolder &lt;/span&gt;object and the Calendar's &lt;span style="font-style: italic;"&gt;Items &lt;/span&gt;collection and they would work for a while and at some point would stop firing.&lt;br /&gt;&lt;br /&gt;I eventually traced this down to what I believe is a COM reference counting issue. I wasn't storing a reference to these objects, so I guess there was no implicit AddRef by the interop library. As such, there was no need for the runtime to keep the object around.&lt;br /&gt;&lt;br /&gt;Hanging on to these references appears to be resolving this issue, so I stand by my assumptions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Problem 2: How do we know what has been deleted?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The events I was hooking up to were on the &lt;span style="font-style: italic;"&gt;ItemsEvents_Event &lt;/span&gt;interface off the &lt;span style="font-style: italic;"&gt;MAPIFolder.Items&lt;/span&gt; property. There are thee events on this interface:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li style="font-style: italic;"&gt;ItemAdd&lt;/li&gt;&lt;br /&gt;&lt;li style="font-style: italic;"&gt;ItemChange&lt;/li&gt;&lt;br /&gt;&lt;li style="font-style: italic;"&gt;ItemRemove&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The first two have a single parameter which will be the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;that is either being added or changed. Great! The last one doesn't have any parameters - all it tells you is that an item has been removed, but doesn't give you any indication what has been deleted. Besides that, its actually too late anyway, the item has already been deleted (you cannot cancel it).&lt;br /&gt;&lt;br /&gt;So, I am now hooking up to the &lt;span style="font-style: italic;"&gt;BeforeItemMove &lt;/span&gt;event on the &lt;span style="font-style: italic;"&gt;MAPIFolderEvents_12_Event&lt;/span&gt; interface off the &lt;span style="font-style: italic;"&gt;MAPIFolder &lt;/span&gt;object. This gives me a reference to the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;being moved, the folder in which it is being moved to, and also allows me to cancel it.&lt;br /&gt;&lt;br /&gt;To detect that it is being deleted, just check the folder it is being moved to is &lt;span style="font-style: italic;"&gt;null&lt;/span&gt; (hard-delete such as &lt;span style="font-style: italic;"&gt;Shift-Del&lt;/span&gt;) or the deleted items folder (soft-delete).&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0); font-weight: bold;"&gt;Solution&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have created a class that will monitor a user's default calendar and fires three events:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AppointmentAdded - gives you the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;instance added.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AppointmentModified - gives you the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;instance changed.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AppointmentDeleting - gives you the &lt;span style="font-style: italic;"&gt;AppointmentItem &lt;/span&gt;that is about to be deleted and allows you to cancel the operation if needed.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sample usage:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The following code is for use within the &lt;span style="font-style: italic;"&gt;ThisAddIn &lt;/span&gt;class. It outputs to console when an item is added, modified, or about to be deleted. It also displays a dialog box confirming an item should be deleted.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ThisAddIn_Startup(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, System.EventArgs e)&lt;br /&gt;{&lt;br /&gt; CalendarMonitor monitor = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalendarMonitor(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Application.ActiveExplorer());&lt;br /&gt; monitor.AppointmentAdded +=&lt;br /&gt;     &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt;(monitor_AppointmentAdded);&lt;br /&gt; monitor.AppointmentModified +=&lt;br /&gt;     &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt;(monitor_AppointmentModified);&lt;br /&gt; monitor.AppointmentDeleting +=&lt;br /&gt;     &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;CancelEventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt;(monitor_AppointmentDeleting);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; monitor_AppointmentAdded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs&amp;lt;AppointmentItem&amp;gt; e)&lt;br /&gt;{&lt;br /&gt; Debug.Print(&lt;span class="str"&gt;"Appointment Added: {0}"&lt;/span&gt;, e.Value.GlobalAppointmentID);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; monitor_AppointmentModified(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs&amp;lt;AppointmentItem&amp;gt; e)&lt;br /&gt;{&lt;br /&gt; Debug.Print(&lt;span class="str"&gt;"Appointment Modified: {0}"&lt;/span&gt;, e.Value.GlobalAppointmentID);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; monitor_AppointmentDeleting(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, CancelEventArgs&amp;lt;AppointmentItem&amp;gt; e)&lt;br /&gt;{&lt;br /&gt; Debug.Print(&lt;span class="str"&gt;"Appointment Deleting: {0}"&lt;/span&gt;, e.Value.GlobalAppointmentID);&lt;br /&gt; DialogResult dr = MessageBox.Show(&lt;span class="str"&gt;"Delete appointment?"&lt;/span&gt;, &lt;span class="str"&gt;"Confirm"&lt;/span&gt;,&lt;br /&gt; MessageBoxButtons.YesNo, MessageBoxIcon.Question);&lt;br /&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (dr == DialogResult.No)&lt;br /&gt; {&lt;br /&gt;     e.Cancel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;There are two other classes used: &lt;span style="font-style: italic;"&gt;EventArgs&lt;/span&gt;&lt;t&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;CancelEventArgs&lt;/span&gt;&lt;t&gt;&lt;span style="font-style: italic;"&gt;. &lt;/span&gt;These generics are used by the events to pass strongly typed appointments.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;EventArgs.cs:&lt;/strong&gt;&lt;br /&gt;&lt;/t&gt;&lt;/t&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; OutlookAddIn2&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EventArgs&amp;lt;T&amp;gt; : EventArgs&lt;br /&gt; {&lt;br /&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; T _value;&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; EventArgs(T aValue)&lt;br /&gt;     {&lt;br /&gt;         _value = aValue;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; T Value&lt;br /&gt;     {&lt;br /&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _value; }&lt;br /&gt;         set { _value = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;CancelEventArgs.cs:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; OutlookAddIn2&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CancelEventArgs&amp;lt;T&amp;gt; : EventArgs&amp;lt;T&amp;gt;&lt;br /&gt; {&lt;br /&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _cancel;&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; CancelEventArgs(T aValue)&lt;br /&gt;         : &lt;span class="kwrd"&gt;base&lt;/span&gt;(aValue)&lt;br /&gt;     {&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Cancel&lt;br /&gt;     {&lt;br /&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _cancel; }&lt;br /&gt;         set { _cancel = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;CalendarMonitor.cs:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Office.Interop.Outlook;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Runtime.InteropServices;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; OutlookAddIn2&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CalendarMonitor&lt;br /&gt;  {&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; Explorer _explorer;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; _folderPaths;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;MAPIFolder&amp;gt; _calendarFolders;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;Items&amp;gt; _calendarItems;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; MAPIFolder _deletedItemsFolder;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt; AppointmentAdded;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt; AppointmentModified;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; EventHandler&amp;lt;CancelEventArgs&amp;lt;AppointmentItem&amp;gt;&amp;gt; AppointmentDeleting;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; CalendarMonitor(Explorer anExplorer)&lt;br /&gt;    {&lt;br /&gt;      _folderPaths = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;br /&gt;      _calendarFolders = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;MAPIFolder&amp;gt;();&lt;br /&gt;      _calendarItems = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Items&amp;gt;();&lt;br /&gt;&lt;br /&gt;      _explorer = anExplorer;&lt;br /&gt;      _explorer.BeforeFolderSwitch += &lt;br /&gt;        &lt;span class="kwrd"&gt;new&lt;/span&gt; ExplorerEvents_10_BeforeFolderSwitchEventHandler(Explorer_BeforeFolderSwitch);&lt;br /&gt;&lt;br /&gt;      NameSpace session = _explorer.Session;&lt;br /&gt;      &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;      {&lt;br /&gt;        _deletedItemsFolder = session.GetDefaultFolder(OlDefaultFolders.olFolderDeletedItems);&lt;br /&gt;        HookupDefaultCalendarEvents(session);&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;      {&lt;br /&gt;        Marshal.ReleaseComObject(session);&lt;br /&gt;        session = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HookupDefaultCalendarEvents(NameSpace aSession)&lt;br /&gt;    {&lt;br /&gt;      MAPIFolder folder = aSession.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (folder != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          HookupCalendarEvents(folder);&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          Marshal.ReleaseComObject(folder);&lt;br /&gt;          folder = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Explorer_BeforeFolderSwitch(&lt;span class="kwrd"&gt;object&lt;/span&gt; aNewFolder, &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Cancel)&lt;br /&gt;    {&lt;br /&gt;      MAPIFolder folder = (aNewFolder &lt;span class="kwrd"&gt;as&lt;/span&gt; MAPIFolder);&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;// Hookup events to any other Calendar folder opened.&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (folder != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt; (folder.DefaultItemType == OlItemType.olAppointmentItem)&lt;br /&gt;          {&lt;br /&gt;            HookupCalendarEvents(folder);&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          Marshal.ReleaseComObject(folder);&lt;br /&gt;          folder = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HookupCalendarEvents(MAPIFolder aCalendarFolder)&lt;br /&gt;    {&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (aCalendarFolder.DefaultItemType != OlItemType.olAppointmentItem)&lt;br /&gt;      {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException(&lt;span class="str"&gt;"The MAPIFolder must use "&lt;/span&gt; +&lt;br /&gt;          &lt;span class="str"&gt;"AppointmentItems as the default type."&lt;/span&gt;);&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;// Ignore other user's calendars.&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; ((_folderPaths.Contains(aCalendarFolder.FolderPath) == &lt;span class="kwrd"&gt;false&lt;/span&gt;) &lt;br /&gt;        &amp;amp;&amp;amp; (IsUsersCalendar(aCalendarFolder)))&lt;br /&gt;      {&lt;br /&gt;        Items items = aCalendarFolder.Items;&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// Store folder path to prevent double ups on our listeners.&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        _folderPaths.Add(aCalendarFolder.FolderPath);&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// Store a reference to the folder and to the items collection so that it remains alive for&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// as long as we want. This keeps the ref count up on the underlying COM object and prevents&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// it from being intermittently released (then the events don't get fired).&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        _calendarFolders.Add(aCalendarFolder);&lt;br /&gt;        _calendarItems.Add(items);&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// Add listeners for the events we need.&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;        ((MAPIFolderEvents_12_Event)aCalendarFolder).BeforeItemMove += &lt;br /&gt;          &lt;span class="kwrd"&gt;new&lt;/span&gt; MAPIFolderEvents_12_BeforeItemMoveEventHandler(Calendar_BeforeItemMove);&lt;br /&gt;        items.ItemChange += &lt;span class="kwrd"&gt;new&lt;/span&gt; ItemsEvents_ItemChangeEventHandler(CalendarItems_ItemChange);&lt;br /&gt;        items.ItemAdd += &lt;span class="kwrd"&gt;new&lt;/span&gt; ItemsEvents_ItemAddEventHandler(CalendarItems_ItemAdd);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalendarItems_ItemAdd(&lt;span class="kwrd"&gt;object&lt;/span&gt; anItem)&lt;br /&gt;    {&lt;br /&gt;      AppointmentItem appointment = (anItem &lt;span class="kwrd"&gt;as&lt;/span&gt; AppointmentItem);&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (appointment != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentAdded != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;          {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentAdded(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; EventArgs&amp;lt;AppointmentItem&amp;gt;(appointment));&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          Marshal.ReleaseComObject(appointment);&lt;br /&gt;          appointment = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalendarItems_ItemChange(&lt;span class="kwrd"&gt;object&lt;/span&gt; anItem)&lt;br /&gt;    {&lt;br /&gt;      AppointmentItem appointment = (anItem &lt;span class="kwrd"&gt;as&lt;/span&gt; AppointmentItem);&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (appointment != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentModified != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;          {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentModified(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; EventArgs&amp;lt;AppointmentItem&amp;gt;(appointment));&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;          Marshal.ReleaseComObject(appointment);&lt;br /&gt;          appointment = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Calendar_BeforeItemMove(&lt;span class="kwrd"&gt;object&lt;/span&gt; anItem, MAPIFolder aMoveToFolder, &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Cancel)&lt;br /&gt;    {&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; ((aMoveToFolder == &lt;span class="kwrd"&gt;null&lt;/span&gt;) || (IsDeletedItemsFolder(aMoveToFolder)))&lt;br /&gt;      {&lt;br /&gt;        AppointmentItem appointment = (anItem &lt;span class="kwrd"&gt;as&lt;/span&gt; AppointmentItem);&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (appointment != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;          &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;          {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentDeleting != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;              &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;              &lt;span class="rem"&gt;// Listeners to the AppointmentDeleting event can cancel the move operation if moving&lt;/span&gt;&lt;br /&gt;              &lt;span class="rem"&gt;// to the deleted items folder.&lt;/span&gt;&lt;br /&gt;              &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;              CancelEventArgs&amp;lt;AppointmentItem&amp;gt; args = &lt;span class="kwrd"&gt;new&lt;/span&gt; CancelEventArgs&amp;lt;AppointmentItem&amp;gt;(appointment);&lt;br /&gt;              &lt;span class="kwrd"&gt;this&lt;/span&gt;.AppointmentDeleting(&lt;span class="kwrd"&gt;this&lt;/span&gt;, args);&lt;br /&gt;              Cancel = args.Cancel;&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;          &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;          {&lt;br /&gt;            Marshal.ReleaseComObject(appointment);&lt;br /&gt;            appointment = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsUsersCalendar(MAPIFolder aFolder)&lt;br /&gt;    {&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;// This is based purely on my observations so far - a better way?&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; (aFolder.Store != &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsDeletedItemsFolder(MAPIFolder aFolder)&lt;br /&gt;    {&lt;br /&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; (aFolder.EntryID == _deletedItemsFolder.EntryID);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-1480705763085485969?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/1480705763085485969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=1480705763085485969' title='53 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/1480705763085485969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/1480705763085485969'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/01/listening-to-calendar-events-with.html' title='Listening to Calendar Events with Outlook 2007 and VSTO'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>53</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-830214127865165554</id><published>2008-01-09T10:03:00.000+08:00</published><updated>2008-01-09T10:07:37.371+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook 2007'/><title type='text'>Maintaining Custom Toolbar Positions in Outlook 2007</title><content type='html'>&lt;span style="color: rgb(255, 0, 0);"&gt;NOTE: This applies to Visual Studio 2008 and Outlook 2007.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are a few articles floating around have examples on saving toolbar position information at the end of a session and restoring that position the next time Outlook is loaded. One at MSDN applies to Visual Studio 2008 and .NET Framework 3.5:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms268891.aspx"&gt;How to: Maintain Position Information for Custom Toolbars between Outlook Sessions&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I tried this code with Outlook 2007 and it throws an exception on shutdown when it tries to save the toolbar position information. Reading the article again, I noticed that it says it applies to Outlook 2003.&lt;br /&gt;&lt;br /&gt;I just assumed that it would work with Outlook 2007, and why would they release an article for Visual Studio 2008 that works with an old version of Outlook?&lt;br /&gt;&lt;br /&gt;The exception that is being thrown when the CommandBar instance is accessed is:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x800A01A8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Look up this HRESULT value and you can see that it means "Object Required".&lt;br /&gt;&lt;br /&gt;To me, this means that the CommandBar has already been cleaned up and is no longer accessible. ThisAddIn_Shutdown is supposedly the first user code to be run before a shutdown occurs, so what do you do?&lt;br /&gt;&lt;br /&gt;I have settled on listening to the Close event of the main Explorer window (the one the CommandBar is added to). This is called before ThisAddIn_Shutdown and the CommandBar is still accessible.&lt;br /&gt;&lt;br /&gt;Example:&lt;pre class="csharpcode"&gt;  ...&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ThisAddIn_Startup(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;      Outlook.Explorer explorer = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Application.ActiveExplorer();&lt;br /&gt;    &lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (explorer != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;          ((ExplorerEvents_10_Event)explorer).Close += &lt;span class="kwrd"&gt;new&lt;/span&gt; ExplorerEvents_10_CloseEventHandler(ThisAddIn_Close);&lt;br /&gt;&lt;br /&gt;          commandBar = explorer.CommandBars.Add(TOOLBARNAME,&lt;br /&gt;              Office.MsoBarPosition.msoBarFloating, &lt;span class="kwrd"&gt;false&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;        &lt;br /&gt;          ...&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ThisAddIn_Close()&lt;br /&gt;  {&lt;br /&gt;      SaveCommandBarSettings();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ...&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-830214127865165554?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/830214127865165554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=830214127865165554' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/830214127865165554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/830214127865165554'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2008/01/maintaining-custom-toolbar-positions-in.html' title='Maintaining Custom Toolbar Positions in Outlook 2007'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-4200499650781939589</id><published>2007-12-28T13:45:00.000+08:00</published><updated>2007-12-28T13:53:16.467+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Standards'/><title type='text'>Coding Standards and Design Guidelines</title><content type='html'>I get a lot of people at work asking me about our coding standards and guidelines. We do have some, but to be perfectly honest, they could be better.&lt;br /&gt;&lt;br /&gt;I like to utilize the &lt;a href="http://blogs.msdn.com/fxcop/"&gt;Code Analysis&lt;/a&gt; feature of the Visual Studio version I am running, and let the compiler help with warnings and errors when rules are broken. Unfortunately this is not available with all versions.&lt;br /&gt;&lt;br /&gt;I also found two very useful articles on MSDN that help a lot with defining standards:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/bb278146.aspx"&gt;Reviewing Managed Code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms229042%28VS.80%29.aspx"&gt;Design Guidelines for Developing Class Libraries&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-4200499650781939589?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/4200499650781939589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=4200499650781939589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4200499650781939589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4200499650781939589'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/12/coding-standards-and-design-guidelines.html' title='Coding Standards and Design Guidelines'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-4352186442318161139</id><published>2007-12-28T13:38:00.000+08:00</published><updated>2007-12-28T13:44:12.780+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Books'/><title type='text'>Development Books</title><content type='html'>A colleague sent me this link to an online book store in Australia that specializes in computer books (development, networking, project management, etc).&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.bookware.com.au/images/bookware_logo_4.gif" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.bookware.com.au/"&gt;http://www.bookware.com.au&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Postage should be a lot cheaper than ordering from Amazon, and the prices are way lower than our local stores in Perth.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-4352186442318161139?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/4352186442318161139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=4352186442318161139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4352186442318161139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4352186442318161139'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/12/development-books.html' title='Development Books'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-929275747801787340</id><published>2007-12-27T13:39:00.000+08:00</published><updated>2008-02-04T09:58:36.607+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Service'/><category scheme='http://www.blogger.com/atom/ns#' term='LLBLGEN'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Optmistic Concurrency withTimestamps, LLBLGen and Web Services</title><content type='html'>Found a great article on how to implement optimistic concurrency with LLBLGEN and SQL Server:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://davidhayden.com/blog/dave/archive/2006/10/24/ConcurrencyTimestampLLBLGenPro.aspx"&gt;Optmistic Concurrency and Timestamps in SQL Server Using LLBLGen Pro O/R Mapper&lt;/a&gt; by &lt;a href="http://www.davidhayden.com/"&gt;David Hayden&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now, I am using XML Web Services and passing entities back and forth, and what I have found is that the &lt;strong&gt;DBValue&lt;/strong&gt; property on each field is NOT serialized! I have not found a better solution as yet, but I am currently just using the field's &lt;strong&gt;CurrentValue&lt;/strong&gt;. So, assuming the timestamp properties used do not get changed on the client, it will work, but this is a problem that will need to be fixed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update: &lt;/span&gt;Looks like there was an issue with the deserialization in version 2.5 (October 25 2007 release). The December release has apparently fixed this issue:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=12436&amp;amp;StartAtMessage=0%F0%90%B7%89"&gt;http://www.llblgen.com/TinyForum/Messages.aspx?...&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Modifications with LLBLGEN 2.5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am inherently lazy, which is a bad thing when it comes to coding, but the solution described by LLBLGEN's help and David Hayden relies on a factory class for each entity. Sure, we should probably modify the templates and create a new factory class for each of our entities, but for what I wanted, that sounded like too much work.&lt;br /&gt;&lt;br /&gt;Now, in LLBLGEN 2.5, all entities are now derived from another generated partial class called &lt;span style="font-weight: bold;"&gt;CommonEntityBase&lt;/span&gt;. And, lets face it, we are probably going to create our timestamp field on every entity and call it the same name (in this case, every entity has a timetamp field called &lt;span style="font-style: italic;"&gt;LastModified&lt;/span&gt;). So, I created a new partial class definition for &lt;span style="font-weight: bold;"&gt;CommonEntityBase &lt;/span&gt;that allows me to get access to the timestamp field I will use for all entities' concurrency control.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CommonEntityBase&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; LAST_MODIFIED_FIELD_NAME = &lt;span class="str"&gt;"LastModified"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IEntityField2 LastModifiedField&lt;br /&gt;{&lt;br /&gt;    get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Fields[LAST_MODIFIED_FIELD_NAME]; }&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This then allows me to create a single factory for concurrency predicate expressions:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EntityConcurrencyFactory : IConcurrencyPredicateFactory&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IPredicateExpression CreatePredicate(ConcurrencyPredicateType predicateTypeToCreate,&lt;br /&gt;  &lt;span class="kwrd"&gt;object&lt;/span&gt; containingEntity)&lt;br /&gt;{&lt;br /&gt;    IPredicateExpression toReturn = &lt;span class="kwrd"&gt;new&lt;/span&gt; PredicateExpression();&lt;br /&gt;    CommonEntityBase entity = (CommonEntityBase)containingEntity;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (predicateTypeToCreate)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; ConcurrencyPredicateType.Delete:&lt;br /&gt;        &lt;span class="kwrd"&gt;case&lt;/span&gt; ConcurrencyPredicateType.Save:&lt;br /&gt;            &lt;span class="rem"&gt;// only for updates&lt;/span&gt;&lt;br /&gt;            toReturn.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; FieldCompareValuePredicate(entity.LastModifiedField,&lt;br /&gt;                &lt;span class="kwrd"&gt;null&lt;/span&gt;, ComparisonOperator.Equal, entity.LastModifiedField.CurrentValue));&lt;br /&gt;            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; toReturn;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Two classes for all entities - sounds good to me. Now, using David's example, there isn't any difference in the code (just every entity uses the same factory):&lt;br /&gt;&lt;pre class="csharpcode"&gt;DataAccessAdapter adapter = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataAccessAdapter(...);&lt;br /&gt;&lt;br /&gt;BlogEntity blog = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlogEntity();&lt;br /&gt;blog.BlogId = 1;&lt;br /&gt;&lt;br /&gt;adapter.FetchEntity(blog);&lt;br /&gt;&lt;br /&gt;blog.Name = &lt;span class="str"&gt;"New Name"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;IPredicateExpression expression = &lt;span class="kwrd"&gt;new&lt;/span&gt; EntityConcurrencyFactory()&lt;br /&gt;.CreatePredicate(ConcurrencyPredicateType.Save, blog);&lt;br /&gt;&lt;br /&gt;adapter.SaveEntity(blog, &lt;span class="kwrd"&gt;true&lt;/span&gt;, expression);&lt;/pre&gt;&lt;br /&gt;You can still change optimistic concurrency strategies easily, but it is easier to apply to all of your entities at once.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-929275747801787340?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/929275747801787340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=929275747801787340' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/929275747801787340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/929275747801787340'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/12/optmistic-concurrency-withtimestamps.html' title='Optmistic Concurrency withTimestamps, LLBLGen and Web Services'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-117321262637725802</id><published>2007-12-27T12:10:00.000+08:00</published><updated>2007-12-28T10:32:24.267+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><title type='text'>Tag Cloud for Blogger</title><content type='html'>I found a neat bit of code to turn your standard tag list into a "cloud". &lt;br /&gt;&lt;br /&gt;This one is okay: &lt;a href="http://www.compender.com/2007/12/simple-tag-cloud.html"&gt;Compender&lt;/a&gt; by Raymond May Jr.&lt;br /&gt;&lt;br /&gt;This one is better (in my opinion) and is the one I am using: &lt;a href="http://phy3blog.googlepages.com/Beta-Blogger-Label-Cloud.html"&gt;New Blogger Tag Cloud / Label Cloud&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-117321262637725802?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/117321262637725802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=117321262637725802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/117321262637725802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/117321262637725802'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/12/tag-cloud-for-blogger.html' title='Tag Cloud for Blogger'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-1692879720615935914</id><published>2007-12-10T14:21:00.000+08:00</published><updated>2007-12-27T11:50:21.109+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RDC'/><title type='text'>Can't Connect to Machine via Remote Desktop</title><content type='html'>I had a machine I could not Remote Desktop (RDC) to. No matter what I did, I got the same error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;The connection was ended because of a network error. Please try connecting to the remote computer again.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the System event log on the machine I was trying to connect to, I found quite a few Error entries with the source &lt;span style="font-weight: bold;"&gt;TermDD&lt;/span&gt;. This described the following error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;The RDP protocol component "DATA ENCRYPTION" detected an error in the protocol stream and has disconnected the client.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After a quick search, I found the following Microsoft KB article that helped me fix the problem:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/323497"&gt;"The RDP Protocol Component "DATA ENCRYPTION" Detected an Error..." error message&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A reboot on the machine and it is now working fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-1692879720615935914?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/1692879720615935914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=1692879720615935914' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/1692879720615935914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/1692879720615935914'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/12/cant-connect-to-machine-via-remote.html' title='Can&apos;t Connect to Machine via Remote Desktop'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-4862519555931735837</id><published>2007-11-30T13:54:00.000+08:00</published><updated>2007-12-27T11:47:53.129+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook 2007'/><title type='text'>Accessing the Current Principal in VSTO Add-In</title><content type='html'>I recently tried to get access to the Current Principal within an Outlook Add-In. Accessing the Identity was returning a blank name and an unauthorised user. Wierd.&lt;br /&gt;&lt;br /&gt;It turns out the the VSTOLoader will load each Add-In into its own AppDomain. As such, you need to set the principal policy explicitly before you access the current principal for the first time.&lt;br /&gt;&lt;br /&gt;Example:&lt;pre class="csharpcode"&gt;AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);&lt;br /&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; userName = Thread.CurrentPrincipal.Identity.Name;&lt;/pre&gt;&lt;br /&gt;As it running within an isolated environment, I am sure there are other issues you need to be aware of.&lt;br /&gt;&lt;br /&gt;See the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.appdomain(VS.90).aspx"&gt;AppDomain Class&lt;/a&gt; in the MSDN Library for more information on application domains.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-4862519555931735837?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/4862519555931735837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=4862519555931735837' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4862519555931735837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/4862519555931735837'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/11/accessing-current-principal-in-vsto-add.html' title='Accessing the Current Principal in VSTO Add-In'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-8308731035720022718</id><published>2007-11-29T14:26:00.000+08:00</published><updated>2007-12-27T11:48:17.298+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook 2007'/><title type='text'>Accessing Custom Resource Mailbox Properties With VSTO</title><content type='html'>In Exchange 2007 you can create custom resource properties to annotate your resources. For example, you may want to create a custom property called Vehicle and add this to all resources that represent vehicles in your Exchange organisation. The TechNet article, &lt;a href="http://technet.microsoft.com/en-us/library/bb124948.aspx"&gt;How to Create or Remove Custom Resource Properties&lt;/a&gt;, describes how this is done.&lt;br /&gt;&lt;br /&gt;Getting access to these custom resource properties via Visual Studio Tools for Office (VSTO) is relatively straight forward, as long as you know exactly what you need to do! The problem is finding this with the documentation and newsgroup postings out there.&lt;br /&gt;&lt;br /&gt;Anyway, access to this type of information is not available via properties on the Outlook Object Model. However, in VSTO 3 (for Outlook 2007), most Outlook objects have a &lt;strong&gt;PropertyAccessor&lt;/strong&gt; object that allows you to get access to ALL the properties on the underlying MAPI object, not just the ones exposed by the COM interface. The &lt;strong&gt;GetProperty&lt;/strong&gt; method takes a string identifying a property on the object and returns the value as an &lt;strong&gt;object&lt;/strong&gt;. This string identifier consists of a namespace and some sort of property tag value. There are several namespaces that can be used, but the one used here is &lt;strong&gt;http://schemas.microsoft.com/mapi/proptag/&lt;/strong&gt;. More information on referencing properties by namespace can be found in the MSDN article outrageously called &lt;a href="http://msdn2.microsoft.com/EN-US/library/bb147567.aspx"&gt;Referencing Properties by Namespace&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Finding out the property tag value is next to impossible looking at the MSDN documentation. They simply don't document it, which I found incredibly frustrating. That is, until I found a copy of &lt;a href="http://www.dimastr.com/outspy/"&gt;Outlook Spy&lt;/a&gt;. This is an excellent tool that allows you to browse the object model and also get access to the MAPI objects, including the elusive property tags!&lt;br /&gt;&lt;br /&gt;Getting back to custom resource properties, I used &lt;strong&gt;Outlook Spy&lt;/strong&gt; to examine one of my vehicle-type recipients. Under the &lt;strong&gt;AddressEntity&lt;/strong&gt; property is a &lt;strong&gt;MAPIObject&lt;/strong&gt;. If you "browse" this property, a window is displayed listing all of the properties of that MAPI object, including the property tag value, the type and its current value. On the right of the window is a field called &lt;strong&gt;DASL&lt;/strong&gt;. This field is the value that you need to pass into the &lt;strong&gt;PropertyAccessor.GetProperty()&lt;/strong&gt; method to extract its value. In my case, the property listing the custom resource properties was using the DASL http://schemas.microsoft.com/mapi/proptag/0x0806101E.&lt;br /&gt;&lt;br /&gt;So, once you have this, the code is simple. The following example assumes you already have a &lt;strong&gt;Recipient&lt;/strong&gt; object which is an &lt;strong&gt;Equipment&lt;/strong&gt; resource with the custom property &lt;strong&gt;Vehicle&lt;/strong&gt;.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsVehicleResource(Recipient aRecipient)&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (aRecipient.Type == (&lt;span class="kwrd"&gt;int&lt;/span&gt;)OlMeetingRecipientType.olResource)&lt;br /&gt; {&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;  {&lt;br /&gt;   &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;// Get resource info property via MAPI property accessor.&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;// NOTE: this will throw an exception if it doesn't exist (ie: not a resource)&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;object&lt;/span&gt; resourceInfo = aRecipient.AddressEntry.PropertyAccessor.GetProperty(&lt;br /&gt;&lt;span class="str"&gt;"http://schemas.microsoft.com/mapi/proptag/0x0806101E"&lt;/span&gt;);&lt;br /&gt;   &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;// Split comma separated info into parts and look for information identifying&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;// the resource as Equipment and Vehicle.&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;string&lt;/span&gt;[] resourceDetails = resourceInfo.ToString().Split(&lt;span class="str"&gt;','&lt;/span&gt;);&lt;br /&gt;   result = (resourceDetails.Contains(&lt;span class="str"&gt;"Equipment"&lt;/span&gt;) &amp;amp;amp;&amp;amp;amp; resourceDetails.Contains(&lt;span class="str"&gt;"Vehicle"&lt;/span&gt;));&lt;br /&gt;  }&lt;br /&gt;  &lt;span class="kwrd"&gt;catch&lt;/span&gt; (System.Exception ex)&lt;br /&gt;  {&lt;br /&gt;   &lt;span class="rem"&gt;// TODO: error handling&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; result;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;And that is it!&lt;br /&gt;&lt;br /&gt;For more information on using the PropertyAccessor object, have a look at the &lt;a href="http://msdn2.microsoft.com/en-us/library/bb147570.aspx"&gt;MSDN documentation online&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-8308731035720022718?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/8308731035720022718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=8308731035720022718' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8308731035720022718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8308731035720022718'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/11/accessing-custom-resource-mailbox.html' title='Accessing Custom Resource Mailbox Properties With VSTO'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-2026724384511130126</id><published>2007-11-27T15:38:00.000+08:00</published><updated>2007-12-27T10:11:24.183+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Service'/><category scheme='http://www.blogger.com/atom/ns#' term='LLBLGEN'/><title type='text'>Using LLBLGEN Generated Classes with Web Services</title><content type='html'>&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;UPDATE: This only applies to version 2.0.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you are using LLBLGEN with Web Services and you want to return entities and views to the client, you should have configured your machine to work according to the LLGBLGEN article titled &lt;strong&gt;Generated code - XML Webservices support&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;This works nicely with Entity Classess, and probably Typed Lists (which I haven't used/tested yet), but there is a problem with Typed Views. If you have a Web Method that returns one of your Typed Views, you are probably getting errors generating the proxy classes, or the type specified in the proxy class that is generated does not match the Typed View in your Web Method!&lt;br /&gt;&lt;br /&gt;There appears to be a bug in the &lt;strong&gt;webServiceHelper.template&lt;/strong&gt; file that is used by the LLBLGEN generator. You can find this file in the following directory:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;C:\Program Files\Solutions Design\LLBLGen Pro v2.0\Templates\SharedTemplates\Net2.x\C#&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Open the file in a text editor and look for the following line in the "TypedView Classes" region:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;return new XmlQualifiedName("&lt;[CurrentTypedListName]&gt;TypedList", namespaceToUse);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Change the above line to:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;return new XmlQualifiedName("&lt;[CurrentTypedViewName]&gt;TypedView", namespaceToUse);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Now instead of having every one of your typed views with an XmlQualifiedName of TypedList, it is actually to the name of the class. Look in WebServiceHelper.cs (or WebServiceHelper.vb) to confirm this change is working.&lt;br /&gt;&lt;br /&gt;I generally find that these changes only affect the proxy generation when the service reference is recreated; updating the reference doesn't always work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-2026724384511130126?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/2026724384511130126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=2026724384511130126' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2026724384511130126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2026724384511130126'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/11/using-llblgen-generated-classes-with.html' title='Using LLBLGEN Generated Classes with Web Services'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-3513353461897774676</id><published>2007-10-17T16:52:00.000+08:00</published><updated>2007-10-17T16:55:01.324+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Documentation'/><category scheme='http://www.blogger.com/atom/ns#' term='Sandcastle'/><title type='text'>Generating Documentation with Sandcastle</title><content type='html'>&lt;p dtid="281474976710660"&gt;The following apps are required to get going with Sandcastle:&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul dtid="281474976710666"&gt;&lt;li dtid="281474976710667"&gt;XP  Service Pack 2 &lt;/li&gt;&lt;li dtid="281474976710668"&gt;.NET 2.0 &lt;/li&gt;&lt;li dtid="281474976710669"&gt;HTML Help Workshop &lt;/li&gt;&lt;li dtid="281474976710670"&gt;Microsoft Sandcastle &lt;/li&gt;&lt;li dtid="281474976710671"&gt;Sandcastle Help File Builder &lt;/li&gt;&lt;/ul&gt;&lt;p dtid="281474976710672"&gt;First, ensure you have HTML Help Workshop by  checking for the existence of the following folder:&lt;/p&gt;&lt;p dtid="281474976710673"&gt;&lt;code dtid="281474976710674"&gt;C:\Program Files\HTML Help  Workshop&lt;/code&gt;&lt;/p&gt;&lt;p dtid="281474976710675"&gt;If it is not there or  does not contain hhc.exe, then download and install it from the following  URL:&lt;/p&gt;&lt;p dtid="281474976710676"&gt;&lt;code dtid="281474976710677"&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp" dtid="281474976710678"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;p dtid="281474976710679"&gt;Microsoft Sandcastle can be found from  here:&lt;/p&gt;&lt;p dtid="281474976710680"&gt;&lt;code dtid="281474976710681"&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=E82EA71D-DA89-42EE-A715-696E3A4873B2&amp;amp;displaylang=en" dtid="281474976710682"&gt;http://www.microsoft.com/downloads/details.aspx?familyid=E82EA71D-DA89-42EE-A715-696E3A4873B2&amp;amp;displaylang=en&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;p dtid="281474976710683"&gt;Sandcastle Help File Builder can be found  here:&lt;/p&gt;&lt;p dtid="281474976710684"&gt;&lt;code dtid="281474976710685"&gt;&lt;a href="http://www.codeplex.com/SHFB" dtid="281474976710686"&gt;http://www.codeplex.com/SHFB&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;&lt;p dtid="281474976710687"&gt;You should also download the Presentation File  Patches from the URL above and extract them into the Sandcastle folder.&lt;/p&gt;&lt;p dtid="281474976710688"&gt;Now you should run &lt;code dtid="281474976710689"&gt;BuildReflectionData.bat&lt;/code&gt; in Sandcastle  root directory to build reflection data for the .NET runtime.&lt;/p&gt;&lt;p dtid="281474976710691"&gt;Now launch  Sandcastle Help File Builder and get going...&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-3513353461897774676?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/3513353461897774676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=3513353461897774676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3513353461897774676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3513353461897774676'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/10/generating-documentation-with.html' title='Generating Documentation with Sandcastle'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-8679473890834101330</id><published>2007-07-25T16:32:00.000+08:00</published><updated>2007-07-25T16:38:53.340+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Free Visual Studio Add-ins</title><content type='html'>Here is an article listing some of the free &lt;a href="http://searchvb.techtarget.com/originalContent/0,289142,sid8_gci1262570,00.html"&gt;Visual Studio Add-ins&lt;/a&gt; available.&lt;br /&gt;&lt;br /&gt;I find &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector for .NET&lt;/a&gt; extremely valuable, particularly when working with client's (somewhat untested) libraries!&lt;br /&gt;&lt;br /&gt;Also check out &lt;a href="http://weblogs.asp.net/gmilano/archive/2005/11/10/430240.aspx"&gt;CoolCommands&lt;/a&gt; and if you are using VB.NET get &lt;a href="http://www.devexpress.com/Products/NET/IDETools/VBRefactor/"&gt;Refactor! for VB.NET &lt;/a&gt;- it provides the refactoring functionality that C# provides out of the box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-8679473890834101330?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/8679473890834101330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=8679473890834101330' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8679473890834101330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8679473890834101330'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/07/free-visual-studio-add-ins.html' title='Free Visual Studio Add-ins'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6225341692568321014</id><published>2007-02-19T13:42:00.000+08:00</published><updated>2007-02-19T13:58:28.386+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ClickOnce'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>ClickOnce Deployment and Expired Temporary (Test) Certificates</title><content type='html'>I have recently been helping on a maintenance project for a new client, and we ran into an issue for our first deployment.&lt;br /&gt;&lt;br /&gt;Basically, a test certificate had been used when the application was first deployed using ClickOnce deployment and had expired in December last year.  Publishing through Visual Studio would not work due to the expired certificate and you get the following error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;The deployment identity does not match the subscription.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Crap! What now?&lt;br /&gt;&lt;br /&gt;I found a Microsoft KB article related to the issue with nice concise title of &lt;a href="http://support.microsoft.com/Default.aspx?kbid=925521"&gt;"You receive an error message when you try to update a Visual Studio 2005 ClickOnce application after the certificate that was used to sign the installation expires".&lt;/a&gt; This gives some code that helps you renew a test certificate.&lt;br /&gt;&lt;br /&gt;Great! Then I found someone who'd actually gone to the effort of making the code a little bit more robust and works with more certificates. You can find the project source and executable on Cliff Stanford's site &lt;a href="http://www.may.be/renewcert/"&gt;RenewCert - Working Version&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This allows you to create a new certificate with the same key and extended expiry date. Publishing of subsequent updates should now work like a charm.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6225341692568321014?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6225341692568321014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6225341692568321014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6225341692568321014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6225341692568321014'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/02/clickonce-deployment-and-expired.html' title='ClickOnce Deployment and Expired Temporary (Test) Certificates'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6762633246444221262</id><published>2007-02-14T13:29:00.000+08:00</published><updated>2007-02-14T14:05:41.631+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Getting the Version of a .NET Assembly at Runtime</title><content type='html'>The versions of all .NET assemblies are commonly located in the AssemblyInfo.cs file in each project. This can be extracted via code for use during execution and can easily be used to display version information on an About Box, for example.&lt;br /&gt;&lt;br /&gt;Getting the version as a string is as straightfoward as the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; version = Assembly.GetExecutingAssembly().GetName().Version.ToString();&lt;/pre&gt;&lt;br /&gt;The GetExecutingAssembly() method returns the Assembly of the executable that the code is running in. Other methods allow you to get the calling assembly or the Assembly containing a particular Type.&lt;br /&gt;&lt;br /&gt;The GetName() method call returns an &lt;a href="http://msdn2.microsoft.com/en-us/library/system.reflection.assemblyname.aspx"&gt;AssemblyName&lt;/a&gt; object, which provides information the assembly's unique identity, including the version, version compatibility, culture information and full name.&lt;br /&gt;&lt;br /&gt;The Version property returns a &lt;a href="http://msdn2.microsoft.com/en-us/system.version.aspx"&gt;Version&lt;/a&gt; object, providing access to the individual elements of the version (major, minor, revision, etc). It also provides overloads for comparison with other Version objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6762633246444221262?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6762633246444221262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6762633246444221262' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6762633246444221262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6762633246444221262'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/02/getting-version-of-net-assembly-at.html' title='Getting the Version of a .NET Assembly at Runtime'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-3106857991480641065</id><published>2007-01-17T14:19:00.000+08:00</published><updated>2007-01-17T14:31:34.585+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><title type='text'>Identifying Memory Leaks in .NET Apps</title><content type='html'>Applies to .NET 1.0, 1.1 and 2.0.&lt;br /&gt;&lt;br /&gt;This information has been extracted from the MSDN article, &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/01/ManagedLeaks/default.aspx"&gt;Identify and Prevent Memory Leaks in Managed Code&lt;/a&gt;, by &lt;a href="http://www.jameskovacs.com/blog/"&gt;James Kovacs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#990000;"&gt;Useful PerfMon Counters&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Process/[Private Bytes]&lt;/strong&gt;&lt;br /&gt;Reports all memory that is exclusively allocated for a process and can't be shared with other processes on the system.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;.NET CLR Memory/[# Bytes in All Heaps]&lt;/strong&gt;&lt;br /&gt;Reports the combined total size of the Gen0, Gen1, Gen2 and large object heaps.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;.NET LocksAndThreads/[# of current logical Threads]&lt;/strong&gt;&lt;br /&gt;Reports the number of logical threads in an AppDomain.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#990000;"&gt;Interpreting the Results&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The following problems may be identified:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Thread Stack Leaks -&lt;strong&gt; &lt;em&gt;[# of current logical Threads]&lt;/em&gt;&lt;/strong&gt; increases unexpectedly&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Unmanaged Memory Leaks - &lt;em&gt;[&lt;strong&gt;Private Bytes]&lt;/strong&gt;&lt;/em&gt; increases but &lt;em&gt;&lt;strong&gt;[# Bytes in All Heaps]&lt;/strong&gt;&lt;/em&gt; remains stable&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Managed Memory "Leaks" - &lt;em&gt;&lt;strong&gt;[Private Bytes]&lt;/strong&gt;&lt;/em&gt; increases AND &lt;em&gt;&lt;strong&gt;[# Bytes in All Heaps]&lt;/strong&gt;&lt;/em&gt; increases&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;For detailed explanations on these, please read the MSDN article, &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/01/ManagedLeaks/default.aspx"&gt;Identify and Prevent Memory Leaks in Managed Code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-3106857991480641065?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/3106857991480641065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=3106857991480641065' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3106857991480641065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/3106857991480641065'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/01/identifying-memory-leaks-in-net-apps.html' title='Identifying Memory Leaks in .NET Apps'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-8243805053537327839</id><published>2007-01-03T09:15:00.000+08:00</published><updated>2007-01-03T09:19:46.251+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQl Server 2005 Express'/><title type='text'>Error Installing SQL Server 2005 Express</title><content type='html'>After trying to install SQL Server 2005 Express Edition on my machine, I got through almost the entire install before it failed with an error message:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Argh!&lt;br /&gt;&lt;br /&gt;If you get this, you should be able to do a quick fix and then click on Retry. Unlike me, who clicked on Cancel and then had to go through almost the entire setup process again!&lt;br /&gt;&lt;br /&gt;Anyway, if you look in your log file, you should see something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;Error Code: 1067&lt;br /&gt;MSI (s) (4C!44) [09:42:09:089]: Product: Microsoft SQL Server 2005 Express Edition -- Error 29503. The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."&lt;br /&gt;The error is  (1067) The process terminated unexpectedly.&lt;br /&gt;.&lt;br /&gt;&lt;br /&gt;Error 29503. The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."&lt;br /&gt;The error is  (1067) The process terminated unexpectedly.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Microsoft has a KB article about a fix for a error on install, but when I read the expected symptoms, it didn't quite look like it was a match. However, following the workaround in this KB article will fix your problem. Well, it fixed mine anyway.&lt;br /&gt;&lt;br /&gt;The article can be found here:&lt;br /&gt;&lt;a href="http://support.microsoft.com/default.aspx/kb/920114"&gt;http://support.microsoft.com/default.aspx/kb/920114&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note&lt;/strong&gt;: the article talks about a Protect folder that requires changes to its permissions, but this folder did not exist on my machine. Creating the folder first and then applying the permissions worked like a treat.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-8243805053537327839?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/8243805053537327839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=8243805053537327839' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8243805053537327839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/8243805053537327839'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2007/01/error-installing-sql-server-2005.html' title='Error Installing SQL Server 2005 Express'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-6497221552080227573</id><published>2006-12-29T07:45:00.000+08:00</published><updated>2007-12-27T11:44:28.233+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='WSS 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Parts'/><title type='text'>A Simple Web Part for Windows Sharepoint Services (WSS) 3.0</title><content type='html'>There doesn't seem to be a lot of information out there on getting started with developing Web Parts for Windows Sharepoint Services 3.0 (WSS). So this is a quick example on developing and deploying a very basic Web Part for use in WSS.&lt;br /&gt;&lt;br /&gt;My disclaimer: this may or may not be the best way to do it. As I said, not a lot of documentation around, but I've managed to get this working successfully, so it can at least be used as a starting point.&lt;br /&gt;&lt;br /&gt;I will assume you have WSS 3.0 installed and running (and working!) on a Windows Server 2003 machine.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;Visual Studio 2005 Extensions for WSS 3.0&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Currently, this is only available as a Community Technology Preview (CTP), and unfortunately will only work on Windows Server 2003. Lets hope Microsoft will do something about this before the release.&lt;br /&gt;&lt;br /&gt;In the meantime, you'll have to install Visual Studio on a Windows Server 2003 machine and develop on that. You may be able to install it on Windows XP, but it relies on the existence of the Microsoft.Sharepoint assembly and you'll only find that on your WSS 3.0 box.&lt;br /&gt;&lt;br /&gt;Download the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=19f21e5e-b715-4f0c-b959-8c6dcbdc1057&amp;amp;displaylang=en"&gt;WSS 3.0 Visual Studio 2005 Extensions&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It is not needed for this example, but the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=05e0dd12-8394-402b-8936-a07fe8afaffd&amp;amp;displaylang=en"&gt;WSS 3.0 Software Development Kit (SDK)&lt;/a&gt; is quite useful, if a bit lacking in parts.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;Creating a Web Part Project&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Run Visual Studio 2005 and bring up the New Project dialog. You should see another project type entry under Visual C# (and Visual Basic) called SharePoint. Selecting this brings up a list of SharePoint templates. Choose the Web Part template and click OK.&lt;br /&gt;&lt;br /&gt;You should be looking at a very simple class:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Runtime.InteropServices;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.UI;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.UI.WebControls.WebParts;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml.Serialization;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.SharePoint;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.SharePoint.WebControls;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.SharePoint.WebPartPages;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; WebPartTest&lt;br /&gt;{&lt;br /&gt; [Guid(&lt;span class="str"&gt;""&lt;/span&gt;)]&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebPart1 : System.Web.UI.WebControls.WebParts.WebPart&lt;br /&gt; {&lt;br /&gt;   &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Render(HtmlTextWriter writer)&lt;br /&gt;   {&lt;br /&gt;     &lt;span class="rem"&gt;// TODO: add custom rendering code here.&lt;/span&gt;&lt;br /&gt;     &lt;span class="rem"&gt;// writer.Write("Output HTML");&lt;/span&gt;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For this example, we want to change the base class to Microsoft.SharePoint.WebPartPages.WebPart (Supposedly you can use the standard .NET WebPart, but I was unable to get this to install). Also, lets uncomment the TODO so that we have some display for the Web Part.&lt;br /&gt;&lt;br /&gt;Great, it compiles... now what?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;Deploying the Web Part&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;There a few things required for deployment:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Add a manifest file&lt;/li&gt;&lt;li&gt;Add a web part config file&lt;/li&gt;&lt;li&gt;Add a CAB setup project&lt;/li&gt;&lt;li&gt;Use the command line to install into WSS&lt;/li&gt;&lt;/ul&gt;The Visual Studio extensions do give you a few extra menu options under build, including a Deploy menu option - this is all well and good for the machine you are developing on, but this doesn't help when you need to deploy a solution to another (client) site.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Manifest:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A manifest file is an XML file that is used to describe the Web Part(s) being deployed. Simply add a new XML file to your project and call it Manifest.xml. Here is an example manifest:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Manifest.xml&lt;/strong&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;&amp;lt;!-- You need only one manifest per CAB project for Web Part Deployment.--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;&amp;lt;!-- This manifest file can have multiple assembly nodes.--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WebPartManifest&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/WebPart/v2/Manifest"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Assemblies&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Assembly&lt;/span&gt; &lt;span class="attr"&gt;FileName&lt;/span&gt;&lt;span class="kwrd"&gt;="WebPartTest.dll"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SafeControls&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SafeControl&lt;/span&gt; &lt;span class="attr"&gt;Namespace&lt;/span&gt;&lt;span class="kwrd"&gt;="WebPartTest"&lt;/span&gt; &lt;span class="attr"&gt;TypeName&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SafeControls&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Assembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Assemblies&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DwpFiles&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DwpFile&lt;/span&gt; &lt;span class="attr"&gt;FileName&lt;/span&gt;&lt;span class="kwrd"&gt;="WebPart1.dwp"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DwpFiles&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WebPartManifest&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Web Part Config:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A web part config file is an XML file used to describe an individual Web Part. Add another new XML file to your project and give it the same name as the Web Part class name, but give it an extension of DWP. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;WebPart1.dwp&lt;/strong&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WebPart&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/WebPart/v2"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;My Web Part&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Description&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;This is my web part.&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Description&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Assembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;WebPartTest&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Assembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TypeName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;WebPartTest.WebPart1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TypeName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WebPart&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;CAB Setup Project:&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Add a CAB Setup project to the solution by adding a New Project and select the CAB Project template under Other Project Types Setup and Deployment. Give it a name like WebPartTest.Setup.&lt;br /&gt;&lt;br /&gt;Now, right click on the project and select Add Project Output. In the dialog that is displayed, select Primary Output Content Files and click OK.&lt;br /&gt;&lt;br /&gt;A Build of this setup project should produce a .CAB file containing your Web Part assembly, its config file (DWP) and the manifest.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Installation into WSS:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Use the stsadm command located in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\ to install and uninstall your packages. IIS will require a restart after this, via the iisreset command.&lt;br /&gt;&lt;br /&gt;To install:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;stsadm -o addwppack -filename WebPartTest.Setup.cab -url &lt;a href="http://localhost/"&gt;http://localhost/&lt;/a&gt; -globalinstall -force&lt;br /&gt;iisreset /timeout:0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To uninstall:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;stsadm -o deletewppack -name WebPartTest.Setup.cab&lt;br /&gt;iisreset /timeout:0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;Final Notes&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;So, it doesn't seem that involved, but unless I missed something completely, its not that well documented. Hopefully this helps someone who is in the same boat that I was.&lt;br /&gt;&lt;br /&gt;I'd be interested to see how other people managed themselves trying to do the same thing, and whether there are any particularly good resources out there for this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-6497221552080227573?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/6497221552080227573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=6497221552080227573' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6497221552080227573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/6497221552080227573'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2006/12/simple-web-part-for-windows-sharepoint.html' title='A Simple Web Part for Windows Sharepoint Services (WSS) 3.0'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-2847101287792170817</id><published>2006-12-28T11:46:00.000+08:00</published><updated>2007-01-09T11:08:01.520+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><title type='text'>Restoring Missing Templates in Visual Studio 2005</title><content type='html'>The other day I noticed that I was missing the Class template in the Add New Item dialog. Not a big deal, I said, just add a text file and change the extension. That was okay for a while, but it started to wear on me - why wasn't it there?&lt;br /&gt;&lt;br /&gt;It turns out I was missing a whole bunch of templates and a complete reinstall of Visual Studio did nothing to fix it.&lt;br /&gt;&lt;br /&gt;Apparently quite a few people are having this problem and yes, there is a fix! Thanks to &lt;a href="http://geekswithblogs.net/ehammersley/archive/2005/11/08/59451.aspx"&gt;Eric Hammersley and his blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Or if you are lazy (like me) and skimmed most of the above, close VS, open a new VS Command Prompt and enter the following command:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;devenv /installvstemplates&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Worked for me!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-2847101287792170817?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/2847101287792170817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=2847101287792170817' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2847101287792170817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/2847101287792170817'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2006/12/restoring-missing-templates-in-visual.html' title='Restoring Missing Templates in Visual Studio 2005'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7740113442922996729.post-5054876756691245382</id><published>2006-12-28T10:44:00.000+08:00</published><updated>2006-12-28T10:48:02.175+08:00</updated><title type='text'>Ta da!</title><content type='html'>Ahh, a new blog.&lt;br /&gt;&lt;br /&gt;This is more a way of gathering and sorting stuff I'm working on and figuring out at the time. If anyone else finds this useful, then that can only be a good thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7740113442922996729-5054876756691245382?l=adriandev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adriandev.blogspot.com/feeds/5054876756691245382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7740113442922996729&amp;postID=5054876756691245382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5054876756691245382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7740113442922996729/posts/default/5054876756691245382'/><link rel='alternate' type='text/html' href='http://adriandev.blogspot.com/2006/12/ta-da.html' title='Ta da!'/><author><name>Adrian Brown</name><uri>http://www.blogger.com/profile/09197663107306500241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://lh5.google.com/image/AdesBrown/RZ38c6tIveI/AAAAAAAAAY0/S7j0Hn42Hhg/bender_80x78.gif.jpg'/></author><thr:total>0</thr:total></entry></feed>
