<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Anything's Possible</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/adamroot/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/adamroot/feed.xml</link>
    <description>Ever heard a developer say &amp;quot;it can&amp;#039;t be done?&amp;quot; It is one of my biggest pet peeves. The truth is, it can be done. If you approach a problem pragmatically and put enough effort into it, understanding the root issues, and not settling for sub-pa</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:13:02 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Building VS 2008 Unit Test Projects in MSBuild 4.0 Beta 2</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/building-vs-2008-unit-test-projects-in-msbuild-4-0-beta-2</link>
      <pubDate>Thu, 10 Dec 2009 10:39:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2009/12/10/building-vs-2008-unit-test-projects-in-msbuild-4-0-beta-2/</guid>
      <description><![CDATA[Introduction
MSBuild 4.0 has all sorts of features for targeting different .NET Framework versions....]]></description>
      <content:encoded><![CDATA[<H5>Introduction</H5>
<P>MSBuild 4.0 has all sorts of features for targeting different .NET Framework versions. The idea is that you can use MSBuild 4.0 to build all your legacy (pre-4.0) project types, as well as new projects that just target a downlevel version of the .NET Framework. In addition, you can mix and match the target framework versions for different projects under a single invocation of MSBuild.exe. Unfortunately, in Beta 2, we've had reports of a problem with building unit test projects that contain the special generated accessor assemblies, otherwise known as "test references". If you have a VS 2008 unit test project with test references, you may find that MSBuild 4.0 gives you an error like:</P>
<P>Caught a BadImageFormatException saying "Could not load file or assembly 'C:\Build\Project\Sources\ProjectName\ProjectName.UnitTests\obj\Debug\ProjectName_Accessor.dll' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.".</P>
<P><EM>Update: This should be fixed for the final release of VSTS 2010.</EM></P>
<H5>The Problem</H5>
<P>MSBuild 4.0 uses the .NET 4.0 CLR. All the MSBuild tasks, including third party and custom tasks, are loaded under the 4.0 runtime. This, in most cases, isn’t bad, because the 4.0 runtime should be perfectly capable of running code that was targeted for the 2.0 runtime. However, in the case of the VS 2008 Team Test BuildShadowTask, the code creates an assembly using the System.Reflection.Emit namespace. That namespace, when provided by the 2.0 CLR emits assemblies targeting the 2.0 CLR. When the namespace&nbsp;is provided by the 4.0 CLR it emits assemblies targeted at the … drum roll please … 4.0 CLR! So, when you build a VS 2008 unit test project&nbsp;(targeting the 3.5 framework, which uses the 2.0 CLR) using MSBuild 4.0, you end up with accessor assemblies that target the 4.0 CLR. Oops. Now downlevel applications trying load the assembly will blow up with the above exception. You’ll see it sometimes during your build with ResGen.exe, or when you go to run your tests from MSTest.exe.</P>
<H5>The <STRIKE>Solution</STRIKE> Workaround</H5>
<P>To get around this, all you need to do&nbsp;is run the BuildShadowTask from MSBuild 3.5, which is the version VS 2008 projects were meant to be built with. However, if you are using build features in TFS 2010 Beta 2, you are in trouble, since it (out-of-the-box) only supports MSBuild 4.0. Sure, you could write your own build activity to run MSBuild 3.5, but MSBuild 4.0 is *supposed* to work. So rather than blaming the TFS Build team (of which I am a part of) I’ll address the real issue. Several teams have gained traction to resolve this bug before shipping, but there is no guarantee. Quite frankly, this bug is minor in regards to the entire project. My team is pushing heavily for it to get done, but time will only tell.</P>
<P>Just as an extra note, the problem is actually in the VS 2008 Microsoft.TeamTest.targets file, or the BuildShadowTask that it uses (depending on how you look at it). They generate an assembly targeting the wrong framework version. So that is a natural place to fix the issue. Instead of modifying the .targets file directly (you could, but think of all the things that could go wrong!) I decided to&nbsp;add a new .targets file, and then modify my unit test projects to load it instead of the original.&nbsp;The new .targets will replace the ResolveTestReferences target that Microsoft.TeamTest.targets exposes.</P>
<H5>Fast Track</H5>
<P>If you just want to get it done and don’t care to know how it works, do this:</P>
<OL>
<LI>Download the <A href="http://cid-6f4c66b0ee56cd90.skydrive.live.com/self.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20%5E5Beta%202%5E6/Microsoft.TeamTest.4.zip">attached</A> file and place the .targets file in %ProgramFiles%\MSBuild\Microsoft\VisualStudio\9.0\TeamTest (or %ProgramFiles(x86)%\MSBuild\Microsoft\VisualStudio\9.0\TeamTest on an x64 system).</LI>
<LI>Add the following property to your unit test project (.csproj or .vbproj) files near the beginning (it needs to be before the import of Microsoft.CSharp.targets).<BR><BR><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">MsTestToolsTargets</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.4.targets<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">MsTestToolsTargets</SPAN><SPAN style="COLOR: blue">&gt;</SPAN></SPAN></LI></OL>
<H5>The Details</H5>
<P>I am aiming to <EM><STRONG>replace</STRONG></EM> the old behavior. Microsoft.Common.targets uses the MsTestToolsTargets property to define where to load the test tools .targets file from, so I have an easy way to replace the old behavior. Let’s first look at the existing Microsoft.TeamTest.targets file.</P>
<P>&nbsp; <SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">UsingTask</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">TaskName</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">BuildShadowTask</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">AssemblyFile</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN></SPAN></P>
<P>If you are familiar with MSBuild project files, this is easy to understand. If not, just know that the UsingTask element is a way to import a coded MSBuild task. In this case, the BuildShadowTask being imported is what generates the accessor assembly. Well, sort of. It links to Publicize.exe, which does the actual assembly generation, but as far as MSBuild is concerned, the task’s implementation is irrelevant.</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>$(ResolveReferencesDependsOn);<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>ResolveTestReferences<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<BR></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">PropertyGroup</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P>In this section, the ResolveReferencesDependsOn property, which is used to determine the targets that the ResolveReferences target depends on, is modified to include the ResolveTestReferences target. The ResolveTestReferences target is the target that invokes BuildShadowTask, which you’ll see below. This is a standard way to add your custom targets to the common target dependency chain.</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Target</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Name</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">ResolveTestReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">Condition</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">'@(Shadow)'!=''</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">BuildShadowTask</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">CurrentResolvedReferences</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferencePath)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">CurrentCopyLocalFiles</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferenceCopyLocalPaths)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Shadows</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(Shadow)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">ProjectPath</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(ProjectDir)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">IntermediatePath</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">SignAssembly</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(SignAssembly)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">KeyFile</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(AssemblyOriginatorKeyFile)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">DelaySign</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(DelaySign)</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">FixedUpReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferencePath</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">NewCopyLocalAssemblies</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferenceCopyLocalPaths</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">BuildShadowTask</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<BR></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Target</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P>Here is the meat of the .targets file. It is a single target that leaves the bulk of the logic to the custom task. It passes all the relevant properties and items to the task, and assigns a couple of outputs. What you need to take from this is that when I re-implement this target, I need to maintain the same behavior. I looked at invoking Publicize.exe to accomplish this, but it turns out that Publicize.exe doesn’t have very many command line parameters. It could be done, but you’d need a custom task or a lot of MSBuild logic to accomplish the same as the standard BuildShadowTask. So, instead, I cheated. My solution was to shell out to MSBuild 3.5 to do this part of the build process. That means I need to be able to target the ResolveTestReferences target alone, which took a little extra work.</P>
<P>Let’s jump into the new .targets file. Remember, this&nbsp;<EM><STRONG>replaces</STRONG></EM> the above logic, it doesn’t add onto it.</P>
<P>&nbsp; <SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">UsingTask</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">TaskName</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">BuildShadowTask</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">AssemblyFile</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN></SPAN></P>
<P>Here I didn’t make any changes to the orginal .targets file. I import the BuildShadowTask as before. I will,&nbsp;in fact, use it, just in a round-about way (you’ll see what I mean in a bit).&nbsp; </P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">CoreResolveTestReferencesTarget</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Condition</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue"> '$(CoreResolveTestReferencesTarget)' == '' </SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN>ExternResolveTestReferences<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">CoreResolveTestReferencesTarget</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<o:p></o:p></SPAN></P>
<P>Here is where some of the magic happens. Remember that I said my solution is to shell out to MSBuild 3.5. Well, the .targets file that I’m creating will be included in both the MSBuild 4.0 and MSBuild 3.5 cases. That is, the initial&nbsp;build and the shelled out build will both use this same logic.&nbsp;I differentiate the two scenarios in this property. The condition on the property states “if the property isn’t set”. That is,&nbsp;I only set the property if it wasn’t previously set. In this case, it won’t be set when the .targets file is loaded from MSBuild 4.0. When I shell out to MSBuild 3.5, I’ll set it explicitly. From MSBuild 4.0 I’ll set it to ExternResolveTestReferences, but when it is called from MSBuild 3.5 it will be set to CoreResolveTestReferences.</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>$(ResolveReferencesDependsOn);<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>$(CoreResolveTestReferencesTarget)<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P>Like the original .targets file, I needed to fit my targets into the dependency chain for the common build targets. We add the target in the value of the property CoreResolveTestReferencesTarget, which I defined above.</P>
<P><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<BR></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveTestReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<BR></SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>ResolveReferences;<BR></SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>$(CoreResolveTestReferencesTarget)<BR></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ResolveTestReferencesDependsOn</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<BR></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">PropertyGroup</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P>I also added a standard dependency property for the ResolveTestReferences target. This is because when you use the original .targets file, you can’t build just the ResolveTestReferences target, because it doesn’t define its dependencies. I needed to call the target directly, so I added the required dependencies.</P>
<P>&nbsp; <SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Target</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Name</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">ResolveTestReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">Condition</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">'@(Shadow)'!=''</SPAN>"&nbsp;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">DependsOnTargets</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">$(ResolveTestReferencesDependsOn)</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN></SPAN></P>
<P>The original ResolveTestReferences contained all the logic to call out to the BuildShadowTask. Since I need to use different logic between MSBuild 4.0 and MSBuild 3.5 I added the target dependencies and removed the logic. The condition just states that “if there are Shadow items”. In other words, only run the target if items are defined as Shadow, which are the test reference (.accessor) files.</P>
<P>&nbsp; <SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Target</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Name</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">CoreResolveTestReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">Condition</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">'@(Shadow)'!=''</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN></SPAN></P>
<P>The CoreResolveTestReferences target is the one called from MSBuild 3.5. It has the same condition as the ResolveTestReferences target to avoid unnecessary invocations. This target will look a lot like the original ResolveTestReferences target. In fact the next bit is a direct copy:</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">BuildShadowTask</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">CurrentResolvedReferences</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferencePath)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">CurrentCopyLocalFiles</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferenceCopyLocalPaths)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Shadows</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(Shadow)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">ProjectPath</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(ProjectDir)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">IntermediatePath</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">SignAssembly</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(SignAssembly)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">KeyFile</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(AssemblyOriginatorKeyFile)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">DelaySign</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(DelaySign)</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">FixedUpReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferencePath</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">NewCopyLocalAssemblies</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferenceCopyLocalPaths</SPAN>"<SPAN style="COLOR: blue">/&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">BuildShadowTask</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN></P>
<P>Just like the original ResolveTestReferences, a call out to the BuildShadowTask is done. The difference is in the next couple of lines:</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">WriteLinesToFile</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">File</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferencePath.txt</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Lines</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferencePath)</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Overwrite</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">true</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">WriteLinesToFile</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">File</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferenceCopyLocalPaths.txt</SPAN>"<o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Lines</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">@(ReferenceCopyLocalPaths)</SPAN>"<BR></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Overwrite</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">true</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN></SPAN></P>
<P>All I’m doing here is writing the values of the ReferencePath and RefenceCopyLocalPaths items out to a text file. Note that there is a potential for data loss here, if the items have metadata attached to them. In my tests, I didn’t see any issues. The reason I write the values of these items out to a file is that I want to read them back into MSBuild 4.0 space. It was the easiest way I could think of to try to replicate the original behavior.</P>
<P><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&nbsp; &lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Target</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P>And, of course, this just closes the CoreResolveTestReferences target. Now onto the MSBuild 4.0 logic.</P>
<P><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&nbsp; &lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Target</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Name</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">ExternResolveTestReferences</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">Condition</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">'@(Shadow)'!=''</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN></SPAN></P>
<P>The ExternResolveTestRefences target contains the logic for MSBuild 4.0 to shell out to MSBuild 3.5. It uses the same condition as seen on the ResolveTestRefences target.</P>
<P><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Exec</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Command</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue">$(MSBuildBinPath)\MSBuild.exe</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue"> /t:ResolveTestReferences </SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue">$(MSBuildProjectFullPath)</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue"> /p:Configuration=</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue">$(Configuration)</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue"> /p:Platform=</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue">$(Platform)</SPAN><SPAN style="COLOR: red">&amp;quot;</SPAN><SPAN style="COLOR: blue"> /p:OutDir=$(OutDir) /p:CoreResolveTestReferencesTarget=CoreResolveTestReferences</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN></SPAN></P>
<P>Here is where we shell out to MSBuild 3.5. In MSBuild 4.0, I found that the MSBuildBinPath property is set to the target framework’s bin path, not the 4.0 bin path, so I was able to use that to invoke the correct version of MSBuild.exe.</P>
<P>If you are not familiar with the MSBuild command line arguments, the /t indicates the target or targets to run and /p defines a property. Since I set up the dependency chain for the ResolveTestRefences target, we can just tell MSBuild 3.5 to build that target. After the /t argument you’ll see that I pass the full path to the MSBuild project that is currently being built, which should be the unit test project. The rest of the arguments are properties that need set to maintain behavior. This is where you might find the need to do some customization. I’ll go over some of the properties and why I included them.</P>
<P>The Configuration property is the configuration that you want to build. A configuration is typically ‘Release’ or ‘Debug’ for .NET projects, but it can be customized. Anyway, here I just wanted to pass the currently building configuration on to MSBuild 3.5 so it builds to the right folders, etc.</P>
<P>The Platform property is the platform that you are targeting. For example, x86 or x64. For .NET projects, it will typically be ‘Any CPU’. Just like the Configuration property, I just wanted to maintain the same for MSBuild 3.5 since it often is used to construct output file paths, etc.</P>
<P>The OutDir property is set because it is a commonly overridden property for TFS Build builds. This problem was initially found from a customer that was trying to use TFS Beta 2 to build legacy projects. Well, TFS Build overrides the OutDir property in order to get all your projects to put their outputs into a single location. To get project references and such to resolve correctly, it is needed, although no outputs are placed there from my invocation of MSBuild 3.5.</P>
<P>Finally, the CoreResolveTestReferencesTarget is set to CoreResolveTestReferences. This is the key to making sure that the invoked MSBuild 3.5 uses the CoreResolveTestReferences target, which does the actual BuildShadowTask call. Don’t change this.</P>
<P>Ok, now the last thing to do is read back in those files that we wrote from the CoreResolveTestReferences task in MSBuild 3.5.</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ReadLinesFromFile</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">File</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferencePath.txt</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">Lines</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferencePath</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ReadLinesFromFile</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ReadLinesFromFile</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">File</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferenceCopyLocalPaths.txt</SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Output</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">TaskParameter</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">Lines</SPAN>"<SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">ItemName</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">ReferenceCopyLocalPaths</SPAN>"<SPAN style="COLOR: blue"> /&gt;<BR></SPAN></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">ReadLinesFromFile</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P>Simply, I read the lines right back into the properties that they were written from in MSBuild 3.5, but in MSBuild 4.0 space. With any luck, any other targets will have the expected values already in these item properties. This was the final key to maintaining the same behavior as the original ResolveTestReferences target.</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Delete</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Files</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferencePath.txt</SPAN>"<SPAN style="COLOR: blue"> /&gt;<BR></SPAN></SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Delete</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> </SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Files</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">=</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">"<SPAN style="COLOR: blue">$(IntermediateOutputPath)ReferenceCopyLocalPaths.txt</SPAN>"<SPAN style="COLOR: blue"> /&gt;</SPAN></SPAN></P>
<P>For good measure, I go ahead and delete the intermediate files, since they mean nothing for incremental building.</P>
<P>&nbsp; <SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&lt;/</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">Target</SPAN><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">&gt;</SPAN></P>
<P><SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"></SPAN>And, of course, this ends the ExternResolveTestReferences target.</P>
<P>All that code is <A href="http://cid-6f4c66b0ee56cd90.skydrive.live.com/self.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20%5E5Beta%202%5E6/Microsoft.TeamTest.4.zip">attached</A> as Microsoft.TeamTest.4.targets. You’ll want to drop that file into your %ProgramFiles%\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest folder. On an x64 system, put it in %ProgramFiles(x86)%\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest.</P>
<P>Now, to get your unit test projects to pick up this .targets file instead of the original, you need to add one property to them. If you have a large project structure, then perhaps you have a single place that you can add it. If you have a large project structure and aren’t using .targets files for your common customizations (properties, custom build processes, etc) then I suggest you start looking into it.</P>
<P>The key is to get this property defined <EM><STRONG>before</STRONG></EM> you import Microsoft.CSharp.targets. If you are at all familiar with MSBuild project files, you won’t have too much trouble. For the rest of you, I’ll show you how to add it to a plain ol’ unit test project. Open the unit test project file (.csproj or .vbproj) in notepad or VS using the XML editor. Find the first set of properties, something like:</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&nbsp; &lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt"><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Configuration</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Condition</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue"> '$(Configuration)' == '' </SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN>Debug<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">Configuration</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">Platform</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"> </SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: red; FONT-SIZE: 9.5pt">Condition</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">=</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">"<SPAN style="COLOR: blue"> '$(Platform)' == '' </SPAN>"<SPAN style="COLOR: blue">&gt;</SPAN>AnyCPU<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">Platform</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ProductVersion</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">9.0.30729<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">ProductVersion</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">SchemaVersion</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">2.0<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">SchemaVersion</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ProjectGuid</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">{9C571CAA-F9D2-4103-8B1E-5AB41E34C187}<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">ProjectGuid</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">OutputType</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">Library<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">OutputType</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">AppDesignerFolder</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">Properties<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">AppDesignerFolder</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">RootNamespace</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">UnitTests<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">RootNamespace</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">AssemblyName</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">UnitTests<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">AssemblyName</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">TargetFrameworkVersion</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">v3.5<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">TargetFrameworkVersion</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">FileAlignment</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">512<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">FileAlignment</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">ProjectTypeGuids</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">ProjectTypeGuids</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>&lt;/</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">PropertyGroup</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;<o:p></o:p></SPAN></P>
<P>Add this property somewhere in that property group:</P>
<P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: none" class=MsoNormal><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&lt;</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: #a31515; FONT-SIZE: 9.5pt">MsTestToolsTargets</SPAN><SPAN style="FONT-FAMILY: Consolas; COLOR: blue; FONT-SIZE: 9.5pt">&gt;</SPAN><SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9.5pt">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.4.targets<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">MsTestToolsTargets</SPAN><SPAN style="COLOR: blue">&gt;</SPAN><o:p></o:p></SPAN></P>
<P>Save the file, and you’re done. Go build from MSBuild 4.0. You should see that the generated accessor assemblies are linked to the 2.0 CLR and <EM><STRONG>not</STRONG></EM> the 4.0 CLR. You can verify by opening the assembly in ILDasm.exe. Open the MANIFEST node.</P>
<P>What you&nbsp;<STRONG><EM>should</EM></STRONG> see:</P><PRE>.assembly extern mscorlib<BR>{<BR>&nbsp; .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .z\V.4..<BR>&nbsp; .ver 2:0:0:0<BR>}</PRE>
<P>What you&nbsp;<STRONG><EM>should not</EM></STRONG>&nbsp;see:</P><PRE>.assembly extern mscorlib<BR>{<BR>&nbsp; .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .z\V.4..<BR>&nbsp; .ver 4:0:0:0<BR>}<BR>.assembly extern mscorlib as mscorlib_2<BR>{<BR>&nbsp; .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .z\V.4..<BR>&nbsp; .ver 2:0:0:0<BR>}</PRE>
<H5>Conclusion</H5>
<P>You&nbsp;<STRONG><EM>can</EM></STRONG> in fact build 2.0 linked accessor assemblies using MSBuild 4.0 Beta 2. However, this is only a workaround. You may need to customize it to your environment or needs.</P>
<P>I hope this helps some people out. Please do leave feedback if you find errors or if you just want to give a big thumbs up (or down).<BR></P>
<H5>Downloads</H5><IFRAME style="PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #fcfcfc; PADDING-LEFT: 0px; WIDTH: 98px; PADDING-RIGHT: 0px; HEIGHT: 115px; PADDING-TOP: 0px" title=Preview marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedicon.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20^5Beta%202^6/Microsoft.TeamTest.4.zip" frameBorder=0 marginWidth=0 scrolling=no mce_src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedicon.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20^5Beta%202^6/Microsoft.TeamTest.4.zip"></IFRAME>
<p><a href="http://cid-6f4c66b0ee56cd90.skydrive.live.com/self.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20^5Beta%202^6/Microsoft.TeamTest.4.zip">http://cid-6f4c66b0ee56cd90.skydrive.live.com/self.aspx/Public/Building%20VS%202008%20Unit%20Test%20Projects%20in%20MSBuild%204.0%20^5Beta%202^6/Microsoft.TeamTest.4.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Source Server and Symbol Server Features in Team Foundation Server 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/source-server-and-symbol-server-features-in-team-foundation-server-2010</link>
      <pubDate>Wed, 17 Jun 2009 12:59:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2009/06/17/source-server-and-symbol-server-features-in-team-foundation-server-2010/</guid>
      <description><![CDATA[Introduction
Jim Lamb wrote a good post about Enabling Symbol and Source Server Support in TFS...]]></description>
      <content:encoded><![CDATA[<H5>Introduction</H5>
<P>Jim Lamb wrote a good post about <A href="http://blogs.msdn.com/jimlamb/archive/2009/06/15/enabling-symbol-and-source-server-support-in-tfs-build-2010-beta-1.aspx" target=_blank mce_href="http://blogs.msdn.com/jimlamb/archive/2009/06/15/enabling-symbol-and-source-server-support-in-tfs-build-2010-beta-1.aspx">Enabling Symbol and Source Server Support in TFS Build 2010 Beta 1</A>. His post gives a great overview of the requirements to get it working out of the box (it’s very easy!), while this post aims to help the beginner understand how it works, to elaborate on some details of the features, and to identify what customizations are available.</P>
<P>Note that the source server and symbol server features complement each other nicely, but neither requires the other.</P>
<H5>Source Server Features</H5>
<P>If you are unfamiliar with Microsoft’s Source Server features, it really is just metadata (source index) added to debugging symbols. A debugger with source server support can read the metadata and locate the correct versions of files and download them as needed during a debugging session. The metadata is contained in a “stream” of a PDB file and keeps the server location, the server path, and the version for each source file referenced in the symbols. That’s it. This process of adding metadata to debugging symbols is sometimes referred to as “source indexing”.</P>
<P>The TFS Build 2010 implementation largely follows the lead of ssindex.cmd from the Debugging Tools for Windows package. In fact, some of the tools shipped with Debugging Tools for Windows are redistributed with TFS 2010 so that the Debugging Tools don’t need to be separately installed. This makes enabling source server support extremely easy. All you need to do is set the Index Sources build parameter to true for the default build process template. You can do this for any build definition that uses the default template by changing the default value for the parameter, or you can change it in the Queue Build dialog when you queue a build (for a definition using the appropriate template).</P>
<P>The source indexing is done by the IndexSources activity provided by TFS Build. It takes only one argument called FileList, which is the list of symbol files (PDBs) to add a source index to. By default, all PDBs under the output directory are indexed.</P>
<P>IndexSources uses the current build (the one that is building) and workspace mappings to determine the version control information it needs for the sources, and doesn’t let you change how it uses that information. The limitation here is that if you are building sources that come from multiple workspaces (not recommended) then your source index may be incomplete.</P>
<H6>Customizing the Source Index</H6>
<P><EM>Consider this a warning that messing with the source index outside of using the IndexSources activity is not supported by TFS.</EM></P>
<P>One of the tools that comes in Debugging Tools for Windows is pdbstr.exe. Its sole purpose is to read and write “streams” from PDB files. One situation you may find yourself in is that your TFS installation is accessible from the web, or from anywhere that requires a different URL than the one that the build machine uses, you may need to read out the source index, modify the TFS URL, and then write the source index back.</P>
<P>You can read the source index to a file using this command: 
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:5901159d-5e41-4db2-8288-ef9642d1a298 class=wlWriterEditableSmartContent><PRE style="BACKGROUND-COLOR: #ffffff; WORD-WRAP: break-word; WHITE-SPACE: pre-wrap; OVERFLOW: auto"><SPAN style="COLOR: #000000">pdbstr</SPAN><SPAN style="COLOR: #000000">.</SPAN><SPAN style="COLOR: #000000">exe -r -p:</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;pdb path&gt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> -i:</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;index file&gt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> -s</SPAN><SPAN style="COLOR: #800000">:srcsrv</SPAN></PRE><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></DIV>
<P>Edit the VSTFSSERVER variable value to point to the appropriate external URL. Then write the index back using: 
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:65118333-76ce-44e9-8732-7346fca20a91 class=wlWriterEditableSmartContent><PRE style="BACKGROUND-COLOR: #ffffff; WORD-WRAP: break-word; WHITE-SPACE: pre-wrap; OVERFLOW: auto"><SPAN style="COLOR: #000000">pdbstr</SPAN><SPAN style="COLOR: #000000">.</SPAN><SPAN style="COLOR: #000000">exe -w -p:</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;pdb path&gt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> -i:</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;index file&gt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> -s</SPAN><SPAN style="COLOR: #800000">:srcsrv</SPAN></PRE><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></DIV>
<P><EM>If any readers have other specific requirements for source indexing, please do let me know and I’ll try to address them.</EM></P>
<H5>Symbol Server Features</H5>
<P>A symbol server is a Windows network share or folder that has a particular format, managed by symstore.exe, another tool shipped with Debugging Tools for Windows. If you direct a supported debugger to that share to find symbols, it should be able to automatically find the right version for the binaries that you are debugging (providing they exist in the share somewhere).</P>
<P>TFS Build 2010 provides support to add symbols to the symbol server share during a build. This is typically done after source indexing (if source indexing is being used) so that someone debugging a build for which they don’t (directly) have symbols or sources can seamlessly step through code and examine call stacks and variables.</P>
<P>To add symbols to a symbol server share, TFS Build provides the PublishSymbols activity. The activity works out-of-the-box by setting the Path to Publish Symbols build process parameter. You should set it to a UNC path, even if you are publishing to a local machine folder, as this feature was aimed at the “typical” user.</P>
<H6>Customizing Symbol Publishing</H6>
<P>Your customization options for symbol publishing is pretty wide open. Since PublishSymbols is really just a wrapper around the InvokeProcess activity (also shipped with TFS Build) which calls symstore.exe with the “add” command, you can provide additional command line arguments using the CommandLineArguments argument. Remember, these are <EM>additional</EM> command line arguments. The StorePath and ProductName activity arguments are required, so you shouldn’t include them in CommandLineArguments. Also, the files to publish are provided to symstore.exe as a temp file that contains a list of files, which is generated by the files provided in the FileList argument. Examples of what you may add to CommandLineArguments are the /3 and /p options. Those are simple examples, refer to symstore.exe documentation on the web for more.</P>
<P>Of course, you could always modify the template and replace PublishSymbols with InvokeProcess in circumstances where PublishSymbols doesn’t give you enough flexibility, but note that PublishSymbols tags the build with information about the symstore.exe transaction so that symbols can be deleted when a build is deleted. You could try to replicate that information yourself, but I won’t detail that here.</P>
<H6>The SharedResourceScope Activity</H6>
<P>One more thing to note about symbol server publishing is the use of the SharedResourceScope activity in the build process template. The purpose is to make sure that concurrent instances of symstore.exe aren’t adding symbols at the same time, as the tool doesn’t support concurrent access to a symbol server share. SharedResourceScope uses the Team Foundation Server to control access to an arbitrarily named resource, in this case the share. That way, if multiple builds are trying to publish symbols at the same time, the requests are queued and only one will publish at a time, while the others wait (instead of fail due to file access errors or “step on each others’ toes”). PublishSymbols does not care about shared resource locks, but it is contained within the SharedResourceScope, so won’t be executed until the lock is appropriately acquired.</P>
<H5>Conclusion</H5>
<P>With Team Foundation Server 2010 you can boost the efficiency across your dev and test teams using the provided source server and symbol server features out-of-the-box. Yet, for the experienced teams with more precise requirements, you have a lot of options for customization.</P>]]></content:encoded>
    </item>
    <item>
      <title>Working with Deleted Build Data in Team Foundation Server 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/working-with-deleted-build-data-in-team-foundation-server-2010</link>
      <pubDate>Fri, 12 Jun 2009 11:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2009/06/12/working-with-deleted-build-data-in-team-foundation-server-2010/</guid>
      <description><![CDATA[In Team Foundation Server 2008 you could delete builds both from the Build Explorer, using the...]]></description>
      <content:encoded><![CDATA[<P>In Team Foundation Server 2008 you could delete builds both from the Build Explorer, using the context menu on one or more builds, and from the command line, using TfsBuild.exe. Also, retention policy would automatically delete builds as specified. Once you deleted the build, you no longer were able to see the build in the Build Explorer, as it no longer "exists", and TfsBuild.exe's delete command will complain that the build doesn't exist. In Team Foundation Server 2010, you may be surprised to find that, although you don't see the build in Build Explorer, your data still exists in the database. Well, some of it.</P>
<P mce_keep="true"><A title="Working with Deleted Build Data in Team Foundation Server 2010 (Beta 1)" href="http://blogs.msdn.com/adamroot/pages/working-with-deleted-build-data-in-team-foundation-server-2010-beta-1.aspx" mce_href="http://blogs.msdn.com/adamroot/pages/working-with-deleted-build-data-in-team-foundation-server-2010-beta-1.aspx">Read More ...</A></P>]]></content:encoded>
    </item>
    <item>
      <title>Working with Deleted Build Data in Team Foundation Server 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/working-with-deleted-build-data-in-team-foundation-server-2010-2</link>
      <pubDate>Fri, 12 Jun 2009 07:04:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2009/06/12/working-with-deleted-build-data-in-team-foundation-server-2010-2/</guid>
      <description><![CDATA[Introduction
In Team Foundation Server 2008 you could delete builds both from the Build Explorer,...]]></description>
      <content:encoded><![CDATA[<H5>Introduction</H5>
<P>In Team Foundation Server 2008 you could delete builds both from the Build Explorer, using the context menu on one or more builds, and from the command line, using TfsBuild.exe. Also, retention policy would automatically delete builds as specified. Once you deleted the build, you no longer were able to see the build in the Build Explorer, as it no longer "exists", and TfsBuild.exe's delete command will complain that the build doesn't exist. In Team Foundation Server 2010, you may be surprised to find that, although you don't see the build in Build Explorer, your data still exists in the database. Well, some of it. 
<P>There is more to the story. Another new feature in TFS 2010 is that you can specify <EM>what</EM> gets deleted when you delete a build, including the drop location (for binaries and other outputs), the version control label, test results, symbols (on a symbol server), and the build details (the actual database records related to the build). Until you delete the build details, your build will remain visible in Build Explorer. This article addresses actions taken after the build detail is deleted. 
<P>There are several reasons for TFS 2010 to keep build data around after the user deletes it, which I'll address in the following sections. 
<H5>Build Information that Doesn't Get Deleted </H5>
<P>So, when you delete the build details of a build, what <EM>doesn't</EM> get deleted from the database? 
<UL>
<LI>The build's detail record. This gets a flag set on it that denotes it as a "deleted" build, but is otherwise intact. 
<LI>The build's top level information nodes and some specific node types. There are several pieces of information that are stored in information nodes that are critical for post-deletion activities. A few are: 
<UL>
<LI>Associated changesets, used for warehouse rebuilding. 
<LI>Configuration summaries and build projects, used for warehouse rebuilding. 
<LI>Symbol store transaction information, used to delete a build’s symbols.</LI></UL>
<LI>The build's outputs. These are used to query build information by binary signatures of an assembly or native image. 
<LI>The build's workspace. Can be queried to reproduce a build or for informational purposes.</LI></UL>
<P>You may wonder how much space this uses per build. Well, it will vary greatly depending on the size and complexity of your project, so I won't try to answer that here. I'll try to do some analysis and give some rough estimates in a later post. 
<H5>Rebuilding the Warehouse</H5>
<P>The warehouse is where reporting data is archived in order to keep historical data as well as to keep the production databases smaller/cleaner for performance and efficiency reasons. I won't go into any details about how or why you may rebuild the warehouse, since I don't have the expertise in that area. 
<H5>Deleting Remaining Build Artifacts</H5>
<P>Let's say you've been deleting builds via retention policy, but you haven't been deleting the build symbols. This may be a useful scenario if you have builds installed or lingering around for longer periods of time than you want to keep builds for. But eventually, your symbol store will become very bloated, so you'll want to clean it up. One method to clean it up is to view the logs in the store and decide which symbols to delete that way. Another way is to let TFS do it for you. You can specify on the command line: 
<P style="FONT-FAMILY: courier"><FONT face="Courier New">tfsbuild.exe delete /server:http://tfsat:8080/collection0 /builddefinition:"Adventure Works\Nightly Build" /daterange:~2008-12-31 /deleteoptions:Symbols</FONT></P>
<P>This particular command will connect to TFS at http://tfsat:8080/collection0 (/server:http://tfsat:8080/collection0) and delete symbols (/deleteoptions:Symbols) for all builds older than December 31, 2008 (/daterange:~2008-12-31) in the build definition called "Nightly Build" on the team project "Adventure Works" (/builddefinition:"Adventure Works\Nightly Build"). There are several variations to the delete command, which you can explore in documentation or via command line help. The /deleteoptions parameter takes one or more of: 
<UL>
<LI>Details 
<LI>Label 
<LI>DropLocation 
<LI>TestResults 
<LI>Symbols 
<LI>All</LI></UL>
<P>To combine multiple, you can separate them by a comma, like: 
<P><FONT face="Courier New">/deleteoptions:Details,DropLocation</FONT> 
<P>Remember, you can delete any artifacts (that haven't been previously deleted) <EM>even after</EM> you delete the build details. That is because a limited amount of data is still stored in the database, including everything needed to delete all the artifacts. 
<H5>Matching Binaries to a Build</H5>
<P>The concept here is that you can query TFS to ask it which build created a particular binary. This is a not-well-documented feature, but it can be pretty useful. The way this works is that during a build, there is an activity that associates build outputs to the build, called AssociateBuildOutputs. What it does is read the PE (Portable Executable) image headers of a managed assembly or native binary and extracts a couple of identifying pieces of information. It stores those in an indexed table of the database. Then, when you have a binary, but for whatever reason don't know specific information about it's version/build, you can read the same information from the PE headers and query the database. This can be done for any build that exists or that has already been deleted (even if the build details were deleted). 
<P>Unfortunately, there is no tool that supports this from the command line or Visual Studio. You'll have to write some code, but it isn't very hard. The TFS Build client libraries will do the header reading for you, so don't worry. Here is an example:</P><PRE class=csharpcode><SPAN class=kwrd>using</SPAN> Microsoft.TeamFoundation.Build.Client; 

<SPAN class=kwrd>static</SPAN> IBuildDetail GetBuildForBuildOutput(IBuildServer buildServer, <SPAN class=kwrd>string</SPAN> outputPath)
{
    <SPAN class=rem>// Return values of the GetSignature function</SPAN>
    Guid guid;
    <SPAN class=kwrd>int</SPAN> age;
    
    <SPAN class=rem>// GetSignature returns false if it failed</SPAN>
    <SPAN class=rem>// to read the executable file</SPAN>
    <SPAN class=kwrd>if</SPAN> (!ModuleSignatureReader.GetSignature(outputPath, <SPAN class=kwrd>out</SPAN> guid, <SPAN class=kwrd>out</SPAN> age))
    {
        <SPAN class=kwrd>return</SPAN> <SPAN class=kwrd>null</SPAN>;
    }
    
    <SPAN class=rem>// GetBuildForBuildOutput returns null if</SPAN>
    <SPAN class=rem>// an appropriate build isn't found</SPAN>
    <SPAN class=kwrd>return</SPAN> buildServer.GetBuildForBuildOutput(guid, age);
}</PRE>
<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: Consolas, "Courier New", Courier, Monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<P>All we are doing here is wrapping a couple functions so we can query by the assembly's path. ModuleSignatureReader.GetSignature will open the file, so it needs IO read access to it. It returns true for success and false for failure. IBuildServer.GetBuildForBuildOutput then calls out to TFS to do the query and return the result. It returns null if a build can't be found for the output. 
<H5>Getting a Build's Workspace Mappings</H5>
<P>TFS Build needs a particular workspace setup to build, just like any dev working in the source code. Often this will be the same as any dev's workspace, but sometimes it will include more or less in order to satisfy specific build requirements (such as building a complete set of products which depend on each other on a nightly basis, or building just a piece of the source tree for every checkin). You can query for the particular workspace mappings used from any build. 
<P>You can do this for any build normally, but since this article focuses on deleted builds, we'll be looking for a deleted build and then getting the workspace mappings. There are only a couple methods that take a QueryDeletedOption. The IBuildServer.QueryBuildsByUri function takes it, and any functions that take IBuildDetailSpec do, by way of the IBuildDetailSpec.QueryDeletedOption property. Here is what that QueryDeletedOption enum looks like: <PRE class=csharpcode><SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>enum</SPAN> QueryDeletedOption
{
    ExcludeDeleted = 0,
    IncludeDeleted = 1,
    OnlyDeleted = 2,
}</PRE>
<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<P>Keep in mind that when we talk about "deleted" builds, we really mean the build details (database records). That still applies with this enumeration. ExcludeDeleted means don't include any deleted builds in the results. IncludeDeleted means go ahead and query deleted builds as well as not-deleted builds. OnlyDeleted means just what it says, only query for deleted builds. 
<P>Again, the command line and Visual Studio client don't have access to this data. You'll have to write code:<PRE class=csharpcode><SPAN class=rem>// Query the desired build, using QueryDeletedOption.Deleted</SPAN>
IBuildDetail build = buildServer.QueryBuildsByUri(<SPAN class=kwrd>new</SPAN> Uri[] { buildUri }, <SPAN class=kwrd>null</SPAN>, QueryOptions.None, QueryDeletedOption.Deleted);

<SPAN class=rem>// Get the workspaces used by the build</SPAN>
IWorkspaceInstance[] workspaces = build.GetWorkspaceInstances();

<SPAN class=rem>// Iterate through the workspaces</SPAN>
<SPAN class=kwrd>foreach</SPAN> (IWorkspaceInstance workspace <SPAN class=kwrd>in</SPAN> workspaces)
{
    Console.WriteLine(<SPAN class=str>"Workspace:"</SPAN>);
    <SPAN class=kwrd>foreach</SPAN> (IWorkspaceInstanceMapping mapping <SPAN class=kwrd>in</SPAN> workspace.Mappings)
    {
        Console.WriteLine(<SPAN class=str>"[{0}] {1}"</SPAN>, mapping.MappingType, mapping.ServerItem);
    }
}</PRE>
<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: Consolas, "Courier New", Courier, Monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<P>Note that there are circumstances where multiple workspaces may have been used by a build (likely a custom build) so you may have multiple workspace instances. 
<H5>Destroying Builds</H5>
<P><EM>Note: Destroying builds is not for the faint of heart. Once a build is destroyed it cannot be recovered. </EM>
<P>Destroying builds is about cleaning up your database. I believe in 9 out of 10 cases there is no need to destroy builds …&nbsp;ever. However, if your projects do <EM>a lot</EM> of builds, destroying old builds can save space and even increase performance. 
<P>When you destroy builds, you are <EM>not</EM> deleting build artifacts, such as version control labels and test results. Destroying a build permanently deletes the information from the database. Typically, if you are destroying builds, you will want to delete all the build artifacts prior to doing so. If you intend to keep the build artifacts, that is fine, too. 
<P>From the command line, you can destroy builds individually, by date range, or a couple other ways. See the documentation or command line help for more information. I envision the destroy command being used to destroy old builds. You may try something like: 
<P><FONT face="Courier New">tfsbuild.exe delete /server:http://tfsat:8080/collection0 /builddefinition:"Adventure Works\Nightly Build" /daterange:~2008-12-31 /deleteoptions:All<BR>tfsbuild.exe destroy /server:http://tfsat:8080/collection0 /builddefinition:"Adventure Works\Nightly Build" /daterange:~2008-12-31</FONT> 
<P>Of course, the delete command is optional. I use it to delete all the build artifacts prior to destroying the builds. These command lines are very similar to the one earlier in this article. Basically, we are deleting all build artifacts and then destroying the database records for builds older than December 31, 2008 for the "Nightly Build" build definition in the "Adventure Works" team project. 
<P>You can also destroy builds from the TFS Build client libraries. You'd do it something like this:</P><PRE class=csharpcode><SPAN class=rem>// Create a build detail spec to query all deleted</SPAN>
<SPAN class=rem>// builds prior to December 31, 2008</SPAN>
IBuildDetailSpec spec = buildServer.CreateBuildDetailSpec(definition);
spec.MaxChangedTime = DateTime.Parse(<SPAN class=str>"2008-12-31"</SPAN>);
spec.QueryDeletedOption = QueryDeletedOption.IncludeDeleted; 

<SPAN class=rem>// Query the builds</SPAN>
IBuildDetail[] builds = buildServer.QueryBuilds(spec).Builds;

<SPAN class=rem>// Delete any remaining artifacts for all the builds</SPAN>
<SPAN class=rem>// (Note: this can take a long time, so do it one at a time)</SPAN>
<SPAN class=kwrd>foreach</SPAN> (IBuildDetail build <SPAN class=kwrd>in</SPAN> builds)
{
    build.Delete(DeleteOptions.All);
}

<SPAN class=rem>// Now destroy the builds</SPAN>
buildServer.DestroyBuilds(builds);</PRE>
<STYLE type=text/css>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: Consolas, "Courier New", Courier, Monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</STYLE>

<P>Again, the buildServer.DeleteBuilds call is optional, and is just used to delete all the build artifacts prior to destroying the build data.</P>
<H5>Conclusion</H5>
<P>As you can see there are several things to do with deleted builds. A lot of them require getting down and dirty with the command line or custom coded tools, but there is nothing that is terribly difficult to manage. The new /daterange option for the delete and destroy commands of TfsBuild.exe will be a nice addition to those of you that like to use the baked tools, but I recommend PowerShell scripts to give you better control of your scheduled maintenance tasks.</P>]]></content:encoded>
    </item>
    <item>
      <title>Shell Style Drag and Drop in .NET - Part 3 (Bug Fix)</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/shell-style-drag-and-drop-in-net-part-3-bug-fix</link>
      <pubDate>Wed, 18 Feb 2009 16:06:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2009/02/18/shell-style-drag-and-drop-in-net-part-3-bug-fix/</guid>
      <description><![CDATA[I updated the download link for the sources of Shell Style Drag and Drop in .NET - Part 3. There was...]]></description>
      <content:encoded><![CDATA[<P>I updated the download link for the sources of <A title="Shell Style Drag and Drop in .NET - Part 3" href="http://blogs.msdn.com/adamroot/archive/2008/02/15/shell-style-drag-and-drop-in-net-part-3.aspx" mce_href="http://blogs.msdn.com/adamroot/archive/2008/02/15/shell-style-drag-and-drop-in-net-part-3.aspx">Shell Style Drag and Drop in .NET - Part 3</A>. There was a bug that several readers found, where some programs would try to get data that didn't exist, and the DragObject implementation didn't tell them about the status of the data properly. This manifested itself, for example, if you tried to add FileDrop data and drop it in the Windows Explorer.</P>
<P>There are some other potential bug fixes on the way, too.</P>]]></content:encoded>
    </item>
    <item>
      <title>Interop with PROPVARIANTs in .NET</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/interop-with-propvariants-in-net</link>
      <pubDate>Fri, 11 Apr 2008 18:45:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2008/04/11/interop-with-propvariants-in-net/</guid>
      <description><![CDATA[Introduction
When it comes interop, .NET has solved most of the hard problems. However, if you've...]]></description>
      <content:encoded><![CDATA[<H4>Introduction</H4>
<P>When it comes interop, .NET has solved most of the hard problems. However, if you've worked with COM interfaces that return or take PROPVARIANTs as parameters, you may have noticed that there isn't much support for this union'd struct type. I came across one such interface, and needed a good way to interop with its PROPVARIANT parameters. In fact, the implementation I was working with returned BLOBs, which break all sorts of basic implementations of variant interop.</P>
<P>Of course, PROPVARIANTs are used in other places than just COM. You may find yourself using P/Invoke with PROPVARIANT params, as well.</P>
<H4>Background</H4>
<P>The PROPVARIANT reuses a lot of definitions of the VARIANT/VARIANTARG types. In fact, they are nearly identical. I guess the difference is around their intended use. That is, VARIANTARG would be used to pass a set of self described arguments to a function, where the caller maintains the memory management role before and after the call. A PROPVARIANT is ideal for out params, where the caller gets an instance of the value that it needs to maintain the memory of, but the callee still maintains its own value's memory.</P>
<P>.NET actually has some support for interop of VARIANT types. For example, if you define this method:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ecaf89e9-d9d6-42bb-9ae1-bc62bd5fb4a8 class=wlWriterEditableSmartContent><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C#</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> GetProp(<BR>&nbsp;&nbsp;&nbsp; [Out, MarshalAs(UnmanagedType.Struct)] </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> pval<BR>&nbsp;&nbsp;&nbsp; );</SPAN></DIV>
<P mce_keep="true">.NET will see the MarshalAs attribute set to use UnmanagedType.Struct in combination with the object type for the parameter and assume the variable you are marshaling is a VARIANT. This works for types like int, short, byte, float, double, but not for types like BLOB. In this case you'll get a runtime error, because .NET considers the VARIANT invalid. If you'd like to know more about how .NET decides what an invalid VARIANT is, take a look at <A title="CLR SPY and Customer Debug Probes: The Invalid IUnknown and Invalid VARIANT Probes" href="http://blogs.msdn.com/adam_nathan/archive/2003/06/11/56710.aspx" target=_blank mce_href="http://blogs.msdn.com/adam_nathan/archive/2003/06/11/56710.aspx">Adam Nathan's post about debug probes</A>.</P>
<H4>The Union</H4>
<P><A title="Layout of MYSTRUCT" href="http://obm2jw.bay.livefilestore.com/y1pjD7Rg2SxO5syASszOe5QXl85rTHjKWrdh7QrkhGhXdlSTTJfC_2Su2dRNc_BD50pK7CqQP5EXunyEBd-jA_ksQ/unionx.gif" target=_blank mce_href="http://obm2jw.bay.livefilestore.com/y1pjD7Rg2SxO5syASszOe5QXl85rTHjKWrdh7QrkhGhXdlSTTJfC_2Su2dRNc_BD50pK7CqQP5EXunyEBd-jA_ksQ/unionx.gif"><IMG style="WIDTH: 400px; HEIGHT: 167px" title="The layout of a struct using a union" border=0 alt="The layout of a struct using a union" align=right src="http://obm2jw.bay.livefilestore.com/y1pjD7Rg2SxO5tlsF7Yu_yMpgXuHTTLroI01qzPLl7st4X9WcwD9Hj0_wQakzhRlI6mw9tdl3Zq2UCywDsl5DJP4g/union.gif" width=400 height=167 mce_src="http://obm2jw.bay.livefilestore.com/y1pjD7Rg2SxO5tlsF7Yu_yMpgXuHTTLroI01qzPLl7st4X9WcwD9Hj0_wQakzhRlI6mw9tdl3Zq2UCywDsl5DJP4g/union.gif"></A>The PROPVARIANT has an interesting structure. For the most part, it is a simple struct, with a field that identifies the type of data, plus a union field that contains the data itself. For those of you .NET developers that don't know what a union is, I'll give you a brief intro.</P>
<P>In a C/C++ type you can define a field as a union. Here is a simple example:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ef7961f5-f571-47ab-bd88-571f9c3874f1 class=wlWriterEditableSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C++</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #0000ff">typedef</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> tagMYSTRUCT
{
    </SPAN><SPAN style="COLOR: #0000ff">union</SPAN><SPAN style="COLOR: #000000">
    {
        </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> iVal;
        BYTE bVal;
    };
} MYSTRUCT;
</SPAN></DIV></PRE></DIV>
<P>In this struct I have defined two fields. Unlike a normal struct, though, I have pulled the two fields into a union. That union says that the two values share the same memory. So, the size of the union member is the max of the sizes of the fields defined within it. In this case, sizeof(int) &gt; sizeof(BYTE), so the union members size equals sizeof(int).</P>
<H4>The Native PROPVARIANT Structure</H4>
<P>Let's take a look at the structure of the native PROPVARIANT:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:27f49d61-8536-4d90-84e6-c0454284a8f4 class=wlWriterEditableSmartContent><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C++</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> tagPROPVARIANT<BR>{<BR>&nbsp; </SPAN><SPAN style="COLOR: #0000ff">union</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> tag_inner_PROPVARIANT<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARTYPE vt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved3;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">union</SPAN><SPAN style="COLOR: #000000"> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR cVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UCHAR bVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SHORT iVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USHORT uiVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG lVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG ulVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INT intVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT uintVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LARGE_INTEGER hVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULARGE_INTEGER uhVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FLOAT fltVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOUBLE dblVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARIANT_BOOL boolVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _VARIANT_BOOL bool;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SCODE scode;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CY cyVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE date;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILETIME filetime;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLSID </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">puuid;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLIPDATA </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pclipdata;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BSTR bstrVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BSTRBLOB bstrblobVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BLOB blob;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPSTR pszVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPWSTR pwszVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">punkVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDispatch </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pdispVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IStream </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pStream;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IStorage </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pStorage;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000"> .. snip .. </SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<BR>&nbsp;&nbsp;&nbsp; } ;<BR>&nbsp;&nbsp;&nbsp; DECIMAL decVal;<BR>&nbsp; };<BR>};</SPAN></DIV>
<P mce_keep="true">This structure has an extra level of confusion... it nests a union in a struct in a union. This is because of that DECIMAL value you'll see at the end. The DECIMAL field actually overlaps the VARTYPE field (via the outer union). This is because the PROPVARIANT's size is 16 bytes (on a 32-bit architecture) before the DECIMAL member, which is 16 bytes in itself. If the DECIMAL member were within the inner union, the size of the PROPVARIANT would grow to 20 bytes, which is no longer compatible with VARIANTs. I ignore the DECIMAL field in my implementation, because I've not run across a need for it.</P>
<P>Most of the types in the PROPVARIANT are simple, including 1/2/4/8 byte integers, 4/8 byte floating point numbers, booleans, and pointers. There are a couple of structs to take note of. BSTRBLOB and BLOB are structs that have two members, a 4-byte integer, and a pointer. These will be considered when we come up with our .NET structure layout.</P>
<H4>Creating a Managed PROPVARIANT</H4>
<P>There have been some attempts at laying out a managed PROPVARIANT by using LayoutKind.Explicit and the FieldOffsetAttribute. These work for marshaling an unmanaged struct to a managed struct, but I've seen issues going the other way. Also, because the fields of a struct in .NET will never share memory, you may end up with hundreds of bytes in your managed struct, which is passed by value! Other implementations use an IntPtr for the union member, but this doesn't allow for accessing all 8 bytes of the union member, at least not on a 32-bit architecture.</P>
<P>My implementation takes a different approach. I use an IntPtr for the first 4 bytes of the union, but I use an extra int field to access the second 4 bytes. That gives me access to all 8 bytes of the union. Plus, on a 64-bit architecture, that provides me with 12 bytes, because the size of the IntPtr becomes 8 bytes. Note that the size of the largest member of the union on a 64-bit architecture is 12 bytes, that is why I used one IntPtr and one int, instead of two IntPtrs which would result in 16 bytes for the union member.</P>
<P>The definition of my managed struct looks like this:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:94415cc8-af37-4b49-8cfc-ea7c9cc117d4 class=wlWriterEditableSmartContent><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C#</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">[StructLayout(LayoutKind.Sequential)]<BR></SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> PropVariant<BR>{<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> vt;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved1;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved2;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved3;<BR>&nbsp;&nbsp;&nbsp; IntPtr p;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> p2;<BR>}</SPAN></DIV>
<P mce_keep="true">NOTE: The vt member value is from the System.Runtime.InteropServices.ComTypes.VarEnum enumeration.</P>
<P>NOTE: I tried to code it to work on 64-bit architectures, but I don't have one to test on, so I'll leave it to my readers to tell me what does/doesn't work with regards to that. This struct will have a size of 16 bytes on a 32-bit architecture, and a size of 20 bytes on a 64-bit architecture.</P>
<P>This completes the implementation for marshaling purposes. You could use this struct to pass a PROPVARIANT to a method, or get a PROPVARIANT as an out parameter, etc. For example, an unmanaged method may like this:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:4054bb84-5d15-4a05-8250-04b98757ab0b class=wlWriterEditableSmartContent><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C++</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">HRESULT GetProp(PROPVARIANT </SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pval);</SPAN></DIV>
<P mce_keep="true">The managed import might look like this:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:752468b3-1aec-49a6-9096-5a918af46573 class=wlWriterEditableSmartContent><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C#</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> GetProp(</SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> PropVariant pval);</SPAN></DIV>
<P mce_keep="true">or</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:6eecd262-753c-4ebc-b91e-9ce2c778b0e9 class=wlWriterEditableSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> C#</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> GetProp(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> PropVariant pval);</SPAN></DIV></PRE></DIV>
<P>The standard .NET marshaler will handle these interop calls just fine without any special marshaling attributes.</P>
<P>However, this doesn't make for easy examination of the data value of the variant.</P>
<H4>Accessing the Data of the Managed PropVariant</H4>
<P>What I've done is taken the union members of the native struct and created them as private member properties of my managed struct. Each property does the appropriate bit twiddling to get its value from the IntPtr field of the struct, and the trailing int field when necessary. Here are a couple of the properties:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:23ecf76c-a078-4fb4-85e9-589451b028b8 class=wlWriterEditableSmartContent><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">sbyte</SPAN><SPAN style="COLOR: #000000"> cVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> CHAR cVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">sbyte</SPAN><SPAN style="COLOR: #000000">)GetDataBytes()[</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">]; }<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">short</SPAN><SPAN style="COLOR: #000000"> iVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> SHORT iVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt16(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> lVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> LONG lVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt32(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000"> hVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> LARGE_INTEGER hVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt64(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">float</SPAN><SPAN style="COLOR: #000000"> fltVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> FLOAT fltVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToSingle(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp; }</SPAN></DIV>
<P mce_keep="true">The BitConverter is part of the framework, and comes in handy when you are working with bits that you don't want to convert by value (ie. (float)1 results in a float of value 1, not a float with bits 0x00..0001).</P>
<P>I wrote a GetDataBytes function to help get the needed bytes from the union part of the structure:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:48e08e15-35c5-4adc-96dd-616d637e69fd class=wlWriterEditableSmartContent><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] GetDataBytes()<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] ret </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[IntPtr.Size </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p.ToInt32()).CopyTo(ret, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">8</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p.ToInt64()).CopyTo(ret, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p2).CopyTo(ret, IntPtr.Size);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> ret;<BR>&nbsp;&nbsp;&nbsp; }</SPAN></DIV>
<P mce_keep="true">Now, based on the vt member, we can determine which property to use to get the real value. This can be simplified into a single public property:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:3d78647a-5f86-4aad-9e51-10d1e508b34a class=wlWriterEditableSmartContent><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> Value<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">switch</SPAN><SPAN style="COLOR: #000000"> ((VarEnum)vt)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> cVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> bVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> iVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> uiVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_INT:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> lVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UINT:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> ulVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> hVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> uhVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_R4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> fltVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_R8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> dblVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BOOL:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> boolVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_ERROR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> scode;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_CY:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> cyVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_DATE:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> date;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_FILETIME:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> DateTime.FromFileTime(hVal); 
<P></SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringBSTR(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BLOB:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] blobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[lVal];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr pBlobData;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pBlobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> IntPtr(p2);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">8</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> In this case, we need to derive a pointer at offset 12,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> because the size of the blob is represented as a 4-byte int<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> but the pointer is immediately after that.</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pBlobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> IntPtr(BitConverter.ToInt64(GetDataBytes(), </SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotSupportedException();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Marshal.Copy(pBlobData, blobData, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">, lVal);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> blobData;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_LPSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringAnsi(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_LPWSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringUni(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UNKNOWN:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.GetObjectForIUnknown(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_DISPATCH:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> p;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">default</SPAN><SPAN style="COLOR: #000000">:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotSupportedException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">The type of this variable is not support ('</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> vt.ToString() </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">')</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</SPAN></P></DIV>
<P>All I do here is determine the type of the data, then return the proper value, referencing my private properties for conversions. For some of the types, I do some special handling. For example, the string types need to allocate managed strings from the native strings, and for the VT_UNKNOWN type I get the COM object that the IUnknown pointer references. Also, the VT_BLOB type is handled so that it gets the size of the data, then allocates a managed byte array to copy the data into. For this type, we have to take into account the architecture.</P>
<H4>Cleaning Things Up</H4>
<P>Because I don't rely on marshaling to clean up unmanaged memory, I need to provide a mechanism to make sure it gets cleaned up. Unfortunately, I can't add a finalizer to the struct to ensure its proper deallocation, but I can provide a method that depends on the user to call when finished with the value:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:d99bac35-5314-4ee7-bf7f-f9f6309830e2 class=wlWriterEditableSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    [DllImport(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">ole32.dll</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">)]
    </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">extern</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> PropVariantClear(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> PropVariant pvar);

    </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> Clear()
    {
        </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Can't pass "this" by ref, so make a copy to call PropVariantClear with</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">        PropVariant var </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000">;
        PropVariantClear(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> var);

        </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Since we couldn't pass "this" by ref, we need to clear the member fields manually
        </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> NOTE: PropVariantClear already freed heap data for us, so we are just setting
        </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">       our references to null.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">        vt </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000">)VarEnum.VT_EMPTY;
        wReserved1 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wReserved2 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wReserved3 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;
        p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> IntPtr.Zero;
        p2 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;
    }
</SPAN></DIV></PRE></DIV>
<P>NOTE: I could have implemented the structure as a class in order to implement a finalizer and IDisposable, then require the MarshalAs attribute to marshal as an UnmanagedType.LPStruct, but that would require the user to initialize the class before use. The usage pattern would also be changed for reusing the object for multiple calls. If you were to reuse the object, the fields would be overwritten without being properly deallocated first. This can happen when using a struct, too, but by using the pattern I chose, you are always expected to call the Clear function, whereas with a class, you only have to call it when reusing the object. The inconsistency is what made me settle on using a struct.</P>
<H4>Using the PropVariant struct</H4>
<P>Using the struct is easy. The usage is similar to the Dispose pattern, however we can't utilize the using keyword. Using the above example method, we can call it like this:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:b83e9339-e088-40b3-9746-6269a277701b class=wlWriterEditableSmartContent><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; PropVariant propVar;<BR>&nbsp;&nbsp;&nbsp; GetProp(</SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> propVar);<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> value </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> propVar.Value;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">finally</SPAN><SPAN style="COLOR: #000000"> { propVar.Clear(); }</SPAN></DIV>
<P mce_keep="true">If you don't call Clear, and the PROPVARIANT contains a pointer to some data, you *will* have a memory leak.</P>
<P>For reusing the variable, you can wrap all your calls in one try..finally block. This is because calling the Clear method on an empty PropVariant does not throw an exception:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:0c23a8f8-cdb2-421e-b944-cab59b790923 class=wlWriterEditableSmartContent><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; PropVariant propVar </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> PropVariant();<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> value;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetProp(</SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> propVar); value </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> propVar.Value;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; propVar.Clear();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> ... use value ...</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetProp(</SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> propVar);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> propVar.Value;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; propVar.Clear();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> ... use value ...</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">finally</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; propVar.Clear();<BR>&nbsp;&nbsp;&nbsp; }</SPAN></DIV>
<H4>Source Code</H4>
<P>I've provided source for the PropVariant struct as a single C# code file. I've also provided a project that has sample usage, using a C++ COM project, plus a test project.</P>
<TABLE class=sourcefiles class="sourcefiles">
<TBODY>
<TR>
<TD class=header class="header">File</TD>
<TD class=header class="header">Description</TD></TR>
<TR>
<TD><A title="View PropVariant.cs" href="http://blogs.msdn.com/adamroot/pages/propvariant-cs.aspx" mce_href="http://blogs.msdn.com/adamroot/pages/propvariant-cs.aspx">View PropVariant.cs</A></TD>
<TD>View the PropVarient implementation online.</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Interop%20with%20PROPVARIANTs/PropVariant.cs" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>Download the PropVariant implementation as a single C# code file.</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Interop%20with%20PROPVARIANTs/VariantInterop.zip" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>A solution with the PropVariant project, a C++ COM project for usage testing, a C# project for usage testing, and a test project for unit tests.</TD></TR></TBODY></TABLE>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Interop with PROPVARIANTs in .NET</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/interop-with-propvariants-in-net-2</link>
      <pubDate>Fri, 11 Apr 2008 13:41:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2008/04/11/interop-with-propvariants-in-net-2/</guid>
      <description><![CDATA[When it comes interop, .NET has solved most of the hard problems. However, if you've worked with COM...]]></description>
      <content:encoded><![CDATA[<P>When it comes interop, .NET has solved most of the hard problems. However, if you've worked with COM interfaces that return or take PROPVARIANTs as parameters, you may have noticed that there isn't much support for this union'd struct type. I came across one such interface, and needed a good way to interop with its PROPVARIANT parameters. In fact, the implementation I was working with returned BLOBs, which break all sorts of basic implementations of variant interop.</P>
<P>Of course, PROPVARIANTs are used in other places than just COM. You may find yourself using P/Invoke with PROPVARIANT params, as well.</P>
<P><A title="Interop with PROPVARIANTs in .NET" href="http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx" mce_href="http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx">Read More ...</A></P>]]></content:encoded>
    </item>
    <item>
      <title>PropVariant.cs</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/propvariant-cs</link>
      <pubDate>Fri, 11 Apr 2008 13:33:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2008/04/11/propvariant-cs/</guid>
      <description><![CDATA[Back to Interop with PROPVARIANTs in .NET

namespace...]]></description>
      <content:encoded><![CDATA[<P>Back to <A class="" title="Interop with PROPVARIANTs in .NET" href="http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx">Interop with PROPVARIANTs in .NET</A></P>
<P mce_keep="true">
<DIV class=wlWriterEditableSmartContent id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a767a0e0-3eef-49a5-9efc-8dbd7e24adca style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"><SPAN style="COLOR: #0000ff">namespace</SPAN><SPAN style="COLOR: #000000"> System.Runtime.InteropServices.ComTypes<BR>{<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> System;<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> System.Runtime.InteropServices;<BR><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Represents the OLE struct PROPVARIANT.<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;remarks&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Must call Clear when finished to avoid memory leaks. If you get the value of<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a VT_UNKNOWN prop, an implicit AddRef is called, thus your reference will<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> be active even after the PropVariant struct is cleared.<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/remarks&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp; [StructLayout(LayoutKind.Sequential)]<BR>&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> PropVariant<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">#region</SPAN><SPAN style="COLOR: #000000"> struct fields</SPAN><SPAN style="COLOR: #000000"><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> The layout of these elements needs to be maintained.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> NOTE: We could use LayoutKind.Explicit, but we want<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to maintain that the IntPtr may be 8 bytes on<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64-bit architectures, so we'll let the CLR keep<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; us aligned.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> NOTE: In order to allow x64 compat, we need to allow for<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expansion of the IntPtr. However, the BLOB struct<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uses a 4-byte int, followed by an IntPtr, so<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; although the p field catches most pointer values,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; we need an additional 4-bytes to get the BLOB<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pointer. The p2 field provides this, as well as<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the last 4-bytes of an 8-byte value on 32-bit<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; architectures.<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> This is actually a VarEnum value, but the VarEnum type<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> shifts the layout of the struct by 4 bytes instead of the<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> expected 2.</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> vt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> wReserved3;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr p;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> p2;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">#endregion</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> struct fields</SPAN><SPAN style="COLOR: #000000"><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">#region</SPAN><SPAN style="COLOR: #000000"> union members</SPAN><SPAN style="COLOR: #000000"><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">sbyte</SPAN><SPAN style="COLOR: #000000"> cVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> CHAR cVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">sbyte</SPAN><SPAN style="COLOR: #000000">)GetDataBytes()[</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">]; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000"> bVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> UCHAR bVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> GetDataBytes()[</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">]; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">short</SPAN><SPAN style="COLOR: #000000"> iVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> SHORT iVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt16(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000"> uiVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> USHORT uiVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToUInt16(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> lVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> LONG lVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt32(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">uint</SPAN><SPAN style="COLOR: #000000"> ulVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> ULONG ulVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToUInt32(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000"> hVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> LARGE_INTEGER hVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToInt64(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">ulong</SPAN><SPAN style="COLOR: #000000"> uhVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> ULARGE_INTEGER uhVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToUInt64(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">float</SPAN><SPAN style="COLOR: #000000"> fltVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> FLOAT fltVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToSingle(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">double</SPAN><SPAN style="COLOR: #000000"> dblVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> DOUBLE dblVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> BitConverter.ToDouble(GetDataBytes(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">bool</SPAN><SPAN style="COLOR: #000000"> boolVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> VARIANT_BOOL boolVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> (iVal </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000"> : </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> scode </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> SCODE scode;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> lVal; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">decimal</SPAN><SPAN style="COLOR: #000000"> cyVal </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> CY cyVal;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">decimal</SPAN><SPAN style="COLOR: #000000">.FromOACurrency(hVal); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DateTime date </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> DATE date;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> DateTime.FromOADate(dblVal); }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">#endregion</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> union members</SPAN><SPAN style="COLOR: #000000"><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Gets a byte array containing the data bits of the struct.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;returns&gt;</SPAN><SPAN style="COLOR: #008000">A byte array that is the combined size of the data bits.</SPAN><SPAN style="COLOR: #808080">&lt;/returns&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] GetDataBytes()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] ret </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[IntPtr.Size </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p.ToInt32()).CopyTo(ret, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">8</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p.ToInt64()).CopyTo(ret, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitConverter.GetBytes(p2).CopyTo(ret, IntPtr.Size);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> ret;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Called to properly clean up the memory referenced by a PropVariant instance.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">ole32.dll</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">)]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">extern</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> PropVariantClear(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> PropVariant pvar);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Called to clear the PropVariant's referenced and local memory.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;remarks&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> You must call Clear to avoid memory leaks.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/remarks&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> Clear()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Can't pass "this" by ref, so make a copy to call PropVariantClear with</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PropVariant var </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PropVariantClear(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> var);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Since we couldn't pass "this" by ref, we need to clear the member fields manually<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> NOTE: PropVariantClear already freed heap data for us, so we are just setting<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; our references to null.</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vt </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">ushort</SPAN><SPAN style="COLOR: #000000">)VarEnum.VT_EMPTY;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wReserved1 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wReserved2 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wReserved3 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> IntPtr.Zero;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p2 </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Gets the variant type.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> VarEnum Type<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"> { </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> (VarEnum)vt; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Gets the variant value.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #808080"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> Value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">get</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> TODO: Add support for reference types (ie. VT_REF | VT_I1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> TODO: Add support for safe arrays</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">switch</SPAN><SPAN style="COLOR: #000000"> ((VarEnum)vt)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> cVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> bVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> iVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> uiVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_INT:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> lVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UINT:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> ulVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_I8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> hVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UI8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> uhVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_R4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> fltVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_R8:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> dblVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BOOL:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> boolVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_ERROR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> scode;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_CY:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> cyVal;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_DATE:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> date;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_FILETIME:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> DateTime.FromFileTime(hVal);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringBSTR(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_BLOB:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] blobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[lVal];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr pBlobData;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pBlobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> IntPtr(p2);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IntPtr.Size </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">8</SPAN><SPAN style="COLOR: #000000">)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> In this case, we need to derive a pointer at offset 12,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> because the size of the blob is represented as a 4-byte int<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> but the pointer is immediately after that.</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pBlobData </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> IntPtr(BitConverter.ToInt64(GetDataBytes(), </SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotSupportedException();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Marshal.Copy(pBlobData, blobData, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">, lVal);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> blobData;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_LPSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringAnsi(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_LPWSTR:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.PtrToStringUni(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_UNKNOWN:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> Marshal.GetObjectForIUnknown(p);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"> VarEnum.VT_DISPATCH:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> p;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">default</SPAN><SPAN style="COLOR: #000000">:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotSupportedException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">The type of this variable is not support ('</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> vt.ToString() </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">')</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR></SPAN></DIV>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Shell Style Drag and Drop in .NET - Part 3</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/shell-style-drag-and-drop-in-net-part-3</link>
      <pubDate>Tue, 19 Feb 2008 06:47:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2008/02/19/shell-style-drag-and-drop-in-net-part-3/</guid>
      <description><![CDATA[Series Links
This is part of a 3 part series:

Shell Style Drag and Drop in .NET (WPF and...]]></description>
      <content:encoded><![CDATA[<H4>Series Links</H4>
<P>This is part of a 3 part series:</P>
<OL>
<LI><A title="Shell Style Drag and Drop in .NET (WPF and WinForms)" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx">Shell Style Drag and Drop in .NET (WPF and WinForms)</A> 
<LI><A title="Shell Style Drag and Drop in .NET - Part 2" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-2.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-2.aspx">Shell Style Drag and Drop in .NET - Part 2</A> 
<LI>Shell Style Drag and Drop in .NET - Part 3</LI></OL>
<H5><IMG align=right src="http://mdjvpg.bay.livefilestore.com/y1pjD7Rg2SxO5sBaY_SnLA1EtrThbdW7eW0AmVc9s1dhd6YYglKbQd44sWCH3QIjXgz29dW8t1KklxJ2jA5T5as8Q/Drop%20Description%20in%20Windows%20Explorer.jpg">Introduction</H5>
<P>In Part 1, <A title="Shell Style Drag and Drop in .NET (WPF and WinForms)" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx">Shell Style Drag and Drop in .NET (WPF and WinForms)</A>, I opened up the discussion about implementing a nice Shell style drag image, like that of Windows Explorer, in C#. This involved exposing a couple of COM interfaces to .NET, as well as implementing the COM IDataObject interface. In <A title="Shell Style Drag and Drop in .NET - Part 2" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-2.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-2.aspx">Shell Style Drag and Drop in .NET - Part 2</A> I took it to the next step, implementing some extension methods and a helper class. These made it easy to use the COM interfaces to achieve Shell integration.</P>
<P>In Part 3, I will open the door even wider. My aim is to achieve complete Shell integration. First, I will look at adding a drop description. This is the little preview text that tells you what you would do by dropping at the current location. It is a dynamic text with an icon, indicating whether you are moving, copying, linking, etc. Then I'll look at handling all the drag source plumbing in a consistent fashion through the use of a new class, the DragSourceHelper. Unlike the DropTargetHelper class from Part 2, the DragSourceHelper actually has a decent amount of work to do.</P>
<H5>Background</H5>
<P>In Parts 1 and 2 I utilized the IDragSourceHelper COM interface exposed by the Windows Shell. In this part we will take a look at IDragSourceHelper2, which inherits IDragSourceHelper and exposed an additional function, SetFlags, for allowing drop descriptions.</P>
<UL>
<LI><A title=IDragSourceHelper2 href="http://msdn2.microsoft.com/en-us/library/bb762030(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb762030(VS.85).aspx">IDragSourceHelper2</A> - Exposes a method that adds functionality to <A title=IDragSourceHelper href="http://msdn2.microsoft.com/en-us/library/bb762034(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb762034(VS.85).aspx">IDragSourceHelper</A>. This method sets the characteristics of a drag-and-drop operation over an IDragSourceHelper object.</LI></UL>
<P>The interface, like IDragSourceHelper, is implemented by the system DragDropHelper class, which is CoCreated using CLSID_DragDropHelper.</P>
<H5></H5>
<H5>The Solution</H5>
<P>The solution for this post is quite large, because we are bringing everything together for a complete solution. The solution comes in several parts, in each of which we'll address a major requirement for the overall solution. </P>
<H6>Finishing the Implementation with Drop Descriptions</H6>
<P>To get drop descriptions working, I need to set a flag on the drag image manager. To do this, I use the IDragSourceHelper2 interface:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:7ba1177b-b23b-44a3-890a-cc67ea10a508 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    [ComVisible(</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">)]
    [ComImport]
    [Guid(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">83E07D0D-0C5F-4163-BF1A-60B274051E40</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000"> IDragSourceHelper2
    {
        </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> InitializeFromBitmap(
            [In, MarshalAs(UnmanagedType.Struct)] </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> ShDragImage dragImage,
            [In, MarshalAs(UnmanagedType.Interface)] IDataObject dataObject);

        </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> InitializeFromWindow(
            [In] IntPtr hwnd,
            [In] </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> Win32Point pt,
            [In, MarshalAs(UnmanagedType.Interface)] IDataObject dataObject);

        </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetFlags(
            [In] </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> dwFlags);
    }
</SPAN></DIV></PRE></DIV>
<P>The IDragSourceHelper2 interface provides the SetFlags function. <A title="SetFlags on MSDN" href="http://msdn2.microsoft.com/en-us/library/bb762033(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb762033(VS.85).aspx">According to MSDN</A>, there is only one flag accepted by this function, and that is DSH_ALLOWDROPDESCRIPTIONTEXT which is defined in shlobjidl.h as 0x1. We will utilize this method solely to enable drop descriptions.</P>
<P>I also need to introduce a native structure, DROPDESCRIPTION, as a managed structure:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:b1d06456-b239-4939-a353-89d01e6e4fac class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    [StructLayout(LayoutKind.Sequential, CharSet </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> CharSet.Unicode, Size </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">1044</SPAN><SPAN style="COLOR: #000000">)]
    </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000"> DropDescription
    {
        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> type;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">260</SPAN><SPAN style="COLOR: #000000">)]
        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> szMessage;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">260</SPAN><SPAN style="COLOR: #000000">)]
        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> szInsert;
    }</SPAN></DIV></PRE></DIV>
<P>Note that the size of the szMessage and szInsert fields is limited to 260 Unicode characters during marshaling. When I set the drop description, this is the structure that I need to set onto the IDataObject for the drag image manager to read and render from.</P>
<P>I also need a new enum, which I've introduced separately in the System.Windows and System.Windows.Forms namespaces for ease of use:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:ac3fb4b3-1826-4b14-a838-46fe968da279 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">enum</SPAN><SPAN style="COLOR: #000000"> DropImageType
    {
        Invalid </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">,
        None </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">,
        Copy </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)DragDropEffects.Copy,
        Move </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)DragDropEffects.Move,
        Link </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)DragDropEffects.Link,
        Label </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">6</SPAN><SPAN style="COLOR: #000000">,
        Warning </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">7</SPAN><SPAN style="COLOR: #000000">
    }
</SPAN></DIV></PRE></DIV>
<P>Not much to say here. These are the values for the "type" field on the DropDescription structure. Many of the values correlate directly to the DragDropEffects enum.</P>
<P>To set the drop description on the data object, I introduce an extension method to the SWF and WPF IDataObject interfaces. As in previous parts, I will use the SWF implementation in my examples:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:e3be5bd9-3f2e-48f2-ab43-bc5ec9020b31 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetDropDescription(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDataObject dataObject, DropImageType type, </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> format, </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> insert)
        {
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (format </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">&amp;&amp;</SPAN><SPAN style="COLOR: #000000"> format.Length </SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">259</SPAN><SPAN style="COLOR: #000000">)
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ArgumentException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Format string exceeds the maximum allowed length of 259.</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">format</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (insert </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">&amp;&amp;</SPAN><SPAN style="COLOR: #000000"> insert.Length </SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">259</SPAN><SPAN style="COLOR: #000000">)
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ArgumentException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Insert string exceeds the maximum allowed length of 259.</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">insert</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Fill the structure</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            DropDescription dd;
            dd.type </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)type;
            dd.szMessage </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> format;
            dd.szInsert </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> insert;

            ComTypes.ComDataObjectExtensions.SetDropDescription((ComTypes.IDataObject)dataObject, dd);
        }
</SPAN></DIV></PRE></DIV>
<P>Here I accept a DropImageType enum value, a format string and an insert string. See the documentation for <A title="DROPDESCRIPTION on MSDN" href="http://msdn2.microsoft.com/en-us/library/bb773268(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb773268(VS.85).aspx">DROPDESCRIPTION on MSDN</A> for details about format and insert, but basically know that you can specify a format like "Move to %1" where "%1" gets replaced with the insert string upon rendering. This is to distinguish the verb from the location, for example. The drag image manager renders the parts of the drop description slightly different to achieve the distinction.</P>
<P>This method leaves some of the work to the ComDataObjectExtensions.SetDropDescription method, which is actually an extension method for the COM IDataObject interface. I separated the logic like this because my SWF and WPF implementations can both take advantage of it. Let's look at that method now:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:58fedac3-e809-4bee-9dfc-45b9c0bf77be class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetDropDescription(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDataObject dataObject, DropDescription dropDescription)
        {
            ComTypes.FORMATETC formatETC;
            FillFormatETC(DropDescriptionFormat, TYMED.TYMED_HGLOBAL, </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> formatETC);

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We need to set the drop description as an HGLOBAL.
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Allocate space ...</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            IntPtr pDD </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Marshal.AllocHGlobal(Marshal.SizeOf(</SPAN><SPAN style="COLOR: #0000ff">typeof</SPAN><SPAN style="COLOR: #000000">(DropDescription)));
            </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> ... and marshal the data</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                Marshal.StructureToPtr(dropDescription, pDD, </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">);

                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> The medium wraps the HGLOBAL</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                System.Runtime.InteropServices.ComTypes.STGMEDIUM medium;
                medium.pUnkForRelease </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;
                medium.tymed </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> ComTypes.TYMED.TYMED_HGLOBAL;
                medium.unionmember </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> pDD;

                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Set the data</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                ComTypes.IDataObject dataObjectCOM </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (ComTypes.IDataObject)dataObject;
                dataObjectCOM.SetData(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> formatETC, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> medium, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);
            }
            </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> If we failed, we need to free the HGLOBAL memory</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                Marshal.FreeHGlobal(pDD);
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000">;
            }
        }
</SPAN></DIV></PRE></DIV>
<P>In this method I marshal the structure to an HGLOBAL and then set the data on the COM IDataObject instance.</P>
<P>Ok, there is one last thing to do, which is a bit more obscure. For the drag image manager to properly re-render the drag image with changing drop descriptions, I need to invalidate the drag image by sending a Window message to the drag window. The drag manager provides the drag window's HWND in the data format "DragWindow" on my IDataObject, so I can grab that and call the SendMessage Win32 API:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:0d3967c8-26a4-436d-82b0-b1489f2c2b60 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">const</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">uint</SPAN><SPAN style="COLOR: #000000"> WM_INVALIDATEDRAGIMAGE </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">0x403</SPAN><SPAN style="COLOR: #000000">;

        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> InvalidateDragImage(IDataObject dataObject)
        {
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (dataObject.GetDataPresent(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">DragWindow</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">))
            {
                IntPtr hwnd </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> GetIntPtrFromData(dataObject.GetData(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">DragWindow</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">));
                PostMessage(hwnd, WM_INVALIDATEDRAGIMAGE, IntPtr.Zero, IntPtr.Zero);
            }
        }

        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> IntPtr GetIntPtrFromData(</SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> data)
        {
            </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] buf </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;

            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (data </SPAN><SPAN style="COLOR: #0000ff">is</SPAN><SPAN style="COLOR: #000000"> MemoryStream)
            {
                buf </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">];
                </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> ((MemoryStream)data).Read(buf, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">))
                    </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ArgumentException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Could not read an IntPtr from the MemoryStream</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);
            }
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (data </SPAN><SPAN style="COLOR: #0000ff">is</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[])
            {
                buf </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[])data;
                </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (buf.Length </SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)
                    </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ArgumentException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Could not read an IntPtr from the byte array</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);
            }

            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (buf </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">)
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ArgumentException(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Could not read an IntPtr from the </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> data.GetType().ToString());

            </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (buf[</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">] </SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">24</SPAN><SPAN style="COLOR: #000000">) </SPAN><SPAN style="COLOR: #000000">|</SPAN><SPAN style="COLOR: #000000"> (buf[</SPAN><SPAN style="COLOR: #000000">2</SPAN><SPAN style="COLOR: #000000">] </SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">16</SPAN><SPAN style="COLOR: #000000">) </SPAN><SPAN style="COLOR: #000000">|</SPAN><SPAN style="COLOR: #000000"> (buf[</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">] </SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">8</SPAN><SPAN style="COLOR: #000000">) </SPAN><SPAN style="COLOR: #000000">|</SPAN><SPAN style="COLOR: #000000"> buf[</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">];
            </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> IntPtr(p);
        }
</SPAN></DIV></PRE></DIV>
<P>You won't find WM_INVALIDATEDRAGIMAGE in documentation, its value is actually WM_USER + 3. I don't remember where I found this, but it works. Would be interesting to know if there are other messages that the drag window accepts to get around some of the problems I'll touch on later.</P>
<P>This InvalidateDragImage method should be called by your drag source's GiveFeedback event handler. I'll walk you through a more complete GiveFeedback event handler later when I talk about the DragSourceHelper class.</P>
<P><STRONG>Drop Descriptions Summary</STRONG></P>
<P>Well, that's that. With these new foundations, I can enable and set drop descriptions for my drag images in my application. To enable the drop descriptions, I need to make sure to call SetFlags with an argument of 1 <STRONG>before</STRONG> I set the drag image via IDragSourceHelper.InitializeFromBitmap or IDragSourceHelper.InitializeFromWindow. To set the drop description, during DragEnter or DragOver events I can call e.Data.SetDropDescription with my desired arguments. The last thing to remember is that the drag source needs to listen to the GiveFeedback event and invalidate the drag window.</P>
<H6>What Happened to the Managed SetData?</H6>
<P>In Parts 1 and 2 when I implemented the COM IDataObject and set it as the inner data store for the SWF and WPF DataObjects, I forgot to address one issue. Both the SWF and WPF versions of DataObject implement both the respective IDataObject and the COM IDataObject. The reason I had to implement the COM IDataObject myself is that the .NET DataObjects don't allow setting data by calling the COM IDataObject.SetData method. They throw a COMException with E_NOTIMPL, which is basically a NotImplementedException. That prevented me from being able to use the .NET DataObjects because the Shell DragDropHelper requires the ability to call that COM callable method to store information for the drag image manager. However, the .NET DataObjects do allow you to provide a COM IDataObject to the constructors, and then would allow me to pass COM calls to the wrapped object directly. That is exactly how I implemented my solution.</P>
<P>(Note: I use ".NET SetData" and "COM SetData" to distinguish the SetData methods exposed by the .NET IDataObject and COM IDataObject respectively. The .NET SetData method is the one you, as a .NET developer, usually call. The COM SetData method is the one that is exposed by the COM IDataObject and is COM-callable. Also, where I've used SWF and/or WPF in the past, I will summarize as just ".NET". The two implementations of data objects are very very similar. So, when I say ".NET IDataObject interface(s)" I mean SWF or WPF, they are pretty much interchangable.)</P>
<P>Well, that put a new block on me. Now, the .NET DataObject that wrapped my COM IDataObject doesn't allow a .NET SetData call. It throws an InvalidOperationException. It is actually an internal converter class that throws the exception. The internal converter class implements the .NET IDataObject interface, and receives the .NET SetData call, but does nothing except throw an exception. The converter class gets created when I pass the COM IDataObject to the constructor of the .NET DataObject, which holds onto it as an internal data store, instead of the default internal data store. I drew up a diagram to show where my .NET SetData calls get blocked:</P>
<P align=center><IMG src="http://mdjvpg.bay.livefilestore.com/y1pjD7Rg2SxO5t_GRse4orpTLalGu0BkQXUeAH5iI1OozFVNX2QE6oMXeAgDNKMOev49Ud4mlJ-pntFna3kJb7pZQ/Wrapped%20COM%20IDataObject%20Diagram.png">&nbsp;<BR>COM IDataObject Wrapped by .NET DataObject</P>
<P>Notice that there is a converter data object wrapping the COM IDataObject, and that is where the .NET SetData call fails. All other GetData and SetData calls go through as expected.</P>
<P>So, why not just implement the .NET IDataObject as well? Well, I certainly went down that path. Unfortunately, when you call DoDragDrop, which accepts the .NET IDataObject interface, as opposed to the DataObject class, somewhere along the line it gets wrapped by a .NET DataObject anyway. This wouldn't be a big deal, except there is another problem. The .NET DataObject classes seem to be less robust than I think they were intended. When I pass an instance of a class that implements both the .NET IDataObject interface as well as the COM IDataObject interface to the constructor, the .NET DataObject recognizes it as a .NET IDataObject and references it directly as its internal data store. That's great! Right? Well, no. The COM SetData method of the .NET DataObjects, as you can see in the above diagram, get a direct reference to the COM IDataObject of the internal converter data object class. Well, if the internal data store isn't of that type, then it will throw an exception, the same one I saw that made me implement the COM IDataObject interface to begin with. Here is a diagram showing this situation:</P>
<P align=center><IMG src="http://mdjvpg.bay.livefilestore.com/y1pjD7Rg2SxO5tvXUB_Ps5ZcaSMqiouNw0mN_td1vyeAmqSd_Bv8yV8at1N83yT21vVntvBFbHOz_4WcdN2ZjSy_A/Wrapped%20dotNET%20IDataObject%20Diagram.png"> <BR>.NET/COM IDataObject Wrapped by .NET DataObject</P>
<P>As you can see, by the .NET DataObject classes not noticing that the internal data store is a COM IDataObject as well as a .NET IDataObject, I can't utilize both versions of SetData. So now what? Well, we only really have one choice. Because we <STRONG>require</STRONG> the COM SetData to function, we need to accept the fact that the .NET SetData won't. At least, not directly. Luckily, I have complete control, as the creator of the DataObject, and so I'll just write a new extension function, SetDataEx, which will accept managed data, marshal it to an HGLOBAL, and set it using the COM SetData. Let's get to it!</P>
<P>I don't need a completely robust solution, because in many cases, I can use the .NET DataObject classes as a converter. But I'll come back to that in a bit. For now, I need a function that takes managed data, marshals it, and sets it to the COM IDataObject using the COM SetData method. This seems like a great candidate for an extension method on the COM IDataObject interface, so that's exactly how I'll implement it. Note, this is <STRONG>not</STRONG> the same as the SetDataEx function I mentioned, which will use this method internally:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:add9e6a5-869b-4605-a199-68c26a22f473 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetManagedData(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDataObject dataObject, </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> format, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> data)
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Initialize the format structure</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            ComTypes.FORMATETC formatETC;
            FillFormatETC(format, TYMED.TYMED_HGLOBAL, </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> formatETC);

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Serialize/marshal our data into an unmanaged medium</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            ComTypes.STGMEDIUM medium;
            GetMediumFromObject(data, </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> medium);
            </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Set the data on our data object</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                dataObject.SetData(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> formatETC, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> medium, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);
            }
            </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> On exceptions, release the medium</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                ReleaseStgMedium(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> medium);
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000">;
            }
        }
</SPAN></DIV></PRE></DIV>
<P>This method really handles just the conversion of a string format to the FORMATETC structure. The meat of the marshaling is in the GetMediumFromObject function:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:db69a19c-1312-4c9a-b064-29d83e668ae4 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> GetMediumFromObject(</SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> data, </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> STGMEDIUM medium)
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We'll serialize to a managed stream temporarily</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            MemoryStream stream </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> MemoryStream();

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Write an indentifying stamp, so we can recognize this as custom
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> marshaled data.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            stream.Write(ManagedDataStamp.ToByteArray(), </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">, Marshal.SizeOf(</SPAN><SPAN style="COLOR: #0000ff">typeof</SPAN><SPAN style="COLOR: #000000">(Guid)));

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Now serialize the data. Note, if the data is not directly serializable,
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> we'll try type conversion. Also, we serialize the type. That way,
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> during deserialization, we know which type to convert back to, if
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> appropriate.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            BinaryFormatter formatter </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> BinaryFormatter();
            formatter.Serialize(stream, data.GetType());
            formatter.Serialize(stream, GetAsSerializable(data));

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Now copy to an HGLOBAL</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[] bytes </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> stream.GetBuffer();
            IntPtr p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Marshal.AllocHGlobal(bytes.Length);
            </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
            {
                Marshal.Copy(bytes, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">, p, bytes.Length);
            }
            </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Make sure to free the memory on exceptions</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                Marshal.FreeHGlobal(p);
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000">;
            }

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Now allocate an STGMEDIUM to wrap the HGLOBAL</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            medium.unionmember </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> p;
            medium.tymed </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> ComTypes.TYMED.TYMED_HGLOBAL;
            medium.pUnkForRelease </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;
        }
</SPAN></DIV></PRE></DIV>
<P>I just create a MemoryStream, which I will serialize my object to, and then write an internally defined GUID to it. This GUID is a stamp for my code to recognize the data by when I go to get the data. I didn't mention it before, but the .NET GetData will only partially work for me. If a type is serializable (implements ISerializable or is marked by the SerializableAttribute) then the .NET GetData method will still work. If not, I'll have to use another new function, GetDataEx to get my data. We'll see that later. After the stamp, I serialize the type, which I'll need during deserialization because the actual data I serialize may be converted. Then, I use a helper method, GetAsSerializable, that will determine if the data's type is serializable, and if not, will try to convert it to a string using a type converter that the type may have declared through the TypeConverterAttribute. I won't show that code here, because it isn't directly relevant to drag and drop. Finally, I allocate an HGLOBAL and fill the STGMEDIUM structure before returning.</P>
<P>The SetDataEx function is an extension method on the .NET IDataObject interfaces:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:60dc934d-1ed7-4aa9-9312-141ef6a8c3a8 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetDataEx(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDataObject dataObject, </SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000"> format, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> data)
        {
            DataFormats.Format dataFormat </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> DataFormats.GetFormat(format);

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Initialize the format structure</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            ComTypes.FORMATETC formatETC </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ComTypes.FORMATETC();
            formatETC.cfFormat </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #0000ff">short</SPAN><SPAN style="COLOR: #000000">)dataFormat.Id;
            formatETC.dwAspect </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> ComTypes.DVASPECT.DVASPECT_CONTENT;
            formatETC.lindex </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">;
            formatETC.ptd </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> IntPtr.Zero;

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Try to discover the TYMED from the format and data</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            ComTypes.TYMED tymed </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> GetCompatibleTymed(format, data);
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> If a TYMED was found, we can use the system DataObject
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> to convert our value for us.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (tymed </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> ComTypes.TYMED.TYMED_NULL)
            {
                formatETC.tymed </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> tymed;

                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Set data on an empty DataObject instance</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                DataObject conv </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DataObject();
                conv.SetData(format, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">, data);

                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Now retrieve the data, using the COM interface.
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> This will perform a managed to unmanaged conversion for us.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                ComTypes.STGMEDIUM medium;
                ((ComTypes.IDataObject)conv).GetData(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> formatETC, </SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000"> medium);
                </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
                {
                    </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Now set the data on our data object</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                    ((ComTypes.IDataObject)dataObject).SetData(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> formatETC, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> medium, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);
                }
                </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000">
                {
                    </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> On exceptions, release the medium</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                    ReleaseStgMedium(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> medium);
                    </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000">;
                }
            }
            </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Since we couldn't determine a TYMED, this data
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> is likely custom managed data, and won't be used
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> by unmanaged code, so we'll use our custom marshaling
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> implemented by our COM IDataObject extensions.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">
                ComTypes.ComDataObjectExtensions.SetManagedData((ComTypes.IDataObject)dataObject, format, data);
            }
        }
</SPAN></DIV></PRE></DIV>
<P>There <EM>is</EM> a little bit of magic here. You'll see that I call the SetManagedData function at the end of SetDataEx as a last resort only. The rest of the code actually uses a temporary .NET DataObject instance to act as a converter. First I fill a FORMATETC structure for my desired format. Then I attempt to determine the TYMED based on the format name and data. The method GetCompatibleType is uninteresting, and is based on reflection of the .NET DataObject conversion capabilities. ("Compatible" means that it can be converted during a COM GetData call to the .NET DataObject.) It is slightly different for SWF and WPF, but is largely the same. Once I determine a compatible type, I set the data on the temporary .NET DataObject using its .NET SetData method, then call the COM GetData method, which will do marshaling according to the format and type of data. Then, since the marshaling is done, I can just set the data onto the real data object through the COM SetData method. Notice, only if I fail to determine a compatible TYMED do I do my own marshaling using SetManagedData.</P>
<P><STRONG>Managed SetData Summary</STRONG></P>
<P>Now that SetDataEx is in place, it can be used like the .NET SetData method. The only catch is that the data must be either serializable, or have an associated TypeConverter that supports conversion to/from a string. The GetData function will still work other than when the data's type is not serializable. In that case, you can call GetDataEx, which I won't show here. It basically confirms the stamp, then deserializes the data's type, then the data, and performs conversion through a TypeConverter if necessary.</P>
<H6>The DragSourceHelper</H6>
<P>I've discussed a lot about the heart of the problem and have provided a solid foundation to build a complete solution. However, there are some intricacies to proper implementation that I haven't addressed. We need to handle, as a drag source, the cases when the cursor is over a non-drag image enabled drop target, a drop target that doesn't set the drop description, and the Windows Taskbar (which just throws a curve ball for fun). To handle all this, I've implemented the DragSourceHelper, which is a static class that keeps some smart context to eliminate much of the repetitive client coding and to help you manage drag and drop with less hassle.</P>
<P><STRONG>Default QueryContinueDrag Handler</STRONG></P>
<P>I'll be honest up front. The QueryContinueDrag event seems pointless to me. I don't know when a drag source should ever have control over whether to continue a drag and drop operation. Having said that, there is one thing I could think of, that the system, for whatever reason, doesn't handle. That is the escape key. If the user presses escape during the drag and drop operation, most drag sources will just cancel the operation (or should, anyway). That is what my default handler does:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:3dfc0e4f-d035-4b06-9841-0ef9c946608c class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DefaultQueryContinueDrag(QueryContinueDragEventArgs e)
        {
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (e.EscapePressed)
            {
                e.Action </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> DragAction.Cancel;
            }
        }
</SPAN></DIV></PRE></DIV>
<P>Not much more to say here. This method belongs to my DragSourceHelper class and can be called directly from your QueryContinueDrag event handler, or I also expose a QueryContinueDragEventHandler method, so that you can assign it directly as the handler of your QueryContinueDrag event:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:053195b2-9c76-4be4-85ee-3efc073429f6 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DefaultQueryContinueDragHandler(</SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> sender, QueryContinueDragEventArgs e)
        {
            DefaultQueryContinueDrag(e);
        }
</SPAN></DIV></PRE></DIV>
<P>There isn't anything more to say here. For my implementation, that is about all there is.</P>
<P><STRONG>Default GiveFeedback Handler</STRONG></P>
<P>The GiveFeedback event handler has a lot more to do than the QueryContinueDrag handler. This is because I have several cases I have to cover:</P>
<UL>
<LI>Drop targets that don't support drag images</LI></UL>
<BLOCKQUOTE>
<P>Problem: If I assume all drop targets support drag images and don't make a special case, I'll end up showing them a plain arrow cursor, and the drop action will be completely unknown to the user.</P>
<P>Solution: For drop targets that don't support drag images, the drag image manager provides a piece of data in my data object that let's me know this is the case. The "IsShowingLayered" data format is a boolean value, true to indicate that the drop target is showing the drag image, false to indicate not. If the flag is on, I'll set UseDefaultCursors to false, then explicitly set the arrow cursor as my current mouse cursor. If it is not on, I'll set UseDefaultCursors to true, and I won't set the current cursor explicitly.</P></BLOCKQUOTE>
<UL>
<LI>Drop targets that support drag images but don't set the drop description</LI></UL>
<BLOCKQUOTE>
<P>Problem: These targets talk to the Shell's IDropTargetHelper implementation, but don't set the drop description. For these targets, we can provide a default drop description instead of the out-of-date default drag and drop cursors.</P>
<P>Solution: I can handle this by taking care to handle all drag and drop events properly. For one, during DragLeave, I can make sure to set my drop description as invalid, by using the DropImageType.Invalid type. That is what Windows Explorer does, too, so we are consistent. Next, through GiveFeedback, I can detect this invalid drop description, then look at the current drop effect, set by the drop target, and set a default description. That part is easy, the only thing you have to really worry about is the fact that drop targets that don't set the drop description won't invalidate them either! That means I need to track when I have a default drop description currently set. Then I can detect changes to the drop effect and change the current drop description. I'll do this with a flag that is associated to the IDataObject. Well, I lied. That isn't the only thing to worry about. You also need to detect when, after you set a default drop description, a drop target sets a drop description. This can be caused by the mouse leaving the drop target that doesn't set the drop description and entering a drop target that does. I detect this by implementing an IAdviseSink and listening to DataChanged events on the DataObject. I'll address that in the next section, Adding Support for AdviseSinks to the DataObject.</P></BLOCKQUOTE>
<UL>
<LI>The Windows Taskbar</LI></UL>
<BLOCKQUOTE>
<P>Problem: The Taskbar supports drag images, but doesn't set the drop description. The reason it is in a different category is because it is the most prominent place you'll notice that when you drag over it, from Windows Explorer, the no-smoking icon appears (drop effect None) but you won't see drag text. This is actually true for any drop target that supports drag images, but doesn't set a drop description and has a drop effect of None.</P>
<P>Solution: I can implement this by simply not invalidating the drag image after it has been rendered. That is, if I don't invalidate the drag image, then the drop description's icon will not refresh with the text after a pause. In order to implement this properly, I have to invalidate the drag image once after the drop description is set to None, and then not until it changes again.</P></BLOCKQUOTE>
<P>The handler, after all of these cases are covered, looks like this:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:1b3fba08-ddba-42b9-8c0a-c9340709f910 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DefaultGiveFeedback(IDataObject data, GiveFeedbackEventArgs e)
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> For drop targets that don't set the drop description, we'll
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> set a default one. Drop targets that do set drop descriptions
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> should set an invalid drop description during DragLeave.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">bool</SPAN><SPAN style="COLOR: #000000"> setDefaultDropDesc </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">;
            </SPAN><SPAN style="COLOR: #0000ff">bool</SPAN><SPAN style="COLOR: #000000"> isDefaultDropDesc </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> IsDropDescriptionDefault(data);
            DropImageType currentType </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> DropImageType.Invalid;
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">IsDropDescriptionValid(data) </SPAN><SPAN style="COLOR: #000000">||</SPAN><SPAN style="COLOR: #000000"> isDefaultDropDesc)
            {
                currentType </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> GetDropImageType(data);
                setDefaultDropDesc </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">;
            }

            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (IsShowingLayered(data))
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> The default drag source implementation uses drop descriptions,
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> so we won't use default cursors.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                e.UseDefaultCursors </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">;
                Cursor.Current </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Cursors.Arrow;
            }
            </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">
                e.UseDefaultCursors </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">;

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We need to invalidate the drag image to refresh the drop description.
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> This is tricky to implement correctly, but we try to mimic the Windows
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Explorer behavior. We internally use a flag to tell us to invalidate
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> the drag image, so if that is set, we'll invalidate. Otherwise, we
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> always invalidate if the drop description was set by the drop target,
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> *or* if the current drop image is not None. So if we set a default
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> drop description to anything but None, we'll always invalidate.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (InvalidateRequired(data) </SPAN><SPAN style="COLOR: #000000">||</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">isDefaultDropDesc </SPAN><SPAN style="COLOR: #000000">||</SPAN><SPAN style="COLOR: #000000"> currentType </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> DropImageType.None)
            {
                InvalidateDragImage(data);

                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> The invalidate required flag only lasts for one invalidation</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                SetInvalidateRequired(data, </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">);
            }

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> If the drop description is currently invalid, or if it is a default
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> drop description already, we should check about re-setting it.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (setDefaultDropDesc)
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Only change if the effect changed</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> ((DropImageType)e.Effect </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> currentType)
                {
                    </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (e.Effect </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Copy)
                        data.SetDropDescription(DropImageType.Copy, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Copy</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">""</SPAN><SPAN style="COLOR: #000000">);
                    </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (e.Effect </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Link)
                        data.SetDropDescription(DropImageType.Link, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Link</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">""</SPAN><SPAN style="COLOR: #000000">);
                    </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (e.Effect </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Move)
                        data.SetDropDescription(DropImageType.Move, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Move</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">""</SPAN><SPAN style="COLOR: #000000">);
                    </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (e.Effect </SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.None)
                        data.SetDropDescription(DropImageType.None, </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">);
                    SetDropDescriptionIsDefault(data, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);

                    </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We can't invalidate now, because the drag image manager won't
                    </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> pick it up... so we set this flag to invalidate on the next
                    </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> GiveFeedback event.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                    SetInvalidateRequired(data, </SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);
                }
            }
        }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">You'll notice that I first detect if I will need to set the default description, and get the current drop image type. I don't set the default drop description at this point, because it doesn't make a difference. Calling InvalidateDragImage after setting the drop description here will not truly invalidate the drag image. Next, I determine if the drop target supports drag images via my IsShowingLayered helper function. If so, we won't use default cursors, else we will. Next, we determine if we should invalidate the drag image. Basically, if our flag is set from a previous call, or if the drop description was manually set by the drop target, or the drop description's drop image type is not None, then we'll invalidate, plus clear the flag to invalidate next time. Notice, that only when the None effect is applied do we possibly not invalidate the drag image.</P>
<P><STRONG>Adding Support for AdviseSinks to the DataObject</STRONG></P>
<P>In order for the GiveFeedback handler described above to work as expected, we have to detect when a drop target manually sets a drop description. There are a couple of ways to do this, but the most reliable is to listen to DataChanged events from the IDataObject. The COM IDataObject has a couple of methods that, until now, have been left as unsupported. They are DAdvise and DUnadvise. They are simply methods that enable you to pass an instance of IAdviseSink to listen for data events. The IAdviseSink interface covers advisory tasks for several system components, but for drag and drop, we just need to implement the OnDataChanged method:</P>
<P mce_keep="true">
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:b9ac3fc4-825e-4354-944b-8b462846e604 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000"> AdviseSink : ComTypes.IAdviseSink
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> The associated data object</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> IDataObject data;

            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Creates an AdviseSink associated to the specified data object.
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="data"&gt;</SPAN><SPAN style="COLOR: #008000">The data object.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> AdviseSink(IDataObject data)
            {
                </SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000">.data </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> data;
            }

            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Handles DataChanged events from a COM IDataObject.
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="format"&gt;</SPAN><SPAN style="COLOR: #008000">The data format that had a change.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
            </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="stgmedium"&gt;</SPAN><SPAN style="COLOR: #008000">The data value.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnDataChange(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> ComTypes.FORMATETC format, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> ComTypes.STGMEDIUM stgmedium)
            {
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We listen to DropDescription changes, so that we can unset the IsDefault
                </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> drop description flag.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">                </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> odd </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> ComTypes.ComDataObjectExtensions.GetDropDescription((ComTypes.IDataObject)data);
                </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (odd </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">)
                    DragSourceHelper.SetDropDescriptionIsDefault(data, </SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">);
            }

            </SPAN><SPAN style="COLOR: #0000ff">#region</SPAN><SPAN style="COLOR: #000000"> Unsupported callbacks</SPAN><SPAN style="COLOR: #000000">

            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnClose()
            {
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotImplementedException();
            }

            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnRename(System.Runtime.InteropServices.ComTypes.IMoniker moniker)
            {
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotImplementedException();
            }

            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnSave()
            {
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotImplementedException();
            }

            </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnViewChange(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> aspect, </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000"> index)
            {
                </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> NotImplementedException();
            }

            </SPAN><SPAN style="COLOR: #0000ff">#endregion</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Unsupported callbacks</SPAN><SPAN style="COLOR: #000000">
        }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">Because we only care about DropDescription changes, we will connect an instance of the AdviseSink class for notifications of that format only. The OnDataChange function is the callback from the IDataObject and simply verifies the drop description is accessible and then unsets the IsDefault flag for the data object. This tells the DragSourceHelper that this data object no longer has the default drop description.</P>
<P>The drop description flags I've mentioned, IsDefault and InvalidateRequired, are just a couple of internal flags, which I store in a Dictionary keyed on the IDataObject itself. That way I don't need to set internal-only data on the data object.</P>
<P><STRONG>The Do-It-All Functions</STRONG></P>
<P>The DragSourceHelper class isn't too complex, but it is more than I want to go into here. Most of it is just convenient do-it-all or do-it-in-less-lines-of-code functions. Having said that, there are a couple of functions I want to point out. You'll see in the examples, I use the DragSourceHelper.DoDragDrop function. The DoDragDrop function is a one-liner to call for the drag source, and handles <STRONG>all</STRONG> the internal drag and drop logic from the drag source side. The only thing you need to do is prepare a drag image, call DoDragDrop, and then handle the drag drop effect. Of course, for the cases that you need a little more granularity, there are several available functions and overrides to help you get what you need to get done without the hassle. Let's take a look at the DoDragDrop function (I included source for a couple of the called functions for reference):</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:d970c2ea-312c-4238-a49e-c599448af362 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> DragDropEffects DoDragDrop(
            Control control,
            System.Drawing.Point cursorOffset,
            DragDropEffects allowedEffects,
            </SPAN><SPAN style="COLOR: #0000ff">params</SPAN><SPAN style="COLOR: #000000"> KeyValuePair</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">[] data)
        {
            IDataObject dataObject </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> RegisterDefaultDragSource(control, cursorOffset);
            </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> DoDragDropInternal(control, dataObject, allowedEffects, data);
        }

        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> IDataObject RegisterDefaultDragSource(
            Control control, System.Drawing.Point cursorOffset)
        {
            IDataObject data </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> CreateDataObject(control, cursorOffset);
            RegisterDefaultDragSource(control, data);
            </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> data;
        }

        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> RegisterDefaultDragSource(Control control, IDataObject data)
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Cache the drag source and the associated data object</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            DragSourceEntry entry </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragSourceEntry(data);
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">s_dataContext.ContainsKey(control))
                s_dataContext.Add(control, entry);
            </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">
                s_dataContext[control] </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> entry;

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> We need to listen for drop description changes. If a drop target
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> changes the drop description, we shouldn't provide a default one.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            entry.adviseConnection </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> ComTypes.ComDataObjectExtensions.Advise(
                (ComTypes.IDataObject)data, </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> AdviseSink(data), DropDescriptionFormat, </SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Hook up the default drag source event handlers</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            control.GiveFeedback </SPAN><SPAN style="COLOR: #000000">+=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> GiveFeedbackEventHandler(DefaultGiveFeedbackHandler);
            control.QueryContinueDrag </SPAN><SPAN style="COLOR: #000000">+=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> QueryContinueDragEventHandler(DefaultQueryContinueDragHandler);
        }

        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> DragDropEffects DoDragDropInternal(
            Control control, IDataObject dataObject,
            DragDropEffects allowedEffects,
            KeyValuePair</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">[] data)
        {
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> Set the data onto the data object.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (data </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">)
            {
                </SPAN><SPAN style="COLOR: #0000ff">foreach</SPAN><SPAN style="COLOR: #000000"> (KeyValuePair</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"> dataPair </SPAN><SPAN style="COLOR: #0000ff">in</SPAN><SPAN style="COLOR: #000000"> data)
                    dataObject.SetDataEx(dataPair.Key, dataPair.Value);
            }

            </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
            {
                </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> control.DoDragDrop(dataObject, allowedEffects);
            }
            </SPAN><SPAN style="COLOR: #0000ff">finally</SPAN><SPAN style="COLOR: #000000">
            {
                UnregisterDefaultDragSource(control);
            }
        }
</SPAN></DIV></PRE></DIV>
<P>What you'll see is that the DoDragDrop creates an instance of the DataObject, including registering it internally for default GiveFeedback and QueryContinueDrag event handlers and DataChange handler on the DropDescription format. It then adds any data you passed in, and calls the .NET DoDragDop, and then unregisters the event handlers before it returns the result drag drop effect.</P>
<P>This reduces the client code to a one-liner, as in the examples:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:76a8705c-c524-4c58-93df-43491c088766 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        DragSourceHelper.DoDragDrop(button1, </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Point(e.X, e.Y), DragDropEffects.Link </SPAN><SPAN style="COLOR: #000000">|</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Copy,
            </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> KeyValuePair</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">(DataFormats.Text, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Hello Drag and Drop!</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">),
            </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> KeyValuePair</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #0000ff">string</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">(DataFormats.Html, </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;h4&gt;Hello Drag and Drop!&lt;/h4&gt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">));
</SPAN></DIV></PRE></DIV>
<P>In this example, you may have noticed, we are initializing the drag image from the button control itself, instead of a custom bitmap. Other overrides exist to help you achieve your most intriguing drag and drop experience, yet.</P>
<H5>Conclusion</H5>
<P>The last couple of weeks have gone deep into the implementation of a complete Shell-integrated drag and drop experience for your .NET apps. Whether you are working in WinForms or WPF, you can provide great user feedback during drag and drop operations. With WPF, this provides a great base for applications that are highly dynamic in the user experience. In WinForms, you can get that true integration that you've felt like .NET lacked.</P>
<P>I encourage you to use the source provided, although please keep in mind it is Microsoft copyrighted.</P>
<H5>Source Code</H5>
<P>All source for this article is provided below.</P>
<TABLE class=sourcefiles class="sourcefiles">
<TBODY>
<TR>
<TD class=header class="header">File</TD>
<TD class=header class="header">Description</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Shell%20Style%20Drag%20and%20Drop%20in%20.NET%20-%20Part%203/DragDropLib.cs" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>Complete drag and drop library as single CS file. Drop directly into your existing projects. Includes SWF and WPF implementations. No samples.</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Shell%20Style%20Drag%20and%20Drop%20in%20.NET%20-%20Part%203/ShellDragDrop%20Part%203-2.zip" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>Complete set of projects for the drag and drop library. Includes samples. </TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Shell%20Style%20Drag%20and%20Drop%20in%20.NET%20-%20Part%203/ShellDragDrop%20Part%203.zip" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>The above link has an important&nbsp;bug fix, but if you need the original sources, you can download this one. </TD></TR></TBODY></TABLE>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Shell Style Drag and Drop in .NET - Part 2</title>
      <link>https://docs.microsoft.com/archive/blogs/adamroot/shell-style-drag-and-drop-in-net-part-2</link>
      <pubDate>Tue, 19 Feb 2008 06:46:00 GMT</pubDate>
      <dc:creator><![CDATA[Garry Trinder]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/adamroot/2008/02/19/shell-style-drag-and-drop-in-net-part-2/</guid>
      <description><![CDATA[Series Links
This is part of a 3 part series:

Shell Style Drag and Drop in .NET (WPF and...]]></description>
      <content:encoded><![CDATA[<H4>Series Links</H4>
<P>This is part of a 3 part series:</P>
<OL>
<LI><A title="Shell Style Drag and Drop in .NET (WPF and WinForms)" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx">Shell Style Drag and Drop in .NET (WPF and WinForms)</A></LI>
<LI>Shell Style Drag and Drop in .NET - Part 2</LI>
<LI><A title="Shell Style Drag and Drop in .NET - Part 3" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-3.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-part-3.aspx">Shell Style Drag and Drop in .NET - Part 3</A></LI></OL>
<H4>Introduction</H4>
<P>Last week, in <A title="Shell Style Drag and Drop in .NET (WPF and WinForms)" href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx" target=_blank mce_href="http://blogs.msdn.com/adamroot/pages/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx">Shell Style Drag and Drop in .NET (WPF and WinForms)</A>, I looked at hooking up the COM interfaces necessary to implement drag images using the Windows Shell. This week, I'm going to introduce some .NET 3.5 extensions (which can be easily converted into .NET 3.0 and earlier static helper functions) that reduce the code overhead of implementing great drag and drop preview images in your .NET applications.</P>
<P>NOTE: Like last week, this is not an in depth overview of drag and drop in .NET, but instead focuses on utilizing the Shell's drag image manager to develop more tightly integrated drag and drop applications.</P>
<H5>Background</H5>
<P>For those of you who didn't read last week's post (or found it too long), here is a recap of the important COM interfaces:</P>
<UL>
<LI><A title=IDragSourceHelper href="http://msdn2.microsoft.com/en-us/library/bb762034(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb762034(VS.85).aspx">IDragSourceHelper</A> - Exposed by the Shell to allow an application to specify the image that will be displayed during a Shell drag-and-drop operation. 
<LI><A title=IDropTargetHelper href="http://msdn2.microsoft.com/en-us/library/bb762028(VS.85).aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/bb762028(VS.85).aspx">IDropTargetHelper</A> - Exposes methods that allow drop targets to display a drag image while the image is over the target window. 
<LI><A href="http://msdn2.microsoft.com/en-us/library/ms688421.aspx" target=_blank>IDataObject</A> - Specifies methods that enable data transfer and notification of changes in data (we only use it for the former).</LI></UL>
<P>I implemented IDataObject (the COM version, not System.Windows.IDataObject or System.Windows.Forms.IDataObject) and then imported the other interfaces, along with the DragDropHelper class, CoCreated using CLSID_DragDropHelper from the Shell.</P>
<H5>The Extensions</H5>
<P>Unlike last week, I won't take you step by step into the implementation of these extensions. But I will give you an overview of what I've added.</P>
<H6>IDataObject Extensions</H6>
<P>For each System.Windows.IDataObject and System.Windows.Forms.IDataObject, I added several extensions to simplify the initialization of the drag image. Since they are very similar, I'll use System.Windows.Forms as my example, and leave the WPF implementation to be explored by you.</P>
<P>Last week, I used code like this to start the drag and drop operation:</P>
<P mce_keep="true">&nbsp;</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a61ff240-6f3d-4ba4-bdb7-513d2888fe75 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> bt_MouseDown(</SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> sender, MouseEventArgs e)
    {
        Bitmap bmp </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Bitmap(</SPAN><SPAN style="COLOR: #000000">100</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">100</SPAN><SPAN style="COLOR: #000000">, PixelFormat.Format32bppArgb);
        </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> (Graphics g </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Graphics.FromImage(bmp))
        {
            g.Clear(Color.Magenta);
            </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> (Pen pen </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Pen(Color.Blue, 4f))
            {
                g.DrawEllipse(pen, </SPAN><SPAN style="COLOR: #000000">20</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">20</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">60</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">60</SPAN><SPAN style="COLOR: #000000">);
            }
        }
        
        DataObject data </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DataObject(</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropLib.DataObject());
        
        ShDragImage shdi </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ShDragImage();
        Win32Size size;
        size.cx </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> bmp.Width;
        size.cy </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> bmp.Height;
        shdi.sizeDragImage </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> size;
        Point p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> e.Location;
        Win32Point wpt;
        wpt.x </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> p.X;
        wpt.y </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> p.Y;
        shdi.ptOffset </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wpt;
        shdi.hbmpDragImage </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> bmp.GetHbitmap();
        shdi.crColorKey </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Color.Magenta.ToArgb();
        
        IDragSourceHelper sourceHelper </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (IDragSourceHelper)</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropHelper();
        sourceHelper.InitializeFromBitmap(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> shdi, data);
        
        DoDragDrop(data, DragDropEffects.Copy);
    }</SPAN></DIV></PRE></DIV>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">The overhead of creating and populating the ShDragImage structure can get tedious and dirties the code. Also, if you read the code last week, you may have noticed the usage of the DragDropHelper was always two lines, such as above. One line to create the object and cast to the interface, and one line to call into it. Granted, you could convert this into a one-liner, but it would be ugly, and still more typing than necessary. Because the InitializeFromBitmap method works on an existing IDataObject instance, I decided an extension was appropriate. Basically, the ShDragImage structure has two important pieces of information. The HBITMAP pointer, which indicates our drag image, and the offset of the cursor relative to the image. The size of the bitmap is certainly important, but that information can be derived from the Bitmap instance, so my extension ended up like this:</P>
<P mce_keep="true">&nbsp;</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:8a339a22-6972-4eb0-b005-9e69cdda42d8 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Sets the drag image.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="dataObject"&gt;</SPAN><SPAN style="COLOR: #008000">The DataObject to set the drag image on.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="image"&gt;</SPAN><SPAN style="COLOR: #008000">The drag image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The location of the cursor relative to the image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> SetDragImage(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDataObject dataObject, Image image, Point cursorOffset)
        {
            ShDragImage shdi </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> ShDragImage();

            Win32Size size;
            size.cx </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> image.Width;
            size.cy </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> image.Height;
            shdi.sizeDragImage </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> size;

            Win32Point wpt;
            wpt.x </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> cursorOffset.X;
            wpt.y </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> cursorOffset.Y;
            shdi.ptOffset </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> wpt;

            shdi.crColorKey </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Color.Magenta.ToArgb();

            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> This HBITMAP will be managed by the DragDropHelper
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> as soon as we pass it to InitializeFromBitmap. If we fail
            </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"> to make the hand off, we'll delete it to prevent a mem leak.</SPAN><SPAN style="COLOR: #008000">
</SPAN><SPAN style="COLOR: #000000">            IntPtr hbmp </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> GetHbitmapFromImage(image);
            shdi.hbmpDragImage </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> hbmp;

            </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
            {
                IDragSourceHelper sourceHelper </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (IDragSourceHelper)</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropHelper();

                </SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">
                {
                    sourceHelper.InitializeFromBitmap(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> shdi, (ComIDataObject)dataObject);
                }
                </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000"> (NotImplementedException ex)
                {
                    </SPAN><SPAN style="COLOR: #0000ff">throw</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Exception(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">A NotImplementedException was caught. </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">
                       </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">This could be because you forgot to construct your DataObject </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">
                       </SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">using a DragDropLib.DataObject</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">, ex);
                }
            }
            </SPAN><SPAN style="COLOR: #0000ff">catch</SPAN><SPAN style="COLOR: #000000">
            {
                DeleteObject(hbmp);
            }
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Gets an HBITMAP from any image.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="image"&gt;</SPAN><SPAN style="COLOR: #008000">The image to get an HBITMAP from.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;returns&gt;</SPAN><SPAN style="COLOR: #008000">An HBITMAP pointer.</SPAN><SPAN style="COLOR: #808080">&lt;/returns&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;remarks&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> The caller is responsible to call DeleteObject on the HBITMAP.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/remarks&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> IntPtr GetHbitmapFromImage(Image image)
        {
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (image </SPAN><SPAN style="COLOR: #0000ff">is</SPAN><SPAN style="COLOR: #000000"> Bitmap)
            {
                </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> ((Bitmap)image).GetHbitmap();
            }
            </SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">
            {
                Bitmap bmp </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Bitmap(image);
                </SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000"> bmp.GetHbitmap();
            }
        }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">You'll notice that the SetDragImage extension function simply takes an IDataObject (in this case it is the System.Windows.Forms.IDataObject), an Image, and a cursor offset. From these pieces of information, we can easily populate the ShDragImage struct and call the IDragSourceHelper.InitializeFromBitmap method.</P>
<P>With this extension, which I placed in the System.Windows.Forms namespace for convenience, the code to begin a drag and drop routine is much simpler:</P>
<P mce_keep="true">&nbsp;</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:81a59439-868b-45c5-a2b8-9d4122cd9e3f class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> bt_MouseDown(</SPAN><SPAN style="COLOR: #0000ff">object</SPAN><SPAN style="COLOR: #000000"> sender, MouseEventArgs e)
    {
        Bitmap bmp </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Bitmap(</SPAN><SPAN style="COLOR: #000000">100</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">100</SPAN><SPAN style="COLOR: #000000">, PixelFormat.Format32bppArgb);
        </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> (Graphics g </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Graphics.FromImage(bmp))
        {
            g.Clear(Color.Magenta);
            </SPAN><SPAN style="COLOR: #0000ff">using</SPAN><SPAN style="COLOR: #000000"> (Pen pen </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> Pen(Color.Blue, 4f))
            {
                g.DrawEllipse(pen, </SPAN><SPAN style="COLOR: #000000">20</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">20</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">60</SPAN><SPAN style="COLOR: #000000">, </SPAN><SPAN style="COLOR: #000000">60</SPAN><SPAN style="COLOR: #000000">);
            }
        }
        
        DataObject data </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DataObject(</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropLib.DataObject());
        data.SetDragImage(bmp, e.Location);
        
        DoDragDrop(data, DragDropEffects.Copy);
    }</SPAN></DIV></PRE></DIV>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">Ignoring the creation of the Bitmap, I can now start drag and drop using a drag image in 3 lines of code.</P>
<H6>IDropTargetHelper Extensions</H6>
<P>Much like IDataObject, I can also extend IDropTargetHelper. However, now, instead of extending System.Windows.IDataObject and System.Windows.Forms.IDataObject separately, we extend IDropTargetHelper with methods for both WPF and WinForms. Again, I'll work with the WinForms code, but the WPF extensions are very similar.</P>
<P>Last week, we used code that handled the drag and drop events like this:</P>
<P mce_keep="true">&nbsp;</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:b49bb1a0-0201-42d7-a201-9ed46fa5d861 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    </SPAN><SPAN style="COLOR: #0000ff">protected</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">override</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnDragEnter(DragEventArgs e)
    {
        e.Effect </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Copy;
        Point p </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> Cursor.Position;
        Win32Point wp;
        wp.x </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> p.X;
        wp.y </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> p.Y;
        IDropTargetHelper dropHelper </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (IDropTargetHelper)</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropHelper();
        dropHelper.DragEnter(IntPtr.Zero, (ComIDataObject)e.Data, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> wp, (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)e.Effect);
    }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">The code is simple enough, but again, it gets tedious to declare the Win32Point struct and populate it. So, we can implement some extensions that use the native System.Windows.Forms and System.Drawing types: </P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:c1a6815b-1122-43ec-99b4-f6d36b6d906f class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the specified Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragEnter event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="dropHelper"&gt;</SPAN><SPAN style="COLOR: #008000">The DragDropHelper instance to notify.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="control"&gt;</SPAN><SPAN style="COLOR: #008000">The Control the received the DragEnter event.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="data"&gt;</SPAN><SPAN style="COLOR: #008000">The DataObject containing a drag image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DragEnter(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDropTargetHelper dropHelper, Control control,
            IDataObject data, Point cursorOffset, DragDropEffects effect)
        {
            IntPtr controlHandle </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> IntPtr.Zero;
            </SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000"> (control </SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">)
                controlHandle </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> control.Handle;
            Win32Point pt </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> SwfDragDropLibExtensions.ToWin32Point(cursorOffset);
            dropHelper.DragEnter(controlHandle, (ComIDataObject)data, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> pt, (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)effect);
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the current Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragOver event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="dropHelper"&gt;</SPAN><SPAN style="COLOR: #008000">The DragDropHelper instance to notify.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DragOver(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDropTargetHelper dropHelper, Point cursorOffset, DragDropEffects effect)
        {
            Win32Point pt </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> SwfDragDropLibExtensions.ToWin32Point(cursorOffset);
            dropHelper.DragOver(</SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> pt, (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)effect);
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the current Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a Drop event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="dropHelper"&gt;</SPAN><SPAN style="COLOR: #008000">The DragDropHelper instance to notify.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="data"&gt;</SPAN><SPAN style="COLOR: #008000">The DataObject containing a drag image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> Drop(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000"> IDropTargetHelper dropHelper, IDataObject data, Point cursorOffset, DragDropEffects effect)
        {
            Win32Point pt </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> SwfDragDropLibExtensions.ToWin32Point(cursorOffset);
            dropHelper.Drop((ComIDataObject)data, </SPAN><SPAN style="COLOR: #0000ff">ref</SPAN><SPAN style="COLOR: #000000"> pt, (</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)effect);
        }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">On top of that, I wanted to add one more layer. Since I always need an instance of the DragDropHelper, why not wrap that into some static methods? What I ended up doing is creating a static class called DropTargetHelper. This class maintains a static instance of the DragDropHelper and exposes some static methods. I also put this class in the System.Windows.Forms namespace, since that is generally where it would be used. Note that these methods don't do anything except add a layer of abstraction around the creation of the DragDropHelper class:</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:b4501e29-aa74-4201-957d-558ed1dafa01 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #0000ff">namespace</SPAN><SPAN style="COLOR: #000000"> System.Windows.Forms
{
    </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000"> DropTargetHelper
    {
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Internal instance of the DragDropHelper.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> IDropTargetHelper s_instance </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> (IDropTargetHelper)</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"> DragDropHelper();

        </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> DropTargetHelper()
        {
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the specified Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragEnter event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="control"&gt;</SPAN><SPAN style="COLOR: #008000">The Control the received the DragEnter event.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="data"&gt;</SPAN><SPAN style="COLOR: #008000">The DataObject containing a drag image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DragEnter(Control control, IDataObject data, Point cursorOffset, DragDropEffects effect)
        {
            SwfDropTargetHelperExtensions.DragEnter(s_instance, control, data, cursorOffset, effect);
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the current Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragOver event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DragOver(Point cursorOffset, DragDropEffects effect)
        {
            SwfDropTargetHelperExtensions.DragOver(s_instance, cursorOffset, effect);
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the current Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragLeave event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> DragLeave()
        {
            s_instance.DragLeave();
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Notifies the DragDropHelper that the current Control received
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> a DragOver event.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="data"&gt;</SPAN><SPAN style="COLOR: #008000">The DataObject containing a drag image.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="cursorOffset"&gt;</SPAN><SPAN style="COLOR: #008000">The current cursor's offset relative to the window.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="effect"&gt;</SPAN><SPAN style="COLOR: #008000">The accepted drag drop effect.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> Drop(IDataObject data, Point cursorOffset, DragDropEffects effect)
        {
            SwfDropTargetHelperExtensions.Drop(s_instance, data, cursorOffset, effect);
        }

        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> Tells the DragDropHelper to show or hide the drag image.
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;/summary&gt;</SPAN><SPAN style="COLOR: #008000">
        </SPAN><SPAN style="COLOR: #808080">///</SPAN><SPAN style="COLOR: #008000"> </SPAN><SPAN style="COLOR: #808080">&lt;param name="show"&gt;</SPAN><SPAN style="COLOR: #008000">True to show the image. False to hide it.</SPAN><SPAN style="COLOR: #808080">&lt;/param&gt;</SPAN><SPAN style="COLOR: #808080">
</SPAN><SPAN style="COLOR: #000000">        </SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> Show(</SPAN><SPAN style="COLOR: #0000ff">bool</SPAN><SPAN style="COLOR: #000000"> show)
        {
            s_instance.Show(show);
        }
    }
}</SPAN></DIV></PRE></DIV>
<P>NOTE: You may notice I'm calling my extension methods as static methods. This is because my code can be easily converted to work with .NET 3.0 or before by removing (or compiling out by way of preprocessor directives) the "this" keyword in front of the first parameter of the extension methods. I was going to include source that was compatible with .NET 3.0 but decided against it last minute. Anyway, the extensions, whether called as a static method or as an extension method, will do the same thing.</P>
<P>Now my drag event handlers can be simplified to something like this:</P>
<P mce_keep="true">&nbsp;</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a90ee4cb-a2d4-44d1-ba24-f4433a5e1064 class=wlWriterSmartContent><PRE style="BACKGROUND-COLOR: white"><DIV><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><SPAN style="COLOR: #000000">    </SPAN><SPAN style="COLOR: #0000ff">protected</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">override</SPAN><SPAN style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000"> OnDragEnter(DragEventArgs e)
    {
        e.Effect </SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"> DragDropEffects.Copy;
        DropTargetHelper.DragEnter(</SPAN><SPAN style="COLOR: #0000ff">this</SPAN><SPAN style="COLOR: #000000">, e.Data, Cursor.Position, e.Effect);
    }
</SPAN></DIV></PRE></DIV>
<P mce_keep="true">&nbsp;</P>
<P>Much simpler, and much less tedious to implement across 50 Forms in some enterprise application.</P>
<H5>Conclusion</H5>
<P>Drag and drop is a powerful tool for the end user experience. With a little work, we can implement a set of drag and drop helpers that keep our code tidy and add a great user experience for a minimal cost.</P>
<H5>Source Code</H5>
<P>The sources are available here:</P>
<TABLE class=sourcefiles class="sourcefiles">
<TBODY>
<TR>
<TD class=header class="header">File</TD>
<TD class=header class="header">Description</TD></TR>
<TR>
<TD><A title="View DragDropLib.cs" href="http://blogs.msdn.com/adamroot/pages/dragdroplib-cs-part-2.aspx" target=_blank>View DragDropLib.cs online</A></TD>
<TD>A complete compilation of all the source set into a single CS file so you can drop it into your project(s). Includes WPF and SWF implementations. No samples.</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Shell%20Style%20Drag%20and%20Drop%20Part%202/DragDropLib.cs" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>A complete compilation of all the source set into a single CS file so you can drop it into your project(s). Includes WPF and SWF implementations. No samples.</TD></TR>
<TR>
<TD><IFRAME style="BORDER-BOTTOM: #dde5e9 1px solid; BORDER-LEFT: #dde5e9 1px solid; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #ffffff; MARGIN: 3px; PADDING-LEFT: 0px; WIDTH: 240px; PADDING-RIGHT: 0px; HEIGHT: 26px; BORDER-TOP: #dde5e9 1px solid; BORDER-RIGHT: #dde5e9 1px solid; PADDING-TOP: 0px" marginHeight=0 src="http://cid-6f4c66b0ee56cd90.skydrive.live.com/embedrow.aspx/Public/Shell%20Style%20Drag%20and%20Drop%20Part%202/ShellDragDrop%20Part%202.zip" frameBorder=0 marginWidth=0 scrolling=no></IFRAME></TD>
<TD>A complete set of projects. Includes a complete DragDropLib project with WPF and SWF implementations, plus separated implementations. Includes sample projects.</TD></TR></TBODY></TABLE>
<H5>What's Next?</H5>
<P>Implementing the fundamentals is all good, but nothing feels better than putting it to use. In my next post, we'll look at an example of really putting this technology to use in the end user experience.</P>]]></content:encoded>
    </item>
  </channel>
</rss>