<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="www.w3.org/2005/Atom" xmlns:sy="purl.org/rss/1.0/modules/syndication/" xmlns:dc="purl.org/dc/elements/1.1/" xmlns:content="purl.org/rss/1.0/modules/content/" xmlns:wfw="wellformedweb.org/CommentAPI/" xmlns:slash="purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>The DSUI Team Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/dsui_team/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/dsui_team/feed.xml</link>
    <description>This is the team blog for the User Interface team in Microsoft Developer Support. We handle support for native and managed User Interface and Graphics technologies.</description>
    <lastBuildDate>Tue, 23 Feb 2016 15:33:56 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>System.Windows.Markup.XamlParseException with WPF application in Visual Studio 2015</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/system-windows-markup-xamlparseexception-with-wpf-application-in-visual-studio-2015</link>
      <pubDate>Thu, 13 Aug 2015 15:10:00 GMT</pubDate>
      <dc:creator><![CDATA[Steve Horne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2015/08/13/system-windows-markup-xamlparseexception-with-wpf-application-in-visual-studio-2015/</guid>
      <description><![CDATA[I recently had a customer report that sample WPF code&nbsp;from the Chapter 10: Resources chapter of...]]></description>
      <content:encoded><![CDATA[<p>I recently had a customer report that sample WPF code&nbsp;from the Chapter 10: Resources chapter of the APRESS book 'Pro WPF in C#' was throwing an exception when compiled and run only under the Visual Studio 2015 debugger:</p>
<p>System.Windows.Markup.XamlParseException occurred<br />&nbsp; HResult=-2146233087<br />&nbsp; LineNumber=8<br />&nbsp; LinePosition=32<br />&nbsp; Message='Provide value on 'System.Windows.Baml2006.TypeConverterMarkupExtension' threw an exception.' Line number '8' and line position '32'.<br />&nbsp; Source=PresentationFramework<br />&nbsp; StackTrace:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Markup.WpfXamlLoader.LoadDeferredContent(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings parentSettings, Uri baseUri)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.ResourceDictionary.CreateObject(KeyRecord key)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.ResourceDictionary.OnGettingValue(Object key, Object&amp; value, Boolean&amp; canCache)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.ResourceDictionary.OnGettingValuePrivate(Object key, Object&amp; value, Boolean&amp; canCache)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.ResourceDictionary.GetValueWithoutLock(Object key, Boolean&amp; canCache)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.ResourceDictionary.GetValue(Object key, Boolean&amp; canCache)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.DeferredThemeResourceReference.GetValue(BaseValueSourceInternal valueSource)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.DependencyObject.GetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, RequestFlags requests)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.DependencyObject.GetValueEntry(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, RequestFlags requests)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.DependencyObject.GetValue(DependencyProperty dp)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.StyleHelper.GetChildValueHelper(UncommonField`1 dataField, ItemStructList`1&amp; valueLookupList, DependencyProperty dp, DependencyObject container, FrameworkObject child, Int32 childIndex, Boolean styleLookup, EffectiveValueEntry&amp; entry, ValueLookupType&amp; sourceType, FrameworkElementFactory templateRoot)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.StyleHelper.GetChildValue(UncommonField`1 dataField, DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList`1&amp; childRecordFromChildIndex, EffectiveValueEntry&amp; entry, ValueLookupType&amp; sourceType, FrameworkElementFactory templateRoot)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.StyleHelper.GetValueFromTemplatedParent(DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList`1&amp; childRecordFromChildIndex, FrameworkElementFactory templateRoot, EffectiveValueEntry&amp; entry)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.StyleHelper.ApplyTemplatedParentValue(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1&amp; childRecordFromChildIndex, DependencyProperty dp, FrameworkElementFactory templateRoot)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1&amp; childRecordFromChildIndex, Boolean isDetach, FrameworkElementFactory templateRoot)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.FrameworkTemplate.InvalidatePropertiesOnTemplate(DependencyObject container, Object currentObject)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.FrameworkTemplate.HandleBeforeProperties(Object createdObject, DependencyObject&amp; rootObject, DependencyObject container, FrameworkElement feContainer, INameScope nameScope)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.FrameworkTemplate.&lt;&gt;c__DisplayClass0.&lt;LoadOptimizedTemplateContent&gt;b__5(Object sender, XamlObjectEventArgs args)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Xaml.XamlObjectWriter.OnBeforeProperties(Object value)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Xaml.XamlObjectWriter.Logic_CreateAndAssignToParentStart(ObjectWriterContext ctx)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Xaml.XamlObjectWriter.WriteStartMember(XamlMember property)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Xaml.XamlWriter.WriteNode(XamlReader reader)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)<br />&nbsp; InnerException: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HResult=-2146232800<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message=Cannot locate resource 'resourcelibrary;v1.0.5703.26795;themes/resourcelibrary;component/sadface.jpg'.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Source=PresentationFramework<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StackTrace:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at MS.Internal.AppModel.ResourcePart.GetStreamCore(FileMode mode, FileAccess access)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.IO.Packaging.PackWebResponse.CachedResponse.GetResponseStream()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.IO.Packaging.PackWebResponse.GetResponseStream()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.IO.Packaging.PackWebResponse.get_ContentType()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid&amp; clsId, Boolean&amp; isOriginalWritable, Stream&amp; uriStream, UnmanagedMemoryStream&amp; unmanagedMemoryStream, SafeFileHandle&amp; safeFilehandle)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Media.ImageSourceConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Windows.Baml2006.TypeConverterMarkupExtension.ProvideValue(IServiceProvider serviceProvider)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CallProvideValue(MarkupExtension me, IServiceProvider serviceProvider)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InnerException:</p>
<p>This same application,&nbsp;when run outside of the debugger runs without issue.</p>
<p>A bit of debugging turned up that the environment block of the application when run under the debugger has an extra environment variable set:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; ENABLE_XAML_DIAGNOSTICS_SOURCE_INFO=1</p>
<p>With that discovery I was able to set this environment variable outside of the debugger and also reproduce the issue, verifying it&nbsp;as the root cause.</p>
<p>A bit of online research on this turned up this article - <a href="https://blogs.msdn.com/b/wpf/archive/2015/02/24/expanding-wpf-for-ui-debugging.aspx">blogs.msdn.com/b/wpf/archive/2015/02/24/expanding-wpf-for-ui-debugging.aspx</a>&nbsp;indicating this is a new feature of the WPF framework for .NET 4.6.</p>
<p>I was able to further determine that this can be turned on and off in the debugger from the Tools menu, Options, Debugging, 'Enable UI Debugging Tools for XAML' property, allowing&nbsp;an straight-forward work around for the exception.</p>
<p>After reporting this to WPF product team they verified it is a bug in WPF and is under consideration for a fix in an future .NET hotfix rollup</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Using a Custom AutomationPeer in Cases of UIA Related Performance Degradation</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/using-a-custom-automationpeer-in-cases-of-uia-related-performance-degradation</link>
      <pubDate>Wed, 28 Aug 2013 18:17:00 GMT</pubDate>
      <dc:creator><![CDATA[Jon Burchel - Microsoft]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/08/28/using-a-custom-automationpeer-in-cases-of-uia-related-performance-degradation/</guid>
      <description><![CDATA[Summary
The Microsoft User Interface Automation (UIA) framework is great for helping automate...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: large;"><strong>Summary</strong></span></p>
<p>The Microsoft User Interface Automation (UIA) framework is great for helping automate testing and provide accessibility services for applications generally, but there are some cases where it may be disadvantageous for a client with very deeply nested UI components, since UIA requests can become taxing under those circumstances, degrading performance particularly.&nbsp; This may even inadvertently happen to an application, which has no intentional awareness of UIA features, but which simply derives from the default features exposed within another framework, for example, the Windows Presentation Framework (WPF), which incorporates UIA features into every control by default.&nbsp; In this case, an application with deeply nested UI components (such as a large TreeView, or DataGrid) might expose thousands of elements to UIA, without even being aware.&nbsp; If such an application is run in an environment where another application is making frequent or numerous UIA requests, then those requests, which might normally be very quickly processed, can become burdensome.&nbsp; Examples of such scenarios could be remote desktop sharing applications, narration or accessibility applications, testing frameworks, or any other application that might make UIA requests, ultimately answered from the process space of the unwary WPF developer, who may only recognize that when running in a particular scenario, his application performance begins to suffer significant degradation.</p>
<p><br /><span style="font-size: large;"><strong>Potential alternate causes for similar but unrelated behavior</strong></span></p>
<p>It should be noted that there are several known issues in .NET 3.5 and 4.0, wherein WPF&rsquo;s implementation walks the visual tree unnecessarily in some cases, causing further performance hits.&nbsp; The fix for .NET 4.0 was included with the .NET 4.5 distribution, and when 4.5 is installed on a client, the 4.0 binaries are also affected (being one in the same for both versions of the framework).&nbsp; For prior releases, the fixes are available through the following KB articles:</p>
<p><a href="https://support.microsoft.com/kb/2591373/en-us">2591373: &nbsp;FIX: A .NET Framework 3-based WPF application stops responding if you right-click a control to open a pop-up control</a><br /><a href="https://support.microsoft.com/kb/2591373/en-us">2484841:&nbsp; FIX: A .NET Framework 4.0 WPF application becomes unresponsive if used with MSAA or UIA client applications</a></p>
<p>For these scenarios, one may directly distinguish these performance issues from the ones addressed by the workaround suggested in this sample, through observing the following call stacks when inspecting the process in a debugger during its poorly performing state (or by debugging hang dumps captured of the process memory in that state).&nbsp; The issues addressed in the above fixes will exhibit the following characteristic call stacks, of deeply nested calls to InvalidateAutomationAncestors():</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.<span style="background-color: #ffff00;">InvalidateAutomationAncestors</span>(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span><br /><span style="font-family: courier new,courier; font-size: x-small;">PresentationCore_ni!MS.Internal.UIElementHelper.InvalidateAutomationAncestors(System.Windows.DependencyObject)+0xcf</span></p>
<p>A call stack more characteristic to the issue described and addressed in this post might show a deeply nested series of calls into UpdateLayout() or UpdateSubtree() functions instead, and are not due to any outstanding known issues within the WPF framework itself, but are sometimes an inevitable consequence of implementing a broad UI accessibility framework, and then running UIA clients, some of which may expose the framework to heavy load under some circumstances.&nbsp; Assuming the above known issues are not involved then, the application developer caught in such a circumstance &ndash; wherein some external UIA client is unnecessarily generating excessive hits against the automation tree &ndash; may implement an easy workaround to avoid the issue.&nbsp;</p>
<p>The workaround is that one may simply override the default AutomationPeer exposed by some top level control, under which were many other descendants generating heavy UIA activity by some UIA client or another, and for which he does not actually require exposure to that UIA client.&nbsp; Instead of returning all of the UI children of the control from its AutomationPeer (as WPF does by default), one may return a null collection, and in doing so, short circuit UIA from that portion of the tree.&nbsp; If automation must continue to work for some few particular node(s) from the underlying controls, we can even return just a specific node, or any other combination of nodes, with any degree of sophistication required to meet automation requirements.&nbsp;</p>
<p><span style="color: #ff0000; font-size: x-large; background-color: #ffff00;"><strong>WARNING:</strong></span></p>
<p><span style="color: #000000; font-size: small; background-color: #ffffff;"><strong><strong>The developer employing this approach must be aware that he is breaking the default automation tree intentionally, an act which eliminates the performance overhead of traversing a large and complex control tree, but which also destroys the ability of automation to reach those exposed controls, unless they are explicitly exposed through his custom implementation.&nbsp;</strong></strong></span></p>
<p>For example, narration would not work for any controls that were eliminated from the tree, nor would they be accessible to automation tests themselves, without being included.&nbsp; To witness this limitation, just run the sample, and then use the Narrator in Windows, clicking on a few of the nodes in the tree to experiment.&nbsp; You will find that the nodes we did not expose through our custom AutomationPeer are not narrated, while the one we did expose is still narrated.&nbsp; But the top level item using the default AutomationPeer narrates any node of the tree selected from its descendants.&nbsp; In many cases, this constraint is perfectly acceptable, but a developer using the approach should be aware of it before he considers a change that could potentially break his code for some users or scenarios.</p>
<p>With all of that explanation and forewarning out of the way, on to the fun part!</p>
<p><span style="font-size: large;"><strong>How to Implement the Workaround</strong></span></p>
<p>We create a TreeViewItemWithCustomAutomationPeer just as we do a normal TreeViewItem (where local: corresponds to the local namespace of our project as provided in an xmlns declaration at the top of the MainWindow.xaml):</p>
<p><code class="cplusplus">&lt;local:TreeViewItemWithCustomAutomationPeer Header="CustomAutomationPeerItem"&gt;<br /> ...<br /> &lt;TreeViewItem Name="SpecialItemToBeExposed" ... &gt;&lt;/TreeViewItem&gt;<br /> &lt;/local:TreeViewItemWithCustomAutomationPeer Header="CustomAutomationPeerItem"&gt;</code></p>
<p><span style="font-size: xx-small;">Code taken from MainWindow.xaml.</span></p>
<p>The code works by exposing a custom version of the control we want to use, but for which we will trim its children out of the UIA tree.&nbsp; In my example, I use a TreeViewItem control, since this kind of control is easy to show deep nesting, but it could be anything at all:</p>
<p><code class="csharp">// Our custom TreeViewItem, which implements its own custom AutomationPeer<br /> public class TreeViewItemWithCustomAutomationPeer : TreeViewItem<br /> {<br />&nbsp;&nbsp;&nbsp;&nbsp; // The only change we make, to return our custom AutomationPeer, <br />&nbsp;&nbsp;&nbsp;&nbsp; // instead of the default one that would have been returned. <br />&nbsp;&nbsp;&nbsp;&nbsp; protected override AutomationPeer OnCreateAutomationPeer()<br />&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new CustomAutomationPeerForTreeViewItemWithCustomAutomationPeer(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The item itself for the default TreeViewItemAutomationPeer constructor<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // And get some child designated as necessary for UIA, for whatever reason, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // just used as an example, so we have something to expose custom...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeHelper.FindChildren&lt;TreeViewItem&gt;(this).Where(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i =&gt; i.Name == "SpecialItemToBeExposed").First() <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br />&nbsp;&nbsp;&nbsp;&nbsp; }<br /> }</code></p>
<p><span style="font-size: xx-small;">Code taken from TreeViewItemWithCustomAutomationPeer.cs.</span></p>
<p><br />We must also implement a custom TreeViewItemAutomationPeer, which I named in the sample with the silly but verbosely accurate choice CustomAutomationPeerForTreeViewItemWithCustomAutomationPeer.<br />Here is that implementation:</p>
<p><span style="font-family: courier new,courier;">// Our custom TreeViewItemAutomationPeer, deriving from the default one...</span><br /><span style="font-family: courier new,courier;">public class CustomAutomationPeerForTreeViewItemWithCustomAutomationPeer : </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; TreeViewItemAutomationPeer</span><br /><span style="font-family: courier new,courier;">{</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; public TreeViewItem SomeItemWeWantToExpose = null;</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; public CustomAutomationPeerForTreeViewItemWithCustomAutomationPeer(</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeViewItem currentItem, TreeViewItem someItemWeWantToExpose)</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : base(currentItem)</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SomeItemWeWantToExpose = someItemWeWantToExpose;</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // HERE'S THE ONLY THING THAT REALLY MATTERS IN THIS SIMPLE IMPLEMENTATION!!!</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // You could just return NULL for no children, trim the whole tree out.&nbsp; </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // But let's say you DO need to expose some element way down in the tree,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // for whatever reason.&nbsp; You can do that too, however you want to!</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // That is what is happening with the arbitrary element I chose to include </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // for the purposes of this sample.&nbsp; But you could also implement</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // the same thing with multiple nodes, or even with other children, </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // having their own custom AutomationPeer implementations too.&nbsp; Whatever </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // your actual UIA requirements, you could still manage to achieve them, and </span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // unless they actually do consist of the entirety of the app's control tree,</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // you could still improve performance by eliminating any nodes that are not</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; // actually required...</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; protected override List&lt;AutomationPeer&gt; GetChildrenCore()</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;AutomationPeer&gt; children = new List&lt;AutomationPeer&gt;();</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Some child we want to return...&nbsp; We just passed it into our custom class</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // during its construction and kept track of it to return as the only child.</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; children.Add(</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeViewItemAutomationPeer.CreatePeerForElement(</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SomeItemWeWantToExpose as UIElement));</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return children;</span><br /><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-size: xx-small;">Code taken from TreeViewItemWithCustomAutomationPeer.cs.</span></p>
<p>In the sample, this implementation provides a short-circuit of an otherwise arbitrarily loaded TreeView, to demonstrate how many fewer nodes are represented, while still exposing one deeply nested node that we designated here as being relevant to UI Automation.&nbsp; The sample window, when fully expanded to show all the nodes, looks like this:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/2055.figure1.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/2055.figure1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/2055.figure1.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/2055.figure1.png" alt="" border="0" /></a></p>
<p>Although the print is small due to the size of the window to show the deep nesting, you can see both of the top level nodes in the TreeView hold deeply nested structures of child nodes and siblings without any children of their own.</p>
<p>The bottommost node in the second structure is highlighted.&nbsp; Its parent is the one I chose to expose arbitrarily in the custom AutomationPeer&rsquo;s children.&nbsp; As such, when UIA navigates this tree, it will traverse 25 nodes in the top portion of the tree, which are skipped in the lower tree of the same layout, because we have short circuited it to return only one particular node there, with no children even of its own except for its contents.&nbsp; The impact can be observed using Inspect.exe, from the Windows SDK, to witness the UIA tree returned from both nodes in the TreeView now:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4135.figure23.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4135.figure23.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4135.figure23.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4135.figure23.png" alt="" border="0" /></a></p>
<p>Note the sample does add a reference to UIAutomationProvider in its references, from the default WPF project references added by Visual Studio.&nbsp; Sample code attached.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/44/50/34/CustomAutomationPeerSample.zip" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-44-50-34/CustomAutomationPeerSample.zip">CustomAutomationPeerSample.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Using Theme APIs to draw the border of a control</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/using-theme-apis-to-draw-the-border-of-a-control</link>
      <pubDate>Wed, 26 Jun 2013 22:21:00 GMT</pubDate>
      <dc:creator><![CDATA[Dave Anderson-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/06/26/using-theme-apis-to-draw-the-border-of-a-control/</guid>
      <description><![CDATA[In this article, we will take a look at using the Theme APIs to draw the border of a control using...]]></description>
      <content:encoded><![CDATA[<p>In this article, we will take a look at using the Theme APIs to draw the border of a control using the current visual style.</p>
<p>Each window class is responsible for defining its appearance, which includes the client and non-client portions of the window. A window&rsquo;s border is typically part of its non-client area. Windows will handle drawing the border of a window when non-client window messages such as WM_NCPAINT are passed to the DefWindowProc function.</p>
<p>However, DefWindowProc will use the &ldquo;classic&rdquo; border appearance for child windows. Controls themselves are responsible for drawing their borders if the appearance defined for the current visual style is desired.</p>
<p>In Windows XP and later, COMCTL32.DLL version 6 provides an implementation of each of the standard Windows controls (Edit, Button, etc.) and common controls (List View, Tree View, etc.) that are rendered using the current visual style, if one is currently active. It does so by calling the Theme APIs when rendering the contents of the control.</p>
<p>The following code demonstrates using the Theme API to draw the border of an edit control in various states.</p>
<pre class="scroll"><code class="cplusplus">int cy = 60;<br />RECT rc = {10, 10, 300, cy};<br />int nPartId = EP_EDITBORDER_NOSCROLL;<br />HTHEME hTheme = OpenThemeData(hWnd, L"EDIT");<br />if (hTheme)<br />{<br /> DrawThemeBackground(hTheme, hdc, nPartId, EPSN_DISABLED, &amp;rc, NULL);<br /> <br /> OffsetRect(&amp;rc, 0, cy);<br /> DrawThemeBackground(hTheme, hdc, nPartId, EPSN_FOCUSED, &amp;rc, NULL);<br /> <br /> OffsetRect(&amp;rc, 0, cy);<br /> DrawThemeBackground(hTheme, hdc, nPartId, EPSN_HOT, &amp;rc, NULL);<br /> <br /> OffsetRect(&amp;rc, 0, cy);<br /> DrawThemeBackground(hTheme, hdc, nPartId, EPSN_NORMAL, &amp;rc, NULL);<br /> <br /> CloseThemeData(hTheme);<br />}<br /> </code></pre>
<p>&nbsp;</p>
<p>The following code demonstrates using the Theme API to draw the border of a rich edit control using the Edit theme class. This code can be added to a Win32 Windows project created in Visual Studio 2010 and Visual Studio 2012 using the following steps:</p>
<p>1. Add the following to stdafx.h:</p>
<pre class="scroll"><code class="cplusplus">#include &lt;Richedit.h&gt;<br />#include &lt;CommCtrl.h&gt;<br />#include &lt;Uxtheme.h&gt;<br />#include &lt;vsstyle.h&gt;<br />#include &lt;vssym32.h&gt;<br /> </code></pre>
<p class="Code">2. Replace the implementation of the InitInstance function with the following:&nbsp;</p>
<pre class="scroll"><code class="cplusplus">BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)<br /> {<br /> hInst = hInstance; // Store instance handle in our global variable<br /> HINSTANCE hInstRE = LoadLibrary(L"MSFTEDIT.DLL");<br /> <br /> HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, <br /> szWindowClass, <br /> szTitle, <br /> WS_OVERLAPPEDWINDOW,<br /> CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, <br /> NULL, NULL, hInstance, NULL);<br /> DWORD dwStyle = WS_CHILD | <br /> WS_VISIBLE | <br /> WS_VSCROLL | <br /> WS_HSCROLL | <br /> ES_MULTILINE;<br /> <br /> <br /> HWND hWndRE = CreateWindowEx(WS_EX_CLIENTEDGE, <br /> MSFTEDIT_CLASS, <br /> L"Rich Edit Control", <br /> dwStyle,<br /> 10, 10, 300, 300, <br /> hWnd, NULL, hInstRE, NULL);<br /> SetWindowSubclass(hWndRE, RichEditSubclassProc, 1, NULL);<br /> SendMessage(hWndRE, WM_THEMECHANGED, 0, 0);<br /> <br /> ShowWindow(hWnd, nCmdShow);<br /> UpdateWindow(hWnd);<br /> return TRUE;<br /> }</code></pre>
<p>&nbsp;</p>
<p>3. Add the following functions to the project:</p>
<pre class="scroll"><code class="cplusplus">void DrawThemedFrame(HWND hWnd, HRGN hrgnUpdate, HTHEME hTheme)<br /> {<br /> int idPart = EP_EDITBORDER_HVSCROLL;<br /> int idState = EPSHV_NORMAL;<br /> int cxEdge = GetSystemMetrics(SM_CXEDGE);<br /> int cyEdge = GetSystemMetrics(SM_CYEDGE);<br /> <br /> if (GetFocus() == hWnd)<br /> {<br /> idState = EPSHV_FOCUSED;<br /> }<br /> <br /> if (!IsWindowEnabled(hWnd))<br /> {<br /> idState = EPSHV_DISABLED;<br /> }<br /> <br /> HDC hDC = GetWindowDC(hWnd);<br /> if (hDC)<br /> {<br /> //<br /> // Get the border size from the theme<br /> int cxBorder, cyBorder;<br /> GetThemeInt(hTheme, idPart, idState, TMT_BORDERSIZE, &amp;cxBorder);<br /> cyBorder = cxBorder;<br /> <br /> //<br /> // Get the window coordinates<br /> RECT rcWindow;<br /> GetWindowRect(hWnd, &amp;rcWindow);<br /> <br /> //<br /> // Create an update region without the client edge to pass to <br /> // DefWindowProc<br /> InflateRect(&amp;rcWindow, -cxEdge, -cyEdge);<br /> HRGN hrgn = CreateRectRgnIndirect(&amp;rcWindow);<br /> if (hrgnUpdate)<br /> {<br /> CombineRgn(hrgn, hrgnUpdate, hrgn, RGN_AND);<br /> }<br /> <br /> //<br /> // Zero origin the rect<br /> OffsetRect(&amp;rcWindow, -rcWindow.left, -rcWindow.top);<br /> <br /> //<br /> // Clip our drawing to the non-client edge<br /> OffsetRect(&amp;rcWindow, cxEdge, cyEdge);<br /> ExcludeClipRect(hDC, <br /> rcWindow.left, <br /> rcWindow.top, <br /> rcWindow.right, <br /> rcWindow.bottom);<br /> InflateRect(&amp;rcWindow, cxEdge, cyEdge);<br /> DrawThemeBackground(hTheme, hDC, idPart, idState, &amp;rcWindow, 0);<br /> <br /> //<br /> // Fill with the control's brush since the theme border may not be as <br /> // thick as the client edge<br /> if (cxBorder &lt; cxEdge &amp;&amp; cyBorder &lt; cyEdge)<br /> {<br /> InflateRect(&amp;rcWindow, cxBorder-cxEdge, cyBorder-cyEdge);<br /> FillRect(hDC, &amp;rcWindow, GetSysColorBrush(COLOR_WINDOW));<br /> }<br /> <br /> //<br /> // Let DefWindowProc to the rest, excluding the border we just painted<br /> DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)hrgn, 0);<br /> <br /> DeleteObject(hrgn);<br /> ReleaseDC(hWnd, hDC);<br /> }<br /> }<br /> <br /> <br /> <br /> LRESULT CALLBACK RichEditSubclassProc(HWND hWnd, <br /> UINT uMsg, <br /> WPARAM wParam, <br /> LPARAM lParam, <br /> UINT_PTR uIdSubclass, <br /> DWORD_PTR dwRefData)<br /> {<br /> HTHEME hTheme = (HTHEME)GetWindowLongPtr(hWnd, GWLP_USERDATA);<br /> <br /> switch (uMsg)<br /> {<br /> case WM_DESTROY:<br /> RemoveWindowSubclass(hWnd, RichEditSubclassProc, 1);<br /> CloseThemeData(hTheme);<br /> SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)NULL);<br /> break;<br /> <br /> case WM_SYSCOLORCHANGE:<br /> case WM_SETFOCUS:<br /> case WM_KILLFOCUS:<br /> case WM_ENABLE:<br /> if (hTheme)<br /> DrawThemedFrame(hWnd, NULL, hTheme);<br /> break;<br /> <br /> case WM_THEMECHANGED:<br /> if (hTheme)<br /> {<br /> CloseThemeData(hTheme);<br /> hTheme = NULL;<br /> }<br /> <br /> hTheme = OpenThemeData(hWnd, L"EDIT");<br /> SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)hTheme);<br /> InvalidateRect(hWnd, NULL, TRUE);<br /> break;<br /> <br /> case WM_NCPAINT:<br /> if (hTheme)<br /> {<br /> DrawThemedFrame(hWnd, (HRGN)wParam, hTheme);<br /> return 0;<br /> }<br /> break;<br /> }<br /> return DefSubclassProc(hWnd, uMsg, wParam, lParam);<br /> }<br /> </code></pre>
<p class="Code">&nbsp;4. Add uxtheme.lib and comctl32.lib to the import libraries in the project&rsquo;s Linker settings.</p>
<p class="Code">&nbsp;</p>
<p>The resulting project creates a Rich Edit control that is drawn using the theme data for edit controls when themes are active. Please note this sample demonstrates the minimum code needed to draw a themed border for a control and does not perform any error handling.</p>]]></content:encoded>
    </item>
    <item>
      <title>Printing from a Windows Service</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/printing-from-a-windows-service</link>
      <pubDate>Mon, 24 Jun 2013 09:44:00 GMT</pubDate>
      <dc:creator><![CDATA[Greg Binkerd]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/06/24/printing-from-a-windows-service/</guid>
      <description><![CDATA[It is often desirable to print a document to a printer from your Windows service.&nbsp; While...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: small;"><span style="font-family: Calibri;">It is often desirable to print a document to a printer from your Windows service.&nbsp; While calling the Windows Win32 GDI APIs to send a document to the printer is supported, there are some important considerations to take into account, such as which user account the service is running under, and whether that user has ever logged into the computer before.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">Some scenarios would be a Windows service that runs in the background and needs to print reports to a printer, or a Windows service that needs to print errors when an infrequent problem occurs on a server machine.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">A Windows service that is designed to print can use the Win32 GDI APIs to print documents to a printer.&nbsp; There are some considerations when printing from Windows services, however.&nbsp; If all the print jobs can be sent with one user's credentials, the service can be run under that user's account and will have access to the printers that are known to that user on that computer.&nbsp; If the service must print using the credentials of one or more users defined at run time, then the service must call LogonUser(), LoadUserProfile(), and ImpersonateLoggedOnUser() before printing.&nbsp; </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">While it is possible to send GDI+ output to a printer by obtaining a device context handle for the printer and then passing that handle to a GDI+ Graphics constructor, this is not recommended.&nbsp; The GDI+ functions and classes are not supported for use within a Windows service.&nbsp; Attempting to use these functions and classes from a Windows service may produce unexpected problems, such as diminished service performance and run-time exceptions or errors:</span></span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span><span style="font-family: Calibri; font-size: small;">&nbsp; </span><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms533798(v=VS.85).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/windows/desktop/ms533798(v=VS.85).aspx</span></a></p>
<p><span style="font-family: Calibri; font-size: small;">In addition, if you are developing a Microsoft .NET application, System.Drawing is not supported in a service or web application. Attempting to use System.Drawing within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions (see the &ldquo;Caution&rdquo; section in </span><a href="https://msdn.microsoft.com/en-us/library/system.drawing.aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/system.drawing.aspx</span></a><span style="font-size: small;"><span style="font-family: Calibri;">).</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">System.Printing is also not supported in a service context.&nbsp; This is documented on MSDN here.&nbsp; System.Printing is part of Windows Presentation Foundation.</span></span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span><span style="font-family: Calibri; font-size: small;">&nbsp; </span><a href="https://msdn.microsoft.com/en-us/library/bb613549(v=vs.90).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/bb613549(v=vs.90).aspx</span></a></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">You should be using the Win32 GDI APIs when printing from your Windows Service:</span></span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span><span style="font-family: Calibri; font-size: small;">&nbsp;</span><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145203(v=vs.85).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/windows/desktop/dd145203(v=vs.85).aspx</span></a></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">The following Win32 C++ sample code demonstrates how to print a single page to a printer using the Win32 GDI APIs.&nbsp; The following is only intended as sample code.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TCHAR szPrinterName[MAX_PATH] = TEXT("");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwNameLen = MAX_PATH;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HDC hDC;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOCINFO di;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We will operate on the default printer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetDefaultPrinter( szPrinterName, &amp;dwNameLen );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create the HDC for the printer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( (hDC = CreateDC( TEXT("WINSPOOL"), szPrinterName, NULL, NULL )) == NULL )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The StartDoc function starts the print job<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;di, sizeof(DOCINFO) );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; di.cbSize = sizeof(DOCINFO);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; di.lpszDocName = TEXT("Print Job");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( StartDoc( hDC, &amp;di ) &lt;= 0 )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The StartPage function prepares the printer driver to accept data<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( StartPage( hDC ) &lt;= 0 )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EndDoc( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TCHAR szString[32] = TEXT("Printing from a service");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut( hDC, 0, 0, szString, lstrlen( szString ) );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( EndPage( hDC ) &lt;= 0 )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EndDoc( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( EndDoc( hDC ) &lt;= 0 )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC( hDC );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; Delete the HDC<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC( hDC );</p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">If you are developing a Microsoft .NET application, you can use Platform Invocation Services (PInvoke) to call the Win32 GDI APIs to print.&nbsp; The following C# sample code demonstrates how to print a rectangle to a printer using the Win32 GDI APIs.&nbsp; The following is only intended as sample code.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private void PrintRectangle()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const int ERROR_INSUFFICIENT_BUFFER = 122;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr hdc;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOCINFO di = new DOCINFO();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; di.cbSize = 20;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; di.pDocName = "TestingGDI";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pcchBuffer = 256;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuilder pszBuffer = new StringBuilder(pcchBuffer);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GetDefaultPrinter(null, ref pcchBuffer))<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; return;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int lastWin32Error = Marshal.GetLastWin32Error();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)<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; pszBuffer.Capacity = pcchBuffer;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetDefaultPrinter(pszBuffer, ref pcchBuffer);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This is the default printer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String szPrinter = pszBuffer.ToString();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdc = CreateDC(IntPtr.Zero, szPrinter,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr.Zero, IntPtr.Zero);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Int32 nRes = StartDoc(hdc, di);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nRes &gt; 0)<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; // We call the Win32 StartPage to start a new page on the HDC<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nRes = StartPage(hdc); // You can add error checking to this code</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Draw a Rectangle<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rectangle(hdc, 10, 10, 500, 500);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nRes = EndPage(hdc);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // First, call the Win32 function to signal the end of the document<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EndDoc(hdc);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Then delete the HDC we created for this print job<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC(hdc);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int pcchBuffer);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Win32 DOCINFO structore for starting a print document<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public class DOCINFO<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int cbSize;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string pDocName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string pOutputFile;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string pDataType;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int fwType;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // CreateDC() to create a printer HDC<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern IntPtr CreateDC(IntPtr pNull1, string lpszDevice,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IntPtr<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pNull2, IntPtr lpInitData);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // StartDocW - the Unicode version of StartDoc - to start a print job<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", EntryPoint = "StartDocW", SetLastError = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CharSet = CharSet.Unicode, ExactSpelling = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallingConvention = CallingConvention.StdCall)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern Int32 StartDoc(IntPtr hDC, [In,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MarshalAs(UnmanagedType.LPStruct)] DOCINFO di);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // StartPage - starts a new page in a print job<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", EntryPoint = "StartPage", SetLastError = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CharSet = CharSet.Auto, ExactSpelling = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallingConvention = CallingConvention.StdCall)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern Int32 StartPage(IntPtr hDC);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // EndPage - ends the current page on a printer DC<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", EntryPoint = "EndPage", SetLastError = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CharSet = CharSet.Auto, ExactSpelling = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallingConvention = CallingConvention.StdCall)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern Int32 EndPage(IntPtr hDC);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // EndDoc - signals the end of a print job<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", EntryPoint = "EndDoc", SetLastError = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CharSet = CharSet.Auto, ExactSpelling = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallingConvention = CallingConvention.StdCall)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern Int32 EndDoc(IntPtr hDC);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // DeleteDC - to clean up our printer DC after the job is done<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32.dll", EntryPoint = "DeleteDC", SetLastError = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CharSet = CharSet.Auto, ExactSpelling = true,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallingConvention = CallingConvention.StdCall)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern bool DeleteDC(IntPtr hDC);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport("gdi32")]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern bool Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Debugging a GDI Resource Leak</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/debugging-a-gdi-resource-leak</link>
      <pubDate>Tue, 23 Apr 2013 08:13:00 GMT</pubDate>
      <dc:creator><![CDATA[David Wooden - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/04/23/debugging-a-gdi-resource-leak/</guid>
      <description><![CDATA[One of the most common graphics-related problems we see is a &ldquo;GDI leak&rdquo; (or, simply the...]]></description>
      <content:encoded><![CDATA[<p style="text-align: left;" align="center">One of the most common graphics-related problems we see is a &ldquo;GDI leak&rdquo; (or, simply the usage of too many GDI objects), which will eventually cause rendering problems, errors, and/or performance problems. Some things need to be defined and explained before I talk about how we debug these problems.</p>
<p style="text-align: left;" align="center">&nbsp;</p>
<p>&nbsp;<strong>--Definitions--</strong></p>
<p><strong>GDI Objects</strong> are resources that are managed by GDI32.DLL on behalf of an application.&nbsp;Some of the most common types of GDI objects are Device Contexts (DCs), Bitmaps, Brushes, Fonts, Metafiles, Pens, and Regions.&nbsp; GDI Objects are stored in Kernel Memory (specifically the Paged Pool or Session Pool portions of kernel memory &ndash; more on this later).</p>
<p><strong>GDI Handles</strong> are unique identifiers of a GDI Object.&nbsp; Each GDI Object can have only one handle.&nbsp; Each GDI Handle is process-specific (cannot be used by other processes).</p>
<p>The <strong>GDI Handle Table</strong> is a table (array) of GDI entries.&nbsp; Each&nbsp;entry&nbsp;contains 32-bits of information about a GDI object, including the handle, the type of the object (i.e. bitmap, DC, pen, font, etc.), the process for which that handle is valid, and a pointer to the actual GDI object in Kernel Memory.&nbsp;This table exists in User Memory.</p>
<p>Note: the fact that it contains the <strong>type</strong> of the object is very useful to us, and this can be used to help track down what we&rsquo;re leaking and why &ndash; more on this later.</p>
<p>&nbsp;</p>
<p><strong>--Creating GDI objects (and getting back a handle)--</strong></p>
<p>To create a GDI object, we call the appropriate GDI API function (usually of the form CreateXXX, such as CreateFontIndirect), which will create the object in kernel memory, and if successful, add an entry in the GDI Handle Table, and return a handle to that object.&nbsp;</p>
<p>But what if we run out of handles?&nbsp; What if there isn&rsquo;t enough room left in kernel memory for the object?&nbsp; In these cases, the GDI function will fail, and GetLastError will usually return ERROR_INVALID_HANDLE.</p>
<p>&nbsp;</p>
<p><strong>--Limits--</strong></p>
<p>There is a limit of 65,536 (64k) GDI handles per session.&nbsp; Note though that, particularly on 32-bit (x86) systems, the effective maximum is usually lower than this, due to memory limitations.&nbsp; For example, you generally won&rsquo;t fit anywhere near 65,536 large bitmaps on a 32-bit system, no matter how many handles you&rsquo;re allowed to have.</p>
<p>That 65,536 handles needs to accommodate all processes in the session (your app doesn&rsquo;t get to use them all).&nbsp; In fact, to prevent a single process from bringing the entire system to its knees (and making the OS unable even to draw a dialog saying &ldquo;I&hellip;CAN&rsquo;T&hellip;DRAW&hellip;ANYMORE&rdquo;), there is a <strong>per-process limit</strong>, which by default is 10,000 GDI handles.&nbsp; Although there is rarely, if ever,&nbsp;any good reason for any process to need more than 10k unique GDI objects in memory at the same time, this limit can be raised via the following registry value&hellip;</p>
<p>&nbsp;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows\GDIProcessHandleQuota</p>
<p>If an application is running out of GDI handles (i.e. you hit 10k handles and can&rsquo;t create any more), then raising the above limit is NOT the suggested way of solving the problem.&nbsp;</p>
<p>First of all, raising this limit does not raise the available kernel memory to store the actual GDI objects that the handles identify.</p>
<p>Second of all, raising this limit REDUCES the number of GDI objects that the rest of the system (including Windows itself) can use.</p>
<p>Thirdly, and maybe most importantly, the application should be redesigned to not use so many GDI resources.&nbsp; The right thing to do is to manage resources more efficiently in the application.</p>
<p>&nbsp;</p>
<p><strong>--Debugging--</strong></p>
<p>Okay, so what do we do if we suspect that we are using too many GDI objects?</p>
<p>&nbsp;</p>
<p><strong>1 &ndash; Are we really leaking (or using too many) handles?&nbsp; If so, how many and how fast?</strong>&nbsp;</p>
<ul>
<li>Check GDI Object usage via Task Manager (note, you need to specify the GDI Objects column &ndash; shown below).</li>
</ul>
<p><br />&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4747.tm.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4747.tm.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4747.tm.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4747.tm.png" alt="" border="0" /></a><br />&nbsp;&nbsp;</p>
<ul>
<li>Generally, if you see a process with a GDI Object count in the thousands, then there is a potential problem.</li>
<li>If you see a process with a GDI Object count of near 9,999, then it is very probably out of GDI resources and cannot create more.</li>
<li>When a process (or the system) is out of resources, the creation API (i.e. CreateFont, CreateDC, etc.) will fail and set the last error (GetLastError)&nbsp;to 5 (ERROR_INVALID_HANDLE).</li>
</ul>
<p>&nbsp;</p>
<p><strong>2 &ndash; What types of GDI objects are these?&nbsp; Fonts?&nbsp;Brushes?&nbsp; Bitmaps?&nbsp; etc.</strong>&nbsp;</p>
<ul>
<li>Find out what types of GDI objects are being leaked (<strong>if</strong> not already known).&nbsp; This is harder than it used to be, since most of the tools out there that query this information have fallen out of date with Vista and later.&nbsp; For reference, and as a starting point if you want to try to get them working&hellip;</li>
<ul>
<li>GDIObj from <a href="www.fengyuan.com/download.html">www.fengyuan.com/download.html</a></li>
<li>GDILeaks from <a href="https://msdn.microsoft.com/en-us/magazine/cc188782.aspx">msdn.microsoft.com/en-us/magazine/cc188782.aspx</a></li>
<li>There are more, or you could write your own and use the above as reference (see below).You can do this yourself, but it involves some tricks.&nbsp; The most important thing you&rsquo;ll need is the address of the GDI handle table in User Memory.&nbsp; Though undocumented, this can be obtained by looking for GdiSharedHandleTable inside the process environment block (the PEB).&nbsp; This field contains the address for the handle table.&nbsp;</li>
</ul>
<li>Under <a href="https://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx">WinDbg</a>, once you have public symbols setup, run dt ntdll!_PEB.&nbsp; This will tell you <strong>where</strong> in the PEB you can find GdiSharedHandleTable.&nbsp; Note the location can vary, and will vary between x64 and x86.</li>
<li>Once you have this location, you can look through the entries in memory.&nbsp; It will take some trial and error since the exact layout is undocumented and unsupported.&nbsp; Hint: You could try to use one of the previously linked (older) tools as a starting point.&nbsp;</li>
<li>Once you know what type of objects you&rsquo;re leaking, look for where you are creating these object types in your code (i.e. search for CreateFont and CreateFontIndirect if you are using thousands of font handles), and make sure you are de-selecting and deleting these objects whenever you are done with them.
<ul>
<li>If you think you really need thousands of objects, ask yourself &ndash; are these really all unique objects?&nbsp; Or am I creating hundreds of instances of a 12 point Arial font?&nbsp; If the latter, then try caching a single instance for use by the different parts of your code (for example, create a single 12-point Arial font when your app starts up, and save the handle off).&nbsp; Just use the same handle as needed in your code.&nbsp; Delete it with <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183539(v=vs.85).aspx">DeleteObject</a>&nbsp;when you&rsquo;re really done with it (maybe not until your app closes).</li>
<li>On the other hand, if you really need thousands of unique objects, try to create/select/use/de-select/delete these objects each time you need them.</li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<p><strong>3 &ndash; If there isn&rsquo;t a clear problem handle leak found via 1 and 2&hellip;</strong></p>
<ul>
<li>Check overall Paged Pool usage.<strong></strong></li>
<li>This can be quickly checked with Task Manager (notice the &ldquo;Paged&rdquo; field in the Performance tab of Task Manager shown here)&hellip;<strong></strong></li>
</ul>
<p><strong>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/5633.tm2.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/5633.tm2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/5633.tm2.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/5633.tm2.png" alt="" border="0" /></a></strong></p>
<p>&nbsp;</p>
<ul>
<li>Even better, check&nbsp;the Paged Pool usage with <a href="https://technet.microsoft.com/en-us/sysinternals/bb896653.aspx">Process Explorer</a>.</li>
<ul>
<li>First, you need to set up symbols via Options-&gt;Configure Symbols.&nbsp; Enter a symbol path of <strong>SRV**msdl.microsoft.com/download/symbols</strong></li>
<li>Then, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; click View-&gt;System Information&hellip;</li>
</ul>
<li>Note,&nbsp;Process Explorer also shows the <strong>limit</strong> (when symbols are configured&nbsp;correctly as above) - which is information that Task Manager does not give&hellip;</li>
</ul>
<p><br /> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4162.pe.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4162.pe.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/4162.pe.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/4162.pe.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>4 - If #3 shows that you are running out of Paged Pool&hellip;</strong></p>
<p>&nbsp;</p>
<ul>
<li>First, a bit about which &ldquo;Paged Pool&rdquo; we care about (there are really two kinds).&nbsp; For systems&nbsp;that don&rsquo;t have Terminal Services installed, we&rsquo;re talking about general&nbsp;paged pool; on all other systems, we mean the per-session session pool.</li>
<li>If running XP or earlier versions of Windows, then, you would need to explicitly &ldquo;tell&rdquo; the system that you want pool allocations to be&nbsp;tagged.&nbsp; On these older systems, run gflags.exe (along with WinDbg, this is included with <a href="https://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx">Debugging Tools for Windows</a>), and select the &ldquo;Enable pool tagging&rdquo; checkbox.&nbsp;Then, reboot (again, XP and earlier&nbsp;only).</li>
</ul>
<p>&nbsp;</p>
<ul>
<li><a href="https://support.microsoft.com/kb/177415">Poolmon</a> will tell you what objects are using up Paged Pool (it will also show you the overall usage like Task Manager and Process&nbsp;Explorer did)&hellip;</li>
</ul>
<p><br /> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/7737.pm.png" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/7737.pm.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/7737.pm.png" original-url="blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/7737.pm.png" alt="" border="0" /></a></p>
<ul>
<li>To narrow down what PoolMon shows you, you can start it as follows (for example)&hellip;</li>
<ul>
<li>poolmon &ndash;gla*</li>
</ul>
<li>You can also tell it to sort by various fields and turn off highlighting (press ? for help and ESC to get out of help).</li>
<li>pooltag.txt ships with the Windows Driver Kit (WDK) and lists all the tags, but we only care about a few&hellip;</li>
<li>The tags that GDI use all start with &lsquo;G&rsquo;, making this usage more easy to track (not only in poolmon, but when debugging - for example, under <a href="https://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx">WinDbg</a>, you could run <strong>!poolused 4 Gla: </strong>).</li>
<ul>
<li>Some example tags are&hellip;</li>
<li>&ldquo;Gla:&rdquo; Font type is 0xa.</li>
<li>&ldquo;Gla1&rdquo; DC type is 0x1.</li>
<li>&ldquo;Gh05&rdquo; SURF (bitmap) type is 0x5.</li>
</ul>
<li>To give you a rough idea of memory usage seen through experimentation (these are under XP):</li>
<ul>
<li>DCs (Gla1) &ndash; 1600 bytes per object</li>
<li>Fonts (Gla:) &ndash; 656 bytes per object</li>
<li>Bitmaps (Gla5) &ndash; 392 bytes per object</li>
<li>Regions (Gla4) &ndash; 176 bytes per object</li>
<li>Palettes (Gla8) &ndash; 160 bytes per object</li>
<li>Brushes (Gla@) &ndash; 112 bytes per object</li>
</ul>
<li>Tracking down a pagedpool leak is often more art than science, but a few tools to help you figure out what is leaking are:</li>
<ul>
<li>Under WinDbg: !poolused 4</li>
<li>Under WinDbg: !vm 1</li>
<li>poolmon (see above)</li>
</ul>
</ul>
<ul>
<li>Note &ndash; to track <strong>Session </strong>Paged Pool, use poolmon /s, or poolmon /s# (where # is a session ID).&nbsp; You can toggle between system and session by typing s while poolmon is running.</li>
</ul>
<p>&nbsp;</p>
<p><strong>5 &ndash; Once you know what is being leaked&hellip;</strong></p>
<ul>
<li>Review your code.&nbsp; Make sure you are cleaning up after yourself with <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183539(v=vs.85).aspx">DeleteObject</a>.&nbsp; This is something you should do before even going down this road!</li>
<li>If you can&rsquo;t find the culprit, try adding some trace information next to your CreateXXX and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183539(v=vs.85).aspx">DeleteObject</a>&nbsp;calls, and then examine the output after running.</li>
<li>Put a breakpoint on the CreateXXX function (where the actual function name depends on the type of object &ndash; e.g. ExtCreateBrush), and try to see who the guilty party is.</li>
</ul>
<p>&nbsp;</p>
<ul>
<li>NOTE - Often, if there is a leak of this kind, the function is being hit hundreds or thousands of times, and not every one will be part of the actual leak (often, most of them are not!).&nbsp; Just because you&rsquo;re leaking fonts, doesn&rsquo;t mean *this* CreateFontIndirect call is part of the problem.</li>
</ul>
<p>&nbsp;</p>
<p>Some common mistakes&hellip;</p>
<ul>
<li>In .NET, not explicitly calling <a href="https://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx">Dispose</a> on all System.Drawing objects before they go out of scope (the <strong>using</strong> keyword is also acceptable).</li>
<li>Not calling <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183539(v=vs.85).aspx">DeleteObject</a>&nbsp;on each created GDI object in native (non-.NET) code.</li>
<li>Creating lots of memory intensive objects (for example large bitmaps).&nbsp; Particularly on 32-bit systems.&nbsp; Also, particularly in a terminal services session, where the available <strong>session</strong> paged pool is much lower.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Using Direct2D from a service in C#</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/using-direct2d-from-a-service-in-c</link>
      <pubDate>Tue, 16 Apr 2013 10:19:00 GMT</pubDate>
      <dc:creator><![CDATA[Greg Binkerd]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/04/16/using-direct2d-from-a-service-in-c/</guid>
      <description><![CDATA[It is often desirable to create graphical images on disk from a service context.&nbsp; For example,...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: small;"><span style="font-family: Calibri;">It is often desirable to create graphical images on disk from a service context.&nbsp; For example, some server applications need to render images and send back the generated bitmaps to users connected through web clients. One example would be an ASP.NET web application which needs to generate user profile pictures on the fly. We have observed that many developers choose to use GDI+ and System.Drawing to generate those images. &nbsp;However, GDI+ and System.Drawing are not supported in a service context or in a web application. Attempting to use System.Drawing within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions (see the &ldquo;Caution&rdquo; section in </span></span><a href="https://msdn.microsoft.com/en-us/library/system.drawing.aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/system.drawing.aspx</span></a><span style="font-size: small;"><span style="font-family: Calibri;">).&nbsp; In addition, the WPF (Windows Presentation Foundation) graphics classes are unsupported in a service context.&nbsp;&nbsp; The use of WPF within a Windows service was a scenario that was not designed nor tested for. This is documented on MSDN here:&nbsp; </span></span><a href="https://msdn.microsoft.com/en-us/library/bb613549(v=vs.90).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/bb613549(v=vs.90).aspx</span></a><span style="font-size: small;"><span style="font-family: Calibri;"> .</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">Direct2D is the supported technology for rendering images to an image file on disk in a service context. &nbsp;Below is C# ASP.NET code which shows how to render a Direct2D scene to an image file on disk.&nbsp; This code can be used in any C# service. It demonstrates how to create a Direct2D bitmap based on image data in memory, draw Direct2D objects, such as an Ellipse and a Rectangle, and it also uses DirectWrite to render text. The code relies on the DirectX assembly from the Windows API Code Pack for Microsoft .NET Framework. This assembly provides developers access to Direct2D and DirectWrite from managed code.&nbsp; You will need to use the following file from the Windows API Code Pack for Microsoft .NET Framework, and add it as a reference to your project:&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.dll&nbsp;&nbsp;&nbsp;&nbsp; See:&nbsp; </span></span><a href="https://archive.msdn.microsoft.com/WindowsAPICodePack"><span style="color: #0563c1; font-family: Calibri; font-size: small;">archive.msdn.microsoft.com/WindowsAPICodePack</span></a><span style="font-size: small;"><span style="font-family: Calibri;"> &nbsp;&nbsp;&nbsp;&nbsp;The Windows API Code Pack for Microsoft .NET Framework is a free, managed source code library provided by Microsoft as is.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">After you implement the C# code (below), then you should see an image on disk created as follows:</span></span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/3125.1.jpg" original-url="blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/3125.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/55/84/3125.1.jpg" original-url="blogs.msdn.com/resized-image.ashx/__size/250x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-55-84/3125.1.jpg" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier;"><span style="font-size: small;"><span style="font-family: Calibri;">/**************************** Module Header ******************************\<br />' Copyright (c) Microsoft Corporation.<br />'<br />' This code demonstrates how to use Direct2D to render 2D objects and text to<br />'&nbsp;&nbsp; an image file on disk. <br />'<br />' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,<br />' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED<br />' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.<br />'**************************************************************************/<br />&nbsp;<br />using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Web;<br />using System.Web.UI;<br />using System.Web.UI.WebControls;<br />using Microsoft.WindowsAPICodePack.DirectX;<br />using Microsoft.WindowsAPICodePack.DirectX.Direct2D1;<br />using Microsoft.WindowsAPICodePack.DirectX.WindowsImagingComponent;<br />using Microsoft.WindowsAPICodePack.DirectX.DirectWrite;<br />&nbsp;<br />namespace D2DServerSide<br />{<br />&nbsp;&nbsp;&nbsp; public partial class _Default : System.Web.UI.Page<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D2DFactory d2dFactory;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImagingFactory wicFactory;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWriteFactory dwriteFactory;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D2DBitmap d2dBitmapBarcode;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RenderTarget wicRenderTarget;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RenderTargetProperties renderProps = new RenderTargetProperties<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PixelFormat = new PixelFormat(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.Graphics.Format.B8G8R8A8UNorm,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AlphaMode.Ignore),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Usage = RenderTargetUsages.None,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RenderTargetType = RenderTargetType.Software<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Demonstrates how to create a Direct2D bitmap based on image data in memory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private void CreateBitmap()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We have a 32 bpp Bitmap.&nbsp; This is one example. <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The width and height are:&nbsp; 69 x 23<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var size = new SizeU((uint)69, (uint)23);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitmapProperties bmpProp = new BitmapProperties(new PixelFormat(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.Graphics.Format.B8G8R8A8UNorm,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AlphaMode.Ignore), wicRenderTarget.Dpi.X, wicRenderTarget.Dpi.Y);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d2dBitmapBarcode = wicRenderTarget.CreateBitmap(size, bmpProp);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nWidth = (int)size.Width;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nHeight = (int)size.Height;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] testData = new byte[nWidth * nHeight * 4];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte TestByte = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nCurrentDest = 0;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int y = 0; y &lt; nHeight; y++)<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; for (int x = 0; x &lt; nWidth; x++)<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; byte CurrByte = (byte)TestByte++;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testData.SetValue(CurrByte, nCurrentDest);&nbsp;&nbsp; // blue<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testData.SetValue(CurrByte, nCurrentDest + 1);&nbsp; // green<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testData.SetValue(CurrByte, nCurrentDest + 2);&nbsp; // red<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nCurrentDest += 4;<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;&nbsp;&nbsp;&nbsp;&nbsp; d2dBitmapBarcode.CopyFromMemory(testData, ((uint)nWidth) * 4 );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void Button1_Click(object sender, EventArgs e)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Create Factories.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d2dFactory = D2DFactory.CreateFactory(D2DFactoryType.Multithreaded);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicFactory = ImagingFactory.Create();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwriteFactory = DWriteFactory.CreateFactory();<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float ShippingLabelWidth = 500.0f;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float ShippingLabelHeight = 500.0f;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SizeU size = new SizeU((uint)ShippingLabelWidth, (uint)ShippingLabelHeight);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImagingBitmap wicBitmap = wicFactory.CreateImagingBitmap(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size.Width,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size.Height,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PixelFormats.Bgr32Bpp,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitmapCreateCacheOption.CacheOnLoad);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget =<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d2dFactory.CreateWicBitmapRenderTarget(wicBitmap, renderProps);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a sample Bitmap<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CreateBitmap();<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.BeginDraw();<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.Clear(new ColorF(0, 1, 0, 1));&nbsp; // clear the background<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SolidColorBrush blackSolidColorBrush;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blackSolidColorBrush = wicRenderTarget.CreateSolidColorBrush(new ColorF(0, 0, 0, 1));<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Render an Ellipse<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ellipse ellipse = new Ellipse();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ellipse.Point = new Point2F(300.0f, 300.0f);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ellipse.RadiusX = 100.0f;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ellipse.RadiusY = 150.0f;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.DrawEllipse(ellipse, blackSolidColorBrush, 10.0f);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Render a Rectangle<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RectF rect;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rect = new RectF(130, 30, 200, 100);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.DrawRectangle(rect, blackSolidColorBrush, 10.0f);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Render text rotated<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextFormat textFormat_Value;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; textFormat_Value = dwriteFactory.CreateTextFormat("Arial", 17,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.DirectWrite.FontWeight.Bold,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.DirectWrite.FontStyle.Normal,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft.WindowsAPICodePack.DirectX.DirectWrite.FontStretch.Normal);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RectF renderText_Value;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; renderText_Value = new RectF(10, 150, 180, 250);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.Transform = Matrix3x2F.Rotation(90, new Point2F(100, 95));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.DrawText("This is a test", textFormat_Value,<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; renderText_Value, blackSolidColorBrush);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.Transform = Matrix3x2F.Translation(0, 0);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RectF DrawBitmap_Rect;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DrawBitmap_Rect = new RectF(10, 275, 180, 350);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.DrawBitmap(d2dBitmapBarcode, 1.0f,<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitmapInterpolationMode.NearestNeighbor, DrawBitmap_Rect);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicRenderTarget.EndDraw();<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<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; // This code will need write permissions to the folder on the server that<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you wish to save the image file to.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // You will need to grant permission to the "Network Service" user<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; account.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicBitmap.SaveToFile(wicFactory, ContainerFormats.Png,<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "c:\\SampleFiles\\Images\\test.png");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception ex)<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; // Catch the exception that is unhandled in TryCast.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type ExceptionType = ex.GetType();<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Check for System.UnauthorizedAccessException here.&nbsp; You will need to<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; grant permission<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; to the "Network Service" user account for the folder on the server<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; that you wish to save the image file to.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Restore the original unhandled exception.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<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; // Clean up<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d2dFactory.Dispose();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wicFactory.Dispose();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwriteFactory.Dispose();<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 />}</span></span></span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">Run-time requirements for Direct2D:</span></span></p>
<p><span style="font-family: Calibri; font-size: small;">-</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: small;"><span style="font-family: Calibri;">Windows 7 or Windows Vista with Service Pack 2 (SP2) and Platform Update for Windows Vista and later.</span></span></p>
<p><span style="font-family: Calibri; font-size: small;">-</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: small;"><span style="font-family: Calibri;">Windows Server 2008 R2 or Windows Server 2008 with Service Pack 2 (SP2) and Platform Update for Windows Server 2008 and later.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">For Windows XP and Windows Server 2003, you will need to use Win32 GDI.&nbsp; For more information on GDI, see:&nbsp;&nbsp; </span></span><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145203(v=vs.85).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/windows/desktop/dd145203(v=vs.85).aspx</span></a></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">For more information on Direct2D, see:</span></span></p>
<p><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd370990(v=vs.85).aspx"><span style="color: #0563c1; font-family: Calibri; font-size: small;">msdn.microsoft.com/en-us/library/windows/desktop/dd370990(v=vs.85).aspx</span></a></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;"><span style="font-family: Calibri;">For more information on the Windows API Code Pack for Microsoft .NET Framework, see: </span></span></p>
<p><a href="https://archive.msdn.microsoft.com/WindowsAPICodePack"><span style="color: #0563c1; font-family: Calibri; font-size: small;">archive.msdn.microsoft.com/WindowsAPICodePack</span></a></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>
<p><span style="font-family: Calibri; font-size: small;">&nbsp;</span></p>]]></content:encoded>
    </item>
    <item>
      <title>Ways to capture the screen</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/ways-to-capture-the-screen</link>
      <pubDate>Mon, 25 Mar 2013 05:52:00 GMT</pubDate>
      <dc:creator><![CDATA[David Wooden - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2013/03/25/ways-to-capture-the-screen/</guid>
      <description><![CDATA[Capturing the screen (or put another way, creating an in-memory&nbsp;copy&nbsp;of the image...]]></description>
      <content:encoded><![CDATA[<p>Capturing the screen (or put another way, creating an in-memory&nbsp;copy&nbsp;of the image currently being displayed on the screen, for re-display, printing, or later saving) is a task with many different solutions.&nbsp; I'll try to enumerate the possibilities below.&nbsp; This isn't a perfect or complete list, but it covers the best supported ways, and lists some of their drawbacks.</p>
<p>1 - Use the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/hh404487(v=VS.85).aspx#feedback">Desktop Duplication API</a>.&nbsp;&nbsp;This is a very powerful and full-featured API, which provides access to every frame of desktop update, BUT, it is not available prior to Windows 8.</p>
<p>One drawback is that most full-screen <strong>exclusive</strong> mode DirectX or OpenGL applications will not be able to be captured with Desktop Duplication.&nbsp;&nbsp;Exclusive mode really means that the &lsquo;Windowed&rsquo; field of <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb172588(v=vs.85).aspx">D3DPRESENT_PARAMETERS</a> is set to false.&nbsp; Some apps are not in true full-screen mode and are windowed, but with the window set to the size of the desktop.&nbsp; These can still be captured.</p>
<p>To make matters a little more confusing, newer DirectX (11.1 and later) exclusive mode apps <strong>can</strong> be captured with the Desktop Duplication API, unless they "opt-out" and specifically disallow it (in which case they won't be capture-able by Desktop Duplication, just like a pre-11.1 DirectX app).</p>
<p>2&nbsp;- The old standby, GDI, can still capture the screen.&nbsp; Typically, <a href="https://social.msdn.microsoft.com/search/en-us/windows/desktop?query=bitblt&amp;Refinement=181">BitBlt</a> is used.&nbsp; This technique is not perfect, and there are some things,&nbsp;such as multimedia output, that won't&nbsp;get captured.</p>
<p>BitBlt can also can be slow, although you can get much better performance by making sure that the bitmap&nbsp;(that you are capturing into) is&nbsp;the same resolution as the screen.&nbsp; To assure this, you could use <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183488(v=vs.85).aspx">CreateCompatibleBitmap</a>&nbsp;(for a device-dependent bitmap), or <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd183494(v=vs.85).aspx">CreateDIBSection</a>&nbsp;(for a device-independent bitmap).&nbsp; If you use CreateDIBSection, just make sure the bit-depth and layout matches the screen's.&nbsp; This allows BitBlt to avoid any color conversion, which can drastically slow everything down.&nbsp; Here's what such code might look like from a high level...</p>
<p><span style="font-family: courier new,courier; font-size: small;">// Pseudo-code...</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">HDC hDCScreen = GetDC(NULL);</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">HDC hDCMem = CreateCompatibleDC(hDCScreen);</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">HBITMAP hBitmap = CreateCompatibleBitmap(hDCScreen, screenwidth, screenheight);</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">SelectObject(hDCMem, hBitmap);</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">BitBlt(hDCMem, 0, 0, screenwidth, screenheight, 0, 0, SRCCOPY);</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">&hellip;</span></p>
<p>&nbsp;</p>
<p>3 - Another option is to use Direct3D.&nbsp; Note that some have reported that this <strong>can</strong> actually be slower than BitBlt, but performance of any technique will depend a lot on the hardware and graphics settings (regardless of the method used).&nbsp; To do this with Direct3D, you could use <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb174405(v=vs.85).aspx">GetRenderTargetData</a> to copy the rendering surface (retrieved with <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb174404(v=vs.85).aspx">GetRenderTarget</a>) to an off-screen surface (which can be created with <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb174358(v=vs.85).aspx">CreateOffscreenPlainSurface</a>).&nbsp; After copying the surface data this way, you can save the contents of the surface to a file using <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb205431(v=vs.85).aspx">D3DXSaveSurfaceToFile</a>.</p>
<p>&nbsp;</p>
<p>4 - Yet another possibility is to use Windows Media technologies to do the capture (specifically, <a href="https://www.microsoft.com/expression/">Expression Encoder</a> will do this if you just need another application).&nbsp; To do it programmatically yourself (using Windows Media), you can use the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ff819485(v=vs.85).aspx">Windows Media Video 9 Screen codec</a>.</p>
<p>&nbsp;</p>
<p>5 - Finally, for pre-Windows 8 systems, you could develop a <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx">Mirror Driver</a> to do this (Windows 8 uses another driver model, which is also described under the preceding&nbsp;link).</p>
<p>&nbsp;</p>
<p>Some of the above techniques (particularly #2 and #3) can also be used to capture only a single window. &nbsp;Note that&nbsp;iif you use BitBlt to do this, you could "or in" the CAPTUREBLT flag if you wanted to capture windows that are layered on top of your window .&nbsp; The <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd162869(v=vs.85).aspx">PrintWindow</a> API is another good option for capturing only a single window (not listed above since it can't capture the entire screen).</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Troubleshooting CreateWindowEx failures</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/troubleshooting-createwindowex-failures</link>
      <pubDate>Mon, 05 Nov 2012 16:21:00 GMT</pubDate>
      <dc:creator><![CDATA[Dave Anderson-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2012/11/05/troubleshooting-createwindowex-failures/</guid>
      <description><![CDATA[Several years back, my team was handling multiple issues where Windows Forms application would throw...]]></description>
      <content:encoded><![CDATA[<p>Several years back, my team was handling multiple issues where Windows Forms application would throw an exception while trying to create a new form, control, etc. While the description string that Windows Forms included in the exception ("Error creating window handle.") indicated that a call to CreateWindowEx failed, the exception did not provide any information on why the call failed. At the time, I wrote a small document that described the steps for debugging native and .NET applications to determine why a given CreateWindowEx call fails. One of my colleagues suggested creating a blog post with the information from that document, so here we go.</p>
<p>&nbsp;</p>
<h4>The CreateWindowEx function</h4>
<p>We should first discuss how the CreateWindowEx function works before diving into how to troubleshoot CreateWindowEx failures.Windows applications, including .NET applications that use Windows Forms or Windows Presentation Foundation, create their windows by calling the CreateWindowExA or CreateWindowExW functions. Both functions internally call a common USER32 function that will perform some&nbsp;parameter validation, such as the window styles and handles specified in the call, handle creating a MDI child window if the WS_EX_MDICHILD extended window style is specified and processes the current activation context for the calling thread. If all is well on the USER32-side of the CreateWindowEx call, it then calls into the kernel-mode (WIN32K) implementation of CreateWindowEx.</p>
<p>The kernel-side of the CreateWindowEx call will first check the following conditions:</p>
<ul>
<li>Does the specified window class exist?</li>
<li>Can the text for the atom be retrieved, if the caller specified an atom for the class name?</li>
<li>Was a parent window specified, if creating a child window?</li>
<li>Will the new window exceed the nested window depth limit, if creating a child window or an owned window? The default limit&nbsp;is 50 levels deep and can be configured via the USERNestedWindowLimit registry value.</li>
<li>Does the parent/owner window belong to the same desktop as the calling thread?</li>
</ul>
<p>Assuming that each of these checks pass, CreateWindowEx will perform the following tasks when attempting to&nbsp;create a new window object:</p>
<ul>
<li>Determine if creating a handle for the new window&nbsp;object will exceed the&nbsp;User handle quota limit for the calling process.</li>
<li>Allocates memory for the new window object from the desktop's heap.</li>
<li>Initializes the memory for the new window object</li>
<li>Creates a handle for the new window object in the User handle table</li>
</ul>
<p>Assuming that the window object was created successfully, CreateWindowEx will notify registered WinEvent and WH_CBT hooks that a new window object has been created, determine the location, size, z-order position, etc. of the new window, followed by calling the window's WndProc to process WM_NCCREATE and WM_CREATE window messages. CreateWindowEx then returns the handle of the new window object.</p>
<p>&nbsp;</p>
<h4>Causes of CreateWindowEx failures</h4>
<p>You may have noticed some of the conditions that will cause CreateWindowEx to fail from the previous section. Let's enumerate conditions that will cause CreateWindowEx to fail:</p>
<ul>
<li>The specified window class does not exist.</li>
<li>Using invalid window styles or extended window styles.</li>
<li>Using invalid User handles, such as window handles and menu handles.</li>
<li>Attempting to create a child window without specifying a parent window.</li>
<li>Attempting to create a child window or an owned window and the specified parent/owner belongs to a different desktop than the calling thread.</li>
<li>Creating a child or owned window will exceed the nested window limit.</li>
<li>Creating a new window object will exceed the handle quota for the calling process.</li>
<li>There is insufficient heap available in the desktop&rsquo;s heap to allocate memory for the new window object.</li>
<li>There are no available entries in the User handle table.</li>
</ul>
<p>Note that while&nbsp;a new window object is successfully created, the CreateWindowEx function may still return NULL. How can this happed?</p>
<p>Recall that before returning, CreateWindowEx will call the window's WndProc to process a WM_NCCREATE and a WM_CREATE window message. The WndProc can stop the window creation by returning&nbsp;0 when handling the WM_NCCREATE window message or by returning -1 when handling the WM_CREATE window message. CreateWindowEx handles this situation by destroying the window object and returning NULL.&nbsp;Additionally, a WH_CBT hook&nbsp;can stop the window creation by returning 0 from its hook procedure when handling the HCBT_CREATEWND notification.</p>
<p>&nbsp;</p>
<h4>CreateWindowEx failures and GetLastError</h4>
<p>The Windows SDK documentation for the CreateWindowEx function states that extended error information can be obtained by calling GetLastError when CreateWindowEx returns NULL. But how useful is the error code returned by GetLastError?</p>
<p>The answer is that it depends on the error condition that caused CreateWindowEx to return NULL.</p>
<p>For example, GetLastError will return ERROR_CANNOT_FIND_WND_CLASS if the window class does not exist. On the other hand, GetLastError may return NOERROR or some error code that seems unrelated to calling CreateWindowEx&nbsp;if the window's&nbsp;WndProc stopped the window creation when handling the WM_NCCREATE or WM_CREATE messages.</p>
<p>&nbsp;</p>
<h4>Troubleshooting CreateWindowEx failures</h4>
<p>Although GetLastError does not always return a valid error code on a CreateWindowEx failure, you should always check the error code as it may help diagnose the source of the failure. Current versions of the .NET Framework included the value returned by GetLastError when throwing a Win32Exception. Earlier versions of the .NET Framework did not include the error code when throwing&nbsp;a Win32Exception.</p>
<p>Hitting the User handle quota limit for the process&nbsp;should be pretty simple to identify. You can view the User object handle count for a process in Task Manager (taskmgr.exe) or by calling the GetGuiResources function. If the handle count is approaching the User handle quota limit, then Task Manager and GetGuiResources is likely reporting a value near the limit. Additionally, GetLastError should return ERROR_NO_MORE_USER_HANDLES. The default limit is 10,000 and can be configured via the USERProcessHandleQuota registry value.</p>
<p>Running out of desktop heap is a little more difficult to identify since there is no mechanism that ships with Windows to measure available desktop heap for a given desktop.&nbsp;However, GetLastError should return ERROR_NOT_ENOUGH_MEMORY. You can find more information on desktop heap at <a href="https://blogs.msdn.com/b/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx">blogs.msdn.com/b/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx.</a></p>
<p>Then there are the scenarios where CreateWindowEx fails and GetLastError returns NOERROR or what appears to be an invalid error code.&nbsp;Generally, in this scenario, the failure is caused by the window's WndProc stopping the window creation. There are some user-mode&nbsp;troubleshooting options&nbsp;that you can use&nbsp;before you start stepping through the disassembly of the kernel side of the CreateWindowEx function.</p>
<p>One approach is to&nbsp;set a&nbsp;WH_CBT window hook on the thread calling CreateWindowEx to determine if a window object has been created for a given CreateWindowEx call. Recall that&nbsp;WH_CBT hook procedures&nbsp;are called with the HCBT_CREATEWND notification after&nbsp;a window object has been created and before the window procedure is called to handle the WM_NCCREATE and WM_CREATE window&nbsp;messages.</p>
<p>You can then set a WH_CALLWNDPROC window hook on the thread calling CreateWindowEx or set a breakpoint on the window's WndProc (if known)&nbsp;to determine if the window's WndProc is called to handle the WM_NCCREATE and WM_CREATE window messages. You can also use the Spy++ tool included with Visual Studio to monitor when windows owned by a thread process WM_NCCREATE and WM_CREATE window messages.</p>
<p>&nbsp;</p>
<h4>Debugging CreateWindowEx with WinDBG</h4>
<p>I tend to use the Debugging Tools for Windows for most of my debugging work, specifically WinDBG. The debugging tasks described below are from a 32-bit Windows&nbsp;7 system using the version of WinDBG included with the Windows SDK for Windows&nbsp;7 and the public Microsoft symbol server.</p>
<p>You may encounter a scenario where you are trying to troubleshoot a CreateWindowEx failure where you do not know the address of the window's WndProc, such as a third-party control. How do you set a breakpoint on the WndProc?</p>
<p>Recall that most of the work for creating a window is done in kernel mode, which includes calling the window's WndProc to process&nbsp;WM_NCCREATE and WM_CREATE window messages. Since the kernel side of CreateWindowEx tries to call&nbsp;a user mode function, Windows needs to transition back into user mode to call&nbsp;the WndProc, which is done via the DispatchClientMessage function.</p>
<p>You can use a breakpoint on CreateWindowEx that enables a breakpoint on DispatchClientMessage and another breakpoint when CreateWindowEx returns that disables the breakpoint on DispatchClientMessage. This should allow you to determine if the window procedure of the window is being called.</p>
<p>Here are breakpoints that I used when debugging an instance of&nbsp;Notepad:</p>
<p><span style="font-family: courier new,courier;">0:000&gt; bl</span><br /><span style="font-family: courier new,courier;">&nbsp;0 e 75934ec3&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001)&nbsp; 0:**** USER32!DispatchClientMessage ".echo ***** DispatchClientMessage *****;dd @esp+4 L4;g"</span><br /><span style="font-family: courier new,courier;">&nbsp;1 e 7592ec7c&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001)&nbsp; 0:**** USER32!CreateWindowExW ".echo ***** CreateWindowExW called *****;be 0;g"</span><br /><span style="font-family: courier new,courier;">&nbsp;2 e 7592ecb0&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001)&nbsp; 0:**** USER32!CreateWindowExW+0x34 ".echo ***** CreateWindowExW returned *****;bd 0;r @eax;g"</span></p>
<p>Breakpoint 0 is initially disabled. It will be enabled when CreateWindowEx is called and disabled when CreateWindowEx returns. When hit, the breakpoint will dump the parameters passed to the function and then resume execution. You could also set up the breakpoint to halt in the debugger where you could then step into the window procedure. Note in the debug output below that the last parameter to DispatchClientMessage is the address of the window procedure.</p>
<p>Breakpoint 1 displays a message that CreateWindowEx is being called, tries to display the class name passed to CreateWindowEx (which will fail if an atom is passed) and enables the breakpoint on DispatchClientMessage.</p>
<p>Breakpoint 2 displays a message that CreateWindowEx is returning, displays the value of the handle that it is returning and disables breakpoint 0.</p>
<p>Below is the debugger ouput from the first CreateWindowEx call in the process:</p>
<p><span style="font-family: courier new,courier;">***** CreateWindowExW called *****</span><br /><span style="font-family: courier new,courier;">***** DispatchClientMessage *****</span><br /><span style="font-family: courier new,courier;">001bf504&nbsp; 00b9fc18 00000081 00000000 001bf56c</span><br /><span style="font-family: courier new,courier;">***** DispatchClientMessage *****</span><br /><span style="font-family: courier new,courier;">001bf548&nbsp; 00b9fc18 00000083 00000000 001bf594</span><br /><span style="font-family: courier new,courier;">***** DispatchClientMessage *****</span><br /><span style="font-family: courier new,courier;">001bf4d4&nbsp; 00b9fc18 00000001 00000000 001bf53c</span><br /><span style="font-family: courier new,courier;">***** DispatchClientMessage *****</span><br /><span style="font-family: courier new,courier;">001bf554&nbsp; 00b9fc18 00000005 00000000 00000000</span><br /><span style="font-family: courier new,courier;">***** DispatchClientMessage *****</span><br /><span style="font-family: courier new,courier;">001bf554&nbsp; 00b9fc18 00000003 00000000 00000000</span><br /><span style="font-family: courier new,courier;">***** CreateWindowExW returned *****</span><br /><span style="font-family: courier new,courier;">eax=000602fe</span></p>
<p>Note the window messages that are being received by the window. WM_NCCREATE is 0x81 and WM_CREATE is 0x1. The other messages are also a part of normal window creation.</p>
<p>In the example above, you might have noticed that I skipped how I found the address of the return from CreateWindowEx in order to set breakpoint 2. The method that I used was to examine the disassembly of the CreateWindowExW function and looked for the return instruction, highlighted below.</p>
<p><span style="font-family: courier new,courier;">0:000&gt; u user32!CreateWindowExW L13</span><br /><span style="font-family: courier new,courier;">USER32!CreateWindowExW:</span><br /><span style="font-family: courier new,courier;">7592ec7c 8bff&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp; edi,edi</span><br /><span style="font-family: courier new,courier;">7592ec7e 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; ebp</span><br /><span style="font-family: courier new,courier;">7592ec7f 8bec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp; ebp,esp</span><br /><span style="font-family: courier new,courier;">7592ec81 6800000040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; 40000000h</span><br /><span style="font-family: courier new,courier;">7592ec86 ff7534&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+34h]</span><br /><span style="font-family: courier new,courier;">7592ec89 ff7530&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+30h]</span><br /><span style="font-family: courier new,courier;">7592ec8c ff752c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+2Ch]</span><br /><span style="font-family: courier new,courier;">7592ec8f ff7528&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+28h]</span><br /><span style="font-family: courier new,courier;">7592ec92 ff7524&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+24h]</span><br /><span style="font-family: courier new,courier;">7592ec95 ff7520&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+20h]</span><br /><span style="font-family: courier new,courier;">7592ec98 ff751c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+1Ch]</span><br /><span style="font-family: courier new,courier;">7592ec9b ff7518&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+18h]</span><br /><span style="font-family: courier new,courier;">7592ec9e ff7514&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+14h]</span><br /><span style="font-family: courier new,courier;">7592eca1 ff7510&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+10h]</span><br /><span style="font-family: courier new,courier;">7592eca4 ff750c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+0Ch]</span><br /><span style="font-family: courier new,courier;">7592eca7 ff7508&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;&nbsp; dword ptr [ebp+8]</span><br /><span style="font-family: courier new,courier;">7592ecaa e8edfeffff&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp;&nbsp; USER32!_CreateWindowEx (7592eb9c)</span><br /><span style="font-family: courier new,courier;">7592ecaf 5d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pop&nbsp;&nbsp;&nbsp;&nbsp; ebp</span><br /><span style="color: #ff0000; font-family: courier new,courier; background-color: #ffff00;">7592ecb0 c23000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret&nbsp;&nbsp;&nbsp;&nbsp; 30h</span></p>
<p>I then use the following syntax to set the breakpoint:</p>
<p><span style="font-family: courier new,courier;">bp2 7592ecb0 ".echo ***** CreateWindowExW returned *****;bd 0;r @eax;g"</span></p>
<p>Alternately, you can set a conditional breakpoint when CreateWindowEx returns and use the !gle command to dump the value that will be returned by GetLastError if CreateWindowEx fails, where the EAX register is zero. In the scenario below, I created a simple Windows Forms application that repeatedly creates child windows until the User handle process quota is reached and CreateWindowEx fails.</p>
<p>I use the following command to set a conditional breakpoint on the return from CreateWindowExW that breaks in the debugger when the function fails:</p>
<p><span style="font-family: courier new,courier;">bp 7592ecb0&nbsp; "j (@eax==0) '.echo ***** CreateWindowExW failed. *****';'g'"</span></p>
<p>Once the debugger breaks on a CreateWindowEx failure, you can obtain the last error value with the !gle command:</p>
<p><span style="font-family: courier new,courier;">0:000&gt; !gle</span><br /><span style="font-family: courier new,courier;">LastErrorValue: (Win32) 0x486 (1158) - The current process has used all of its system allowance of handles for Window Manager objects.</span></p>
<p>You can also execute other debugger commands, including .NET debugger extension commands such as !clrstack:</p>
<p><span style="font-family: courier new,courier;">0:000&gt; .loadby sos clr</span><br /><span style="font-family: courier new,courier;">0:000&gt; !clrstack</span><br /><span style="font-family: courier new,courier;">OS Thread Id: 0xea4 (0)</span><br /><span style="font-family: courier new,courier;">Child SP IP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Call Site</span><br /><span style="font-family: courier new,courier;">001ae9c4 7592ecb0 [InlinedCallFrame: 001ae9c4] </span><br /><span style="font-family: courier new,courier;">001ae9a8 5e6c50ef DomainBoundILStubClass.IL_STUB_PInvoke(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)</span><br /><span style="font-family: courier new,courier;">001ae9c4 5e6a978c [InlinedCallFrame: 001ae9c4] System.Windows.Forms.UnsafeNativeMethods.IntCreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)</span><br /><span style="font-family: courier new,courier;">001aea88 5e6a978c System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)</span><br /><span style="font-family: courier new,courier;">001aead0 5e6a8e9f System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams)</span><br /><span style="font-family: courier new,courier;">001aeb54 5e6a8b82 System.Windows.Forms.Control.CreateHandle()</span><br /><span style="font-family: courier new,courier;">001aebac 5e6a8921 System.Windows.Forms.Control.CreateControl(Boolean)</span><br /><span style="font-family: courier new,courier;">001aebe4 5e6a8818 System.Windows.Forms.Control.CreateControl()</span><br /><span style="font-family: courier new,courier;">001aebfc 5e6b1c31 System.Windows.Forms.Control+ControlCollection.Add(System.Windows.Forms.Control)</span><br /><span style="font-family: courier new,courier;">001aec38 5e6b1aab System.Windows.Forms.Form+ControlCollection.Add(System.Windows.Forms.Control)</span><br /><span style="font-family: courier new,courier;">001aec4c 5ef8f027 System.Windows.Forms.Control.set_ParentInternal(System.Windows.Forms.Control)</span><br /><span style="font-family: courier new,courier;">001aec58 5ebfd59a System.Windows.Forms.Control.set_Parent(System.Windows.Forms.Control)</span><br /><span style="font-family: courier new,courier;">001aec60 002903c3 WindowsFormsApplication1.Form1.button1_Click(System.Object, System.EventArgs)*** WARNING: Unable to verify checksum for WindowsFormsApplication1.exe</span><br /><span style="font-family: courier new,courier;">&nbsp;[D:\Cases\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs @ 24]</span><br /><span style="font-family: courier new,courier;">001aec80 5e654507 System.Windows.Forms.Control.OnClick(System.EventArgs)</span><br /><span style="font-family: courier new,courier;">001aec94 5e656ca2 System.Windows.Forms.Button.OnClick(System.EventArgs)</span><br /><span style="font-family: courier new,courier;">001aecac 5ec3a480 System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)</span><br /><span style="font-family: courier new,courier;">001aecc8 5ec03dd1 System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)</span><br /><span style="font-family: courier new,courier;">001aed5c 5efa6a2f System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier;">001aed60 5efae391 [InlinedCallFrame: 001aed60] </span><br /><span style="font-family: courier new,courier;">001aedb4 5efae391 System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier;">001aedf8 5e6c19f8 System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier;">001aee04 5e6aa393 System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier;">001aee0c 5e6aa311 System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)</span><br /><span style="font-family: courier new,courier;">001aee20 5e6aa256 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)</span><br /><span style="font-family: courier new,courier;">001aefc4 00840ab8 [InlinedCallFrame: 001aefc4] </span><br /><span style="font-family: courier new,courier;">001aefc0 5e6c6c1c DomainBoundILStubClass.IL_STUB_PInvoke(MSG ByRef)</span><br /><span style="font-family: courier new,courier;">001aefc4 5e6ba99f [InlinedCallFrame: 001aefc4] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)</span><br /><span style="font-family: courier new,courier;">001af008 5e6ba99f System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)</span><br /><span style="font-family: courier new,courier;">001af00c 5e6ba5cc [InlinedCallFrame: 001af00c] </span><br /><span style="font-family: courier new,courier;">001af0a4 5e6ba5cc System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)</span><br /><span style="font-family: courier new,courier;">001af0fc 5e6ba421 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)</span><br /><span style="font-family: courier new,courier;">001af12c 5e642815 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)</span><br /><span style="font-family: courier new,courier;">001af140 002900ae WindowsFormsApplication1.Program.Main() [D:\Cases\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs @ 18]</span><br /><span style="font-family: courier new,courier;">001af370 710d21bb [GCFrame: 001af370]&nbsp;</span></p>
<h4>Conclusion</h4>
<p>Hopefully you will be able to apply some of the techniques described in this post if you find yourself in the situation where you are trying to troubleshoot CreateWindowEx failures in managed and native applications.</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Debugging Windows Forms Application Hangs During SystemEvents.UserPreferenceChanged</title>
      <link>https://docs.microsoft.com/archive/blogs/dsui_team/debugging-windows-forms-application-hangs-during-systemevents-userpreferencechanged</link>
      <pubDate>Wed, 31 Oct 2012 08:30:00 GMT</pubDate>
      <dc:creator><![CDATA[Keith Fink-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dsui_team/2012/10/31/debugging-windows-forms-application-hangs-during-systemevents-userpreferencechanged/</guid>
      <description><![CDATA[Hi Everyone,
One of the most common issues we debug related to Windows Forms applications is when...]]></description>
      <content:encoded><![CDATA[<p>Hi Everyone,</p>
<p>One of the most common issues we debug related to Windows Forms applications is when an application becomes unresponsive due to the <a href="https://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.userpreferencechanged(v=vs.80).aspx">SystemEvents.UserPreferenceChanged event</a>. This&nbsp;blog to explain what is actually occurring, and how to find and fix the culprit. The reason this occurs and the solution is explained in KnowledgeBase article 943139.</p>
<p><strong>Windows Forms application freezes when system settings are changed or the workstation is locked</strong><br /><a href="https://support.microsoft.com/kb/943139/EN-US">support.microsoft.com/kb/943139/EN-US</a></p>
<p>For the purposes of this discussion, I&rsquo;m going to talk mainly about System.Windows.Forms.Control or just &ldquo;Control&rdquo; (remember that a Windows Form itself is a derivative of the Control class).</p>
<h3><strong>Why Windows Forms Applications Become Unresponsive&nbsp;During SystemEvents.UserPreferenceChanged</strong></h3>
<p>As KB article 943139 mentions, the application may become unresponsive when a Windows Forms Control has been created on a thread which doesn&rsquo;t pump window messages; and when the application&rsquo;s UI thread receives and processes a WM_SETTINGCHANGE message. Note the window message could be for other &ldquo;settings&rdquo; related messages such as WM_SYSCOLORCHANGE, WM_DISPLAYCHANGED, WM_THEMECHANGED, among others.</p>
<p>The SystemEvents class uses a hidden window internally to handle processing the window messages related to the SystemEvents class. If you were to look at this under Spy++, the window caption for this hidden window starts with &ldquo;.NET-BroadcastEventWindow&rdquo;.&nbsp; So when a WM_SETTINGCHANGE (or related) message comes in, the Winforms message pump retrieves it from the thread&rsquo;s message queue and dispatches it to the window procedure associated with the &ldquo;.NET-BroadcastEventWindow&rdquo;. This uses the thread&rsquo;s SynchronizationContext.Send method to invoke the delegate which eventually raises the SystemEvents.UserPreferenceChanged event for the target window.</p>
<p>Windows Forms installs a <a href="https://msdn.microsoft.com/en-us/library/system.windows.forms.windowsformssynchronizationcontext(v=vs.100).aspx">WindowsFormsSynchronizationContext</a>&nbsp;on each thread which has created a Windows Forms Control. This derived SynchronizationContext is used by Windows Forms to handle communications between various threads with Windows Forms controls. So the delegate which SystemEvents wants to invoke eventually raises UserPreferenceChanged is invoked, it is done so on the WindowsFormsSynchronizationContext.&nbsp; The internal implementation of WindowsFormsSynchronizationContext uses a Windows Forms control known as the &ldquo;Marshaling Control&rdquo; to handle communication between various threads, and subsequently the overridden SynchronizationContext.Send method uses <a href="https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invoke(v=vs.100).aspx">Control.Invoke</a>&nbsp;to marshal the call from the current thread to the target thread. In order for Control.Invoke to return, the target thread must be pumping window messages.When the target thread does not pump window messages, the UI thread is going to block indefinitely, and now you&rsquo;re hung.</p>
<h3><strong>Debugging a Windows Forms Application in the Unresponsive State</strong></h3>
<p>So what does this look like under the debugger? Alright, let&rsquo;s debug this after we are in the hung state to see what&rsquo;s happening. The rest of this blog assumes you are familiar with the use of Windbg,&nbsp;user mode and .NET debugging.&nbsp;If you attach Windbg to a Windows Forms application in this state, your main UI thread should look something like this.</p>
<p>&nbsp;<span style="font-family: courier new,courier; font-size: small;">0:000&gt;knL</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;# ChildEBP RetAddr&nbsp; <br /></span><span style="font-family: courier new,courier; font-size: small;">00 0018e2e0 75340bdd ntdll!NtWaitForMultipleObjects+0x15</span><br /><span style="font-family: courier new,courier; font-size: small;">01 0018e37c 758a1a2c&nbsp;KERNELBASE!WaitForMultipleObjectsEx+0x100<br /></span><span style="font-family: courier new,courier; font-size: small;">03 0018e418 </span><span style="font-family: courier new,courier; font-size: small;">76da2bf1&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">USER32!RealMsgWaitForMultipleObjectsEx+0x14d<br /></span><span style="font-family: courier new,courier; font-size: small;">04 0018e444 </span><span style="font-family: courier new,courier; font-size: small;">76d9202d&nbsp;ole32!CCliModalLoop::BlockFn+0xa1<br /></span><span style="font-family: courier new,courier; font-size: small;">05 0018e4c4 </span><span style="font-family: courier new,courier; font-size: small;">79e0d245&nbsp;ole32!CoWaitForMultipleHandles+0xcd<br /></span><span style="font-family: courier new,courier; font-size: small;">06 0018e4e4 </span><span style="font-family: courier new,courier; font-size: small;">79e0d1a6&nbsp;mscorwks!NT5WaitRoutine+0x51<br /></span><span style="font-family: courier new,courier; font-size: small;">07 0018e550 79e0d10a&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">mscorwks!MsgWaitHelper+0xa5<br /></span><span style="font-family: courier new,courier; font-size: small;">08 0018e570 </span><span style="font-family: courier new,courier; font-size: small;">79ec42d8&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">mscorwks!Thread::DoAppropriateAptStateWait+0x28<br /></span><span style="font-family: courier new,courier; font-size: small;">09 0018e5f4 </span><span style="font-family: courier new,courier; font-size: small;">79ec436d&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">mscorwks!Thread::DoAppropriateWaitWorker+0x13c<br /></span><span style="font-family: courier new,courier; font-size: small;">0a 0018e644 </span><span style="font-family: courier new,courier; font-size: small;">79e64af8&nbsp;mscorwks!Thread::DoAppropriateWait+0x40<br /></span><span style="font-family: courier new,courier; font-size: small;">0b 0018e748 </span><span style="font-family: courier new,courier; font-size: small;">791169df&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">mscorwks!WaitHandleNative::CorWaitOneNative+0x156<br /></span><span style="font-family: courier new,courier; font-size: small;">0c 0018e764 </span><span style="font-family: courier new,courier; font-size: small;">79116995&nbsp;mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int64, </span><span style="font-family: courier new,courier; font-size: small;">Boolean)+0x2f<br /></span><span style="font-family: courier new,courier; font-size: small;">0d 0018e77c </span><span style="font-family: courier new,courier; font-size: small;">7b3f2231&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int32, Boolean)+0x25<br /></span><span style="font-family: courier new,courier; font-size: small;">0e 0018e798 </span><span style="font-family: courier new,courier; font-size: small;">7aed4c20&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)+0x89<br /></span><span style="font-family: courier new,courier; font-size: small;">0f 0018e830 </span><span style="font-family: courier new,courier; font-size: small;">7b3f3bb0&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, </span><span style="font-family: courier new,courier; font-size: small;">System.Delegate, System.Object[], Boolean)+0x31c<br /></span><span style="font-family: courier new,courier; font-size: small;">10 0018e86c </span><span style="font-family: courier new,courier; font-size: small;">7b621873&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Control.Invoke(System.Delegate, </span><span style="font-family: courier new,courier; font-size: small;">System.Object[])+0x50<br /></span><span style="font-family: courier new,courier; font-size: small;">11 0018e884 </span><span style="font-family: courier new,courier; font-size: small;">04f42496&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback, </span><span style="font-family: courier new,courier; font-size: small;">System.Object)+0x5f<br /></span><span style="font-family: courier new,courier; font-size: small;">12 0018e8b8 </span><span style="font-family: courier new,courier; font-size: small;">04f4064f&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_ni!Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke(Boolean, </span><span style="font-family: courier new,courier; font-size: small;">System.Object[])+0x62<br /></span><span style="font-family: courier new,courier; font-size: small;">13 0018e904 </span><span style="font-family: courier new,courier; font-size: small;">04f4195b&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_ni!Microsoft.Win32.SystemEvents.RaiseEvent(Boolean, System.Object, </span><span style="font-family: courier new,courier; font-size: small;">System.Object[])+0x10f<br /></span><span style="font-family: courier new,courier; font-size: small;">14 0018e920 </span><span style="font-family: courier new,courier; font-size: small;">04b85989&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_ni!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(Int32, IntPtr, </span><span style="font-family: courier new,courier; font-size: small;">IntPtr)+0x77<br /></span><span style="font-family: courier new,courier; font-size: small;">15 0018e98c </span><span style="font-family: courier new,courier; font-size: small;">009f09e4&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_ni!Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, </span><span style="font-family: courier new,courier; font-size: small;">IntPtr)+0x189<br /></span><span style="font-family: courier new,courier; font-size: small;">WARNING:</span><span style="font-family: courier new,courier; font-size: small;">Frame IP not in any known module. Following frames may be wrong.<br /></span><span style="font-family: courier new,courier; font-size: small;">16 0018e9b0 </span><span style="font-family: courier new,courier; font-size: small;">770662fa&nbsp;0x9f09e4 <br /></span><span style="font-family: courier new,courier; font-size: small;">17 0018e9dc </span><span style="font-family: courier new,courier; font-size: small;">77066d3a&nbsp;USER32!InternalCallWinProc+0x23<br /></span><span style="font-family: courier new,courier; font-size: small;">18 0018ea54 </span><span style="font-family: courier new,courier; font-size: small;">770677c4&nbsp;USER32!UserCallWinProcCheckWow+0x109<br /></span><span style="font-family: courier new,courier; font-size: small;">19 0018eab4 </span><span style="font-family: courier new,courier; font-size: small;">7706788a&nbsp;USER32!DispatchMessageWorker+0x3bc<br /></span><span style="font-family: courier new,courier; font-size: small;">1a 0018eac4 </span><span style="font-family: courier new,courier; font-size: small;">00491a32&nbsp;USER32!DispatchMessageW+0xf<br /></span><span style="font-family: courier new,courier; font-size: small;">1b 0018eae0 </span><span style="font-family: courier new,courier; font-size: small;">7aed8cee&nbsp;CLRStub[StubLinkStub]@491a32<br /></span><span style="font-family: courier new,courier; font-size: small;">1c 0018eb94 </span><span style="font-family: courier new,courier; font-size: small;">7aed8957&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, </span><span style="font-family: courier new,courier; font-size: small;">Int32, Int32 +0x24e<br /></span><span style="font-family: courier new,courier; font-size: small;">1d 0018ebec </span><span style="font-family: courier new,courier; font-size: small;">7aed87a1&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, </span><span style="font-family: courier new,courier; font-size: small;">System.Windows.Forms.ApplicationContext)+0x177<br /></span><span style="font-family: courier new,courier; font-size: small;">1e 0018ec1c </span><span style="font-family: courier new,courier; font-size: small;">7ae95911&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, </span><span style="font-family: courier new,courier; font-size: small;">System.Windows.Forms.ApplicationContext)+0x61<br /></span><span style="font-family: courier new,courier; font-size: small;">1f 0018ec34 </span><span style="font-family: courier new,courier; font-size: small;">004600ae&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">System_Windows_Forms_ni!System.Windows.Forms.Application.Run(System.Windows.Forms.Form)+0x31<br /></span><span style="font-family: courier new,courier; font-size: small;">20 0018ec40 </span><span style="font-family: courier new,courier; font-size: small;">79d61b4c&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">UserPreferencesHang!UserPreferencesHang.Program.Main()+0x3e</span></p>
<p>You can see in the above callstack the same sequence of events I described earlier. In this particular case, a WM_SYSCOLORCHANGE message was dispatched to the window procedure.</p>
<p>The window procedure handles this by eventually calling Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke. This&nbsp;obtains the thread&rsquo;s SynchronizationContext (in this case, the WindowsFormsSynchronizationContext) and calling its Send method.&nbsp;This calls into Control.Invoke, which then calls into System.Threading.WaitHandle.WaitOne, etc. which we eventually see stuck in kernel32!WaitForMultipleObjects. Since the target thread isn&rsquo;t pumping window messages, we are&nbsp;blocked indefinitely. To determine the target thread, we need to do some managed debugging using the managed debugger extension (sos.dll).</p>
<p>First, load sos.dll into the debugger using the .loadby command.<strong> NOTE: If using .NET 4.0 / 4.5, use "clr" instead of "mscorwks" below.</strong></p>
<p>&nbsp;<span style="font-family: courier new,courier; font-size: small;">0:000&gt; </span><span style="font-family: courier new,courier; font-size: small;">.loadby sos.dll mscorwks</span></p>
<p>Let&rsquo; s examine the thread&rsquo;s managed stack objects, looking for the lowest most instance of a WindowsFormsSynchonizationContext object.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;!dumpstackobjects</span><br /><span style="font-family: courier new,courier; font-size: small;">OS Thread Id: 0x19ac (0)</span><br /><span style="font-family: courier new,courier; font-size: small;">ESP/REG&nbsp; Object&nbsp;&nbsp; Name</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e5e0 0259dd78 System.Windows.Forms.WindowsFormsSynchronizationContext</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e66c 025ebbc4 System.Threading.ManualResetEvent</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e680 025ebbc4 System.Threading.ManualResetEvent</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e6e8 025ebbc4 System.Threading.ManualResetEvent</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e6ec 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e6f8 025ebbc4 System.Threading.ManualResetEvent</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e700 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e730 025ebbdc Microsoft.Win32.SafeHandles.SafeWaitHandle</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e760 025ebbc4 System.Threading.ManualResetEvent</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e778 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e78c 025eba7c System.Windows.Forms.Control+MultithreadSafeCallScope</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7cc 025de514 System.Windows.Forms.PropertyStore</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7d4 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7d8 025ebb10 System.Collections.Queue</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7dc 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7e0 025ebad0 System.Windows.Forms.Control+ThreadMethodEntry</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7e4 025eba88 System.Threading.ExecutionContext</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7e8 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7ec 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7f4 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e7fc 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e824 025eba7c System.Windows.Forms.Control+MultithreadSafeCallScope</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e828 025eba48 System.Threading.SendOrPostCallback</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e82c 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e83c 025eba68 System.Object[]&nbsp;&nbsp;&nbsp;(System.Object[])</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e840 025eba48 System.Threading.SendOrPostCallback</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e844 025eba7c System.Windows.Forms.Control+MultithreadSafeCallScope</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e85c 025de014 System.Threading.Thread</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e860 025eb558 System.Object[]&nbsp;&nbsp;&nbsp;(System.Object[])</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e864 025de4ac System.Windows.Forms.Application+MarshalingControl</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e868 025eba48 System.Threading.SendOrPostCallback</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e874 025eba68 System.Object[]&nbsp;&nbsp;&nbsp;(System.Object[])</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e878 025eba68 System.Object[]&nbsp;&nbsp;&nbsp;(System.Object[])</span><br /><span style="font-family: courier new,courier; font-size: small;">0018e87c 025eba48 System.Threading.SendOrPostCallback</span><br /><span style="font-family: courier new,courier; font-size: small; background-color: #ffff00;">0018e880 025de3f8 System.Windows.Forms.WindowsFormsSynchronizationContext</span><br /><span style="font-family: courier new,courier; font-size: small;">&lt;snip&gt;</span></p>
<p>I&rsquo;ve highlighted the relevant WindowsFormsSynchronizationContext object above. Now we can dump it out to examine it.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;</span><span style="font-family: courier new,courier; font-size: small;">!dumpobj <span style="background-color: #ffff00;">025de3f8<br /></span></span><span style="font-family: courier new,courier; font-size: small;">Name: </span><span style="font-family: courier new,courier; font-size: small;">System.Windows.Forms.WindowsFormsSynchronizationContext<br /></span><span style="font-family: courier new,courier; font-size: small;">MethodTable: </span><span style="font-family: courier new,courier; font-size: small;">7af215b0<br /></span><span style="font-family: courier new,courier; font-size: small;">EEClass: </span><span style="font-family: courier new,courier; font-size: small;">7ad06a94<br /></span><span style="font-family: courier new,courier; font-size: small;">Size: </span><span style="font-family: courier new,courier; font-size: small;">20(0x14) bytes<br /><br /></span><span style="font-family: courier new,courier; font-size: small;">(C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)<br /></span><span style="font-family: courier new,courier; font-size: small;">Fields:<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MT&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">Field&nbsp;&nbsp; Offset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type VT&nbsp;&nbsp;&nbsp;&nbsp; Attr&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">Value Name<br /></span><span style="font-family: courier new,courier; font-size: small;">79780f9c&nbsp; 40005c8&nbsp;&nbsp;&nbsp; </span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Int32&nbsp; 1 instance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 _props<br /></span><span style="font-family: courier new,courier; font-size: small;">7af1f750&nbsp; 4003b24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">8 ...ows.Forms.Control&nbsp; 0 instance </span><span style="font-family: courier new,courier; font-size: small;">025de4ac controlToSendTo<br /></span><span style="font-family: courier new,courier; font-size: small;">7918a4d8&nbsp; 4003b25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">c System.WeakReference&nbsp; 0 instance </span><span style="font-family: courier new,courier; font-size: small; background-color: #33cccc;">025de40c </span><span style="font-family: courier new,courier; font-size: small;"><span style="background-color: #33cccc;">destinationThreadRef</span><br /></span><span style="font-family: courier new,courier; font-size: small;">791647f4&nbsp; 4003b26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Boolean&nbsp; 1 TLstatic&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">dontAutoInstall<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; &gt;&gt; Thread:Value 19ac:0 18f0:0</span><span style="font-family: courier new,courier; font-size: small;">&lt;&lt;<br /></span><span style="font-family: courier new,courier; font-size: small;">791647f4&nbsp; 4003b27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Boolean&nbsp; 1 TLstatic&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">inSyncContextInstallation<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; &gt;&gt; Thread:Value 19ac:0 18f0:0</span><span style="font-family: courier new,courier; font-size: small;">&lt;&lt;<br /></span><span style="font-family: courier new,courier; font-size: small;">7918a00c&nbsp; 4003b28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: courier new,courier; font-size: small;">8 ...ronizationContext&nbsp; 0 </span><span style="font-family: courier new,courier; font-size: small;">TLstatic&nbsp; previousSyncContext<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; &gt;&gt; Thread:Value 19ac:0259dcd4 </span><span style="font-family: courier new,courier; font-size: small;">18f0:025de354 &lt;&lt;&nbsp;<br /></span></p>
<p>We are interested in the destinationThreadRef member, which will be a WeakReference that points to our Thread of interest. Let&rsquo;s dump the address of the destinationThreadRef member.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt; !dumpobj <span style="background-color: #33cccc;">025de40c</span></span><br /><span style="font-family: courier new,courier; font-size: small;">Name: System.WeakReference</span><br /><span style="font-family: courier new,courier; font-size: small;">MethodTable: 7918a4d8</span><br /><span style="font-family: courier new,courier; font-size: small;">EEClass: 78f4a22c</span><br /><span style="font-family: courier new,courier; font-size: small;">Size: 16(0x10) bytes&nbsp;</span><br /><span style="font-family: courier new,courier; font-size: small;">(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">Fields:<br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MT&nbsp;&nbsp;&nbsp;Field&nbsp;&nbsp; Offset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type VT&nbsp;&nbsp;&nbsp;&nbsp; Attr&nbsp;&nbsp;&nbsp;Value Name</span><br /><span style="font-family: courier new,courier; font-size: small;">791935f0&nbsp; 40005b4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.IntPtr&nbsp; 1 instance&nbsp;&nbsp;<span style="background-color: #00ff00;">1c1778</span> m_handle</span><br /><span style="font-family: courier new,courier; font-size: small;">791647f4&nbsp; 40005b5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Boolean&nbsp; 1 instance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 m_IsLongReference</span><br />&nbsp;</p>
<p>The m_handle member is the address of a pointer to our Thread. So we must take this address, and look to see what address it points to.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt; dd </span><span style="font-family: courier new,courier; font-size: small;"><span style="background-color: #00ff00;">1c1778</span> l1<br /></span><span style="font-family: courier new,courier; font-size: small;">001c1778&nbsp; <span style="background-color: #00ffff;">025de014</span></span></p>
<p>Now we can dump the object located at that address to get our System.Threading.Thread object.<br /><br /><span style="font-family: courier new,courier; font-size: small;">0:000&gt;!dumpobj <span style="background-color: #00ffff;">025de014</span></span><br /><span style="font-family: courier new,courier; font-size: small;">Name: System.Threading.Thread</span><br /><span style="font-family: courier new,courier; font-size: small;">MethodTable: 791912fc</span><br /><span style="font-family: courier new,courier; font-size: small;">EEClass: 78f4d9a4</span><br /><span style="font-family: courier new,courier; font-size: small;">Size: 56(0x38) bytes</span><br /><span style="font-family: courier new,courier; font-size: small;">(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">Fields:</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MT&nbsp;&nbsp;&nbsp;Field&nbsp;&nbsp; Offset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type VT&nbsp;&nbsp;&nbsp; &nbsp;Attr&nbsp;&nbsp;&nbsp;Value Name</span><br /><span style="font-family: courier new,courier; font-size: small;">7918210c&nbsp; 400063f&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 ....Contexts.Context&nbsp; 0 instance 00000000 m_Context</span><br /><span style="font-family: courier new,courier; font-size: small;">7918da1c&nbsp; 4000640&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8 ....ExecutionContext&nbsp; 0 instance 025de360 m_ExecutionContext</span><br /><span style="font-family: courier new,courier; font-size: small;">79190d28&nbsp; 4000641&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.String&nbsp; 0 instance 00000000 m_Name </span><br /><span style="font-family: courier new,courier; font-size: small;">7919118c&nbsp; 4000642&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Delegate&nbsp; 0 instance 00000000 m_Delegate</span><br /><span style="font-family: courier new,courier; font-size: small;">7918a424&nbsp; 4000643&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14&nbsp;&nbsp;&nbsp; System.Object[][]&nbsp; 0 instance 025de2a0 m_ThreadStaticsBuckets</span><br /><span style="font-family: courier new,courier; font-size: small;">79192ec4&nbsp; 4000644&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Int32[]&nbsp; 0 instance 025de344 m_ThreadStaticsBits </span><br /><span style="font-family: courier new,courier; font-size: small;">79193924&nbsp; 4000645&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1c ...ation.CultureInfo&nbsp; 0 instance 00000000 m_CurrentCulture</span><br /><span style="font-family: courier new,courier; font-size: small;">79193924&nbsp; 4000646&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;20 ...ation.CultureInfo&nbsp; 0 instance 00000000 m_CurrentUICulture</span><br /><span style="font-family: courier new,courier; font-size: small;">79190944&nbsp; 4000647&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Object&nbsp; 0 instance 00000000 m_ThreadStartArg </span><br /><span style="font-family: courier new,courier; font-size: small;">791935f0&nbsp; 4000648&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.IntPtr&nbsp; 1 instance&nbsp;&nbsp;6dc270 DONT_USE_InternalThread</span><br /><span style="font-family: courier new,courier; font-size: small;">79192f74&nbsp; 4000649&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Int32&nbsp; 1 instance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 m_Priority </span><br /><span style="font-family: courier new,courier; font-size: small;">79192f74&nbsp; 400064a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Int32&nbsp; 1 instance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: #ffff00;"> 3 m_ManagedThreadId</span></span><br /><span style="font-family: courier new,courier; font-size: small;">79169944&nbsp; 400064b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;16c ...LocalDataStoreMgr&nbsp; 0&nbsp;&nbsp; shared&nbsp;&nbsp;static s_LocalDataStoreMgr</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; &gt;&gt; Domain:Value&nbsp; 00681bd8:025e2f54 &lt;&lt;</span><br /><span style="font-family: courier new,courier; font-size: small;">79190944&nbsp; 400064c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Object&nbsp; 0&nbsp;&nbsp;shared&nbsp;&nbsp; static s_SyncObject</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp; &gt;&gt; Domain:Value&nbsp; 00681bd8:02532260 &lt;&lt;&nbsp;</span></p>
<p>The m_ManagedThreadId member above represents the managed thread ID of the thread of interest. So now we can dump all managed threads, looking for the thread with that ID. Note that we must look at the &ldquo;<strong>ID</strong>&rdquo; column in the following output for the managed thread ID.</p>
<p><strong>IMPORTANT:</strong>&nbsp;The ID column from the !threads output below represents the&nbsp;value in hexadecimal. Therefore, it is extremely important to convert the&nbsp;<em>m_ManagedThreadId</em> field from the output above to hex in order to look for the right thread. To do that, simply enter the following command into your debugger, using the integer value of the thread Id above. In this case, we use 0n3 to specify we want to see the hex representation of the integer value 3.</p>
<p><span style="font-family: courier new,courier;">0:000&gt; ?0n3</span><br /><span style="font-family: courier new,courier;">Evaluate expression: 3 = <span style="background-color: #ffff00;">00000003</span></span></p>
<p>In this case, 3 is the same representation in both decimal and hex, so that is what we look for in the output below.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;!threads</span><br /><span style="font-family: courier new,courier; font-size: small;">ThreadCount: 3</span><br /><span style="font-family: courier new,courier; font-size: small;">UnstartedThread: 0</span><br /><span style="font-family: courier new,courier; font-size: small;">BackgroundThread: 2</span><br /><span style="font-family: courier new,courier; font-size: small;">PendingThread: 0</span><br /><span style="font-family: courier new,courier; font-size: small;">DeadThread: 0</span><br /><span style="font-family: courier new,courier; font-size: small;">Hosted Runtime: no<br /></span><span style="font-family: courier new,courier; font-size: small;">&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreEmptive&nbsp;&nbsp;&nbsp;GC Alloc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lock&nbsp;&nbsp; <br /></span><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ID OSID ThreadOBJ&nbsp;&nbsp;&nbsp; State&nbsp;&nbsp;&nbsp; GC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Context&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Domain&nbsp; Count APT Exception</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1 19ac 00685e30&nbsp;&nbsp; 2006020 Enabled&nbsp; 025f0b9c:025f1fe8 00681bd8&nbsp;&nbsp;&nbsp;&nbsp; 0 STA </span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2 2124 006a1f80&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b220 Enabled&nbsp; 00000000:00000000 00681bd8&nbsp;&nbsp;&nbsp;&nbsp; 0 MTA (Finalizer)</span><br /><span style="font-family: courier new,courier; font-size: small; background-color: #33cccc;">&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff00;">3</span> 18f0 006dc270&nbsp;&nbsp; 180b220 Enabled&nbsp; 025e3d90:025e3fe8 00681bd8&nbsp;&nbsp;&nbsp;&nbsp; 0 MTA (Threadpool Worker)&nbsp;</span></p>
<p><strong>Notice that the line with ID 3 (again, that&rsquo;s our managed thread ID), corresponds to debugger thread 4 in the output above</strong>. That is the thread of interest that owns the window. Before switching to that thread in the debugger, note that the thread has is an MTA thread created in the .NET Threadpool. From this alone, we know there are potential problems.&nbsp;First, Windows Forms are only supported on threads using an STA model, and there are places in Winforms that&nbsp;may crash if used on a non-STA thread. The other thing we should be able to assume right away, is that since this is a .NET threadpool thread, it almost certainly will not be pumping messages. So let&rsquo;s switch to that thread and find out.</p>
<p>&nbsp;<span style="font-family: courier new,courier; font-size: small;">0:000&gt; ~4s</span><br /><span style="font-family: courier new,courier; font-size: small;">eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000248 edi=081cf5dc</span><br /><span style="font-family: courier new,courier; font-size: small;">eip=77b9f8b1 esp=081cf594 ebp=081cf600 iopl=0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nv up ei pl zr na pe nc</span><br /><span style="font-family: courier new,courier; font-size: small;">cs=0023&nbsp; ss=002b&nbsp; ds=002b&nbsp; es=002b&nbsp; fs=0053&nbsp; gs=002b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; efl=00000246</span><br /><span style="font-family: courier new,courier; font-size: small;">ntdll!ZwWaitForSingleObject+0x15:</span><br /><span style="font-family: courier new,courier; font-size: small;">77b9f8b1 83c404&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add&nbsp;&nbsp;&nbsp;&nbsp; esp,4</span><br /><br /><span style="font-family: courier new,courier; font-size: small;">0:004&gt; knL</span><br /><span style="font-family: courier new,courier; font-size: small;">&nbsp;# ChildEBP RetAddr<br /></span><span style="font-family: courier new,courier; font-size: small;">00 081cf594 75340a91 ntdll!ZwWaitForSingleObject+0x15</span><br /><span style="font-family: courier new,courier; font-size: small;">01 081cf600 758a1194&nbsp;KERNELBASE!WaitForSingleObjectEx+0x98</span><br /><span style="font-family: courier new,courier; font-size: small;">02 081cf618 79d65497&nbsp;KERNEL32!WaitForSingleObjectExImplementation+0x75</span><br /><span style="font-family: courier new,courier; font-size: small;">03 081cf65c 79d653e3&nbsp;mscorwks!CLREventWaitHelper+0x2f</span><br /><span style="font-family: courier new,courier; font-size: small;">04 081cf6ac 79d65402&nbsp;mscorwks!CLREvent::WaitEx+0x117</span><br /><span style="font-family: courier new,courier; font-size: small;">05 081cf6c0 79dcb75f&nbsp;mscorwks!CLREvent::Wait+0x17</span><br /><span style="font-family: courier new,courier; font-size: small;">06 081cf740 79dcbbed&nbsp;mscorwks!ThreadpoolMgr::SafeWait+0x73</span><br /><span style="font-family: courier new,courier; font-size: small;">07 081cf7a4 79ec305a&nbsp;mscorwks!ThreadpoolMgr::WorkerThreadStart+0x11c</span><br /><span style="font-family: courier new,courier; font-size: small;">08 081cf8c8 758a339a&nbsp;mscorwks!Thread::intermediateThreadProc+0x49</span><br /><span style="font-family: courier new,courier; font-size: small;">09 081cf8d4 77bb9ef2&nbsp;KERNEL32!BaseThreadInitThunk+0xe</span><br /><span style="font-family: courier new,courier; font-size: small;">0a 081cf914 77bb9ec5&nbsp;ntdll!__RtlUserThreadStart+0x70</span><br /><span style="font-family: courier new,courier; font-size: small;">0b 081cf92c 00000000&nbsp;ntdll!_RtlUserThreadStart+0x1b</span></p>
<p>As you can see from the output above, this thread is pretty much what we thought it would be. It is a .NET threadpool thread sitting in WaitForSingleObject, waiting for the CLR to hand it some work. It&rsquo;s definitely not pumping window messages, so the UI thread stays blocked indefinitely. So the&nbsp;resolution to this issue is to do what KB article 943139 mentions: create your Windows Forms controls on an STA thread which&nbsp;routinely pumps messages for the duration of the thread.&nbsp;</p>
<p>We know the resolution to the issue, but&nbsp;what if you don&rsquo;t know what code was responsible for creating the Control(s) on the worker thread? This is really the crux of the problem.&nbsp;The key is being able to find what code is creating these Controls, and the rest of this blog will focus on how to determine that.</p>
<h3>Using Windbg to Determine When Windows Forms Controls Are Created</h3>
<p>It is certainly easy enough to set a breakpoint on the constructor for System.Windows.Forms.Form or System.Windows.Forms.Control, but the problem with that approach is that it will be hit every time your main UI thread creates an instance of one of these objects. We want to limit our output to determining when code is creating Controls on threads <em>other than your primary UI thread</em>. The easiest way to do that is to set a breakpoint on the constructor for the System.Windows.Forms.Application+MarshalingControl type. Whenever any Control is created, Windows Forms first looks to see if it needs to create an instance of the MarshalingControl discussed earlier. The MarshalingControl is created once per thread, the first time anything creates an instance of a Control on that thread. This will track the first time any Control is created on your main UI thread, but also the first time a Control is created on any other thread as well. This should serve to achieve our goal of determining where Controls are being created on a per thread basis, while limiting the amount of unnecessary output.</p>
<p>To do this, start your Windows Forms application and attach Windbg. Once attached, make sure your symbol path is set as appropriate and reload symbols. You can set it to the public Microsoft symbol server, or use your own internal symbol path.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;.sympath srv*msdl.microsoft.com/download/symbols<br /></span><span style="font-size: small;"><span style="font-family: courier new,courier;">Symbol </span><span style="font-family: courier new,courier;">search path is: srv*msdl.microsoft.com/download/symbols<br /></span><span style="font-family: courier new,courier;">Expanded Symbol search path is: srv*msdl.microsoft.com/download/symbols</span></span></p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;.reload</span></p>
<p><span style="font-family: courier new,courier; font-size: small;">Reloading current modules<br />.................................<br /></span></p>
<p>&nbsp;Load the SOS.dll debugger extension from the folder where the CLR (mscorwks.dll) is located. Note: if debugging .NET 4.0 or later, you would use &ldquo;<strong>clr</strong>&rdquo; instead of &ldquo;mscorwks&rdquo; in the command below.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt;.loadby sos.dll mscorwks&nbsp;</span></p>
<p>Locate the address of the constructor for <strong>System.Windows.Forms.Application+MarshalingControl</strong>. We do this using !name2ee along with the module name for the DLL (you can use * to search all modules), and the fully qualified method name.</p>
<p><span style="font-family: courier new,courier;">0:000&gt;!name2ee System_Windows_Forms_ni System.Windows.Forms.Application+MarshalingControl..ctor</span></p>
<p><span style="font-family: courier new,courier;">Module: 7a981000 (System.Windows.Forms.dll)</span><br /><span style="font-family: courier new,courier;">Token: 0x060017d8</span><br /><span style="font-family: courier new,courier;">MethodDesc: 7a99cbcc</span><br /><span style="font-family: courier new,courier;">Name: System.Windows.Forms.Application+MarshalingControl..ctor()</span><br /><span style="font-family: courier new,courier;">JITTED Code Address: <span style="background-color: #ffff00;">7ab46fc0</span></span></p>
<p>7ab46fc0 is the address we want to place a breakpoint on. This breakpoint should be hit the first time a Control is created on a thread. It will dump the managed callstack to the output window and then continue on with normal execution.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt; bp <span style="background-color: #ffff00;">7ab46fc0</span> ".echo MarshalingControl creation detected. Callstack follows.;!clrstack;.echo ==============================;gc"</span></p>
<p>Then run the application and operate under normal conditions to see what output you receive.</p>
<p><span style="font-family: courier new,courier; font-size: small;">0:000&gt; g</span><br /><span style="font-family: courier new,courier; font-size: small;">MarshalingControl creation detected. Callstack follows.</span><br /><span style="font-family: courier new,courier; font-size: small;">OS Thread Id: 0x410 (4)</span><br /><span style="font-family: courier new,courier; font-size: small;">ESP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EIP</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ed34 7ab46fc0 System.Windows.Forms.Application+MarshalingControl..ctor()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ed38&nbsp;7ab75b33 System.Windows.Forms.Application+ThreadContext.get_MarshalingControl()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ed68 7ab75713 System.Windows.Forms.WindowsFormsSynchronizationContext..ctor()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ed7c 7ab75615 System.Windows.Forms.WindowsFormsSynchronizationContext.InstallIfNeeded()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8eda8 7ab746e8 System.Windows.Forms.Control..ctor(Boolean)</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ee48 7ab7c3e4 System.Windows.Forms.ScrollableControl..ctor()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ee64 7ab7c2f7 System.Windows.Forms.ContainerControl..ctor()</span><br /><span style="font-family: courier new,courier; font-size: small;">07b8ee78 7ab743db System.Windows.Forms.Form..ctor()</span><br /><span style="font-family: courier new,courier; font-size: small; background-color: #00ff00;">07b8ee94 005a0478 UserPreferencesHang.ProgressForm..ctor()<br /></span><span style="font-family: courier new,courier; font-size: small;"><span style="background-color: #00ff00;">07b8eea0 005d046a UserPreferencesHang.Form1.DisplayProgressForm()</span><br /><span style="background-color: #00ff00;">07b8eeb4 005d041b UserPreferencesHang.Form1.backgroundWorker1_DoWork(System.Object, System.ComponentModel.DoWorkEventArgs)</span><br />07b8eec8 7a84d3ed System.ComponentModel.BackgroundWorker.OnDoWork(System.ComponentModel.DoWorkEventArgs)<br />07b8eee0 7a84d14e System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)<br />07b8f308 797e1b4c [HelperMethodFrame_PROTECTOBJ: 07b8f308] System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)<br />07b8f44c 78af95c3 System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(System.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)<br />07b8f470 790e273a System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Messaging.IMessageSink)<br />07b8f4d0 790f646a System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.DoAsyncCall()<br />07b8f4dc 790f64a0 System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(System.Object)<br />07b8f4e4 78b4a18f System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(System.Object)<br />07b8f4ec 78b604bf System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)<br />07b8f504 78b4a6f3 System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(System.Threading._ThreadPoolWaitCallback)<br />07b8f518 78b4a589 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(System.Object)<br />07b8f6a8 797e1b4c [GCFrame: 07b8f6a8] </span></p>
<p>The output above shows where this sample application was using the BackgroundWorker component, and handling it's DoWork event. The handler for this is fired on an MTA thread in the .NET Threadpool. We see where the BackgroundWorker's event handler called into some custom code in UserPreferencesHang.Form1.DisplayProgressForm(), which then created an instance of a custom Windows Form. From this output, now we know where to fix our code to prevent it from creating the Form on this background thread. In this case, the fix would be to use Control.Invoke (or BeginInvoke) to marshal the call of the DisplayProgressForm method over to the UI thread.</p>
<h1>Final Thoughts</h1>
<p>We have explained how&nbsp;.NET Windows Forms applications can&nbsp;become unresponsive when handling the Microsoft.Win32.SystemEvents.UserPreferenceChanged event. We have demonstrated how to debug an application already in this state, and more importantly, how to use the debugger to track the creation of Windows Forms on other threads. This should go a long way to helping you diagnose and correct any applications that are suffering from this condition.</p>
<p>Happy Hunting!</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
  </channel>
</rss>