<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Brian McMaster's Blog on QA, .NET, and VS</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/brianmcm/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/brianmcm/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:19:20 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Registry Fix for VS 2008 Intellisense Bug</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/registry-fix-for-vs-2008-intellisense-bug</link>
      <pubDate>Tue, 25 Aug 2009 16:03:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2009/08/25/registry-fix-for-vs-2008-intellisense-bug/</guid>
      <description><![CDATA[I love my intellisense.&nbsp; As such, I am very critical when there's a bug affecting its...]]></description>
      <content:encoded><![CDATA[<P>I love my intellisense.&nbsp; As such, I am very critical when there's a bug affecting its functionality.&nbsp; The bug I ran into late in the VS 2008 product cycle while doing application-building was, unfortunately, not considered high enough priority to fix so late in the game.&nbsp; As a result of the investigation, we did find a fix, and I've been&nbsp;using&nbsp;it ever since with no problems.&nbsp; Here are the details of the problem and how to work around it.</P>
<P>The basic bug is that if you type fast enough, and your CPU is slow or overloaded, you can accidentally bypass the intellisense engine.&nbsp; This will leave you with unwanted text in the editor.&nbsp; As an example, when I first saw this bug on my slow Lenova Thinkpad, I was trying to make a Window.Resources tag.&nbsp; As such, I typed:</P>
<P>&lt;Window.Reso{TAB}</P>
<P>where "{TAB}" was me hitting the tab character to complete the intellisense match.&nbsp; Much to my dismay, instead of my editor containing "&lt;Window.Resources", it actually contained&nbsp;"&lt;Window.Reso&nbsp;&nbsp;&nbsp; ", where the tab character had been replaced by spaces in the editor.&nbsp; To me, this is totally broken!&nbsp; Do I have to stare at my editor and wait for the intellisense dropdown to appear before I can hit the Tab key?&nbsp;&nbsp;I type pretty fast... 95 words per minute&nbsp;according to <A href="https://www.typingtest.com/">www.TypingTest.com</A>... but I know there are many, many people out there who type (and code)&nbsp;much faster.&nbsp; And depending on how many apps I was running, or whether Outlook was downloading mail in the background, or whatever, I could reproduce this intellisense failure about 5-10% of the time&nbsp;on my old laptop.</P>
<P>I was in dire need of a workaround.&nbsp;During the investigation, one of our developers found that a simple bit flip in the registry fixes this issue.&nbsp; Basically, by default, the Orcas XAML intellisense is set to asynchronous behavior.&nbsp; That means, you can keep typing away, and intellisense will run in&nbsp;a background thread and try to keep up... but if you type too fast or it doesn't get enough CPU time, it doesn't want to&nbsp;block the keystrokes from getting&nbsp;placed in&nbsp;the editor, so it just ignores them.&nbsp;&nbsp;That's&nbsp;the bug.&nbsp; The fix is to set the following registry value:</P>
<P>[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Languages\Language Services\XAML]<BR>"EnableAsyncCompletion"=dword:00000000</P>
<P>Setting this registry value to 0, and restarting VS will make it so your keystrokes&nbsp;never bypass the XAML intellisense engine again.&nbsp; If you've ever hit this issue, or think you might,&nbsp;you should&nbsp;make this registry change and never look back.</P>
<P>-Bri</P>]]></content:encoded>
    </item>
    <item>
      <title>Enabling Assistive Devices programmatically for UI Automation on the Mac</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/enabling-assistive-devices-programmatically-for-ui-automation-on-the-mac</link>
      <pubDate>Wed, 02 May 2007 17:14:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2007/05/02/enabling-assistive-devices-programmatically-for-ui-automation-on-the-mac/</guid>
      <description><![CDATA[As part of our effort to test Windows Presentation Foundation Everywhere (WPF/E) on the Mac, I'm...]]></description>
      <content:encoded><![CDATA[<P>As part of our effort to test Windows Presentation Foundation Everywhere (WPF/E) on the Mac, I'm working on a&nbsp;UI Automation tool to drive WPF/E apps from out of process.&nbsp; In the anticipation that WPF/E will eventually support Accessibility (and I assure you it will!), we need to programmatically turn on the checkbox in Mac OS X to enable the AXAPI (Mac's technology similar&nbsp;to MSAA).</P>
<P>It turns out this option in the UI is controlled by the magical file: "/private/var/db/.AccessibilityAPIEnabled".&nbsp; If this file exists, the checkbox is checked, and we can drive applications through AXAPI.&nbsp; If you delete the file, then accessibility is obviously disabled.&nbsp; This operation is reversible on the fly and does not appear to require a reboot to swap, which is really handy.</P>
<P>The final requirement is to create this file programmatically, in my case, through a shell script... although I'm sure there's a cleaner, more involved way to do it.&nbsp; This is the quick and (very) dirty way.&nbsp; Put the following script into a file, and execute it from&nbsp;a Mac Terminal window with "sh myFile".</P>
<P class=MsoNormal><FONT face="Courier New" color=navy size=2><SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: 'Courier New'">#!/bin/sh</SPAN></FONT><BR><FONT face="Courier New" color=navy size=2><SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: 'Courier New'">cd /private/var/db</SPAN></FONT><BR><FONT face="Courier New" color=navy size=2><SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: 'Courier New'"></SPAN></FONT><FONT face="Courier New" color=navy size=2><SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: 'Courier New'">Echo “$ADMINPWD” | sudo touch .AccessibilityAPIEnabled<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal>Of course, emitting the admin password in a text file is what really constitutes "dirty", but it suits my immediate purposes.&nbsp; Someone on the Mac Office team suggested compiling this into an app and setting the "sticky" bit by installing with "1755 permissions" so I don't have to embed the admin pword in my script, which sounds like a good next step.&nbsp; There are many, many more issues to go =).&nbsp; I'm still very new to automation issues on the Mac.&nbsp; We have experts in the company, but having me bother them isn't always optimal, so I'd definitely be interested in any good online resources that you community folks have in mind.&nbsp; Any help is greatly appreciated!</P>
<P>Thanks, </P>
<P>Bri</P>]]></content:encoded>
    </item>
    <item>
      <title>Yahoo! Messenger built in Windows Presentation Foundation</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/yahoo-messenger-built-in-windows-presentation-foundation</link>
      <pubDate>Tue, 27 Feb 2007 17:46:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2007/02/27/yahoo-messenger-built-in-windows-presentation-foundation/</guid>
      <description><![CDATA[You've probably seen this already, but if not, you should really check out the video preview of...]]></description>
      <content:encoded><![CDATA[<P>You've probably seen this already, but if not, you should really check out the video preview of Yahoo!'s messenger app built with WPF.&nbsp; <A href="https://messenger.yahoo.com/windowsvista.php">https://messenger.yahoo.com/windowsvista.php</A>&nbsp;is the link.&nbsp; I can't wait to see this thing running live.&nbsp; It really seems like they've captured the power of what you can do with WPF.</P>
<P>My team within Microsoft is working on releasing our first beta of Cider, which is a visual designer targetting&nbsp;developers wanting to write cool WPF apps in a WYSIWYG editing environment within Visual Studio 9.0.&nbsp; Our designer will fit in with the rest of the <A class="" title="Microsoft Expression" href="https://www.microsoft.com/products/expression/en/default.mspx" target=_blank mce_href="https://www.microsoft.com/products/expression/en/default.mspx">Microsoft Expression</A> technologies, so you'll be able to open your Cider apps in Blend to spice them up with beautiful gradients and animations, but still get your awesome development, layout,&nbsp;and debugging experience within Visual Studio and seamlessly go back and forth between your Expression apps to get your forms looking the way you like.</P>
<P>Of course, after watching this Yahoo! Messenger demo, the question we're all asking is... why not MSN Messenger?&nbsp; Good question.&nbsp; I have no idea.&nbsp; I hope MSN does something sweet, too, otherwise I may have a reason to get an @yahoo email address ;-0.</P>
<P>Bri</P>]]></content:encoded>
    </item>
    <item>
      <title>Huge VS Debugger Fix in Orcas (IMHO) =)</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/huge-vs-debugger-fix-in-orcas-imho</link>
      <pubDate>Fri, 19 Jan 2007 20:11:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2007/01/19/huge-vs-debugger-fix-in-orcas-imho/</guid>
      <description><![CDATA[The bug in the VS debugger that has been a thorn in my side for well over a year is now fixed in the...]]></description>
      <content:encoded><![CDATA[<P>The bug in the VS debugger that has been a thorn in my side for well over a year is now fixed in the next version of VS!&nbsp; If you're a religious VS developer, I'm almost positive you've hit this bug before, although you may not have noticed.&nbsp; The bug in Whidbey is basically that "Set Next Statement" in the right-click menu is broken when your cursor is at the end of a line.&nbsp; In reality, it thinks the insertion point is on the <STRONG>next </STRONG>line, so it tries to set the next statement there, instead.</P>
<P>This bug can manifest itself in one of two ways.&nbsp; If the line <STRONG>after </STRONG>the line your cursor is on is a valid breakpoint line, then the next statement will be set to that line.&nbsp; If this happens to you once, you will probably just think that you mis-clicked, and you will simply attempt to set the next statement to the previous line again.&nbsp; However, if the next line is <STRONG>not</STRONG> a valid line for a breakpoint, then you will see an error message saying, "unable to set the next statement to this location."</P>
<P>Here's an official MS knowledge base article on the issue, as well. <A href="https://support.microsoft.com/kb/919808">https://support.microsoft.com/kb/919808</A></P>
<P>This bug really bothered me, because it made me change the way I do work.&nbsp; Anytime the tool makes me conciously do something differently than what I'm used to doing, it's a bad bug.&nbsp; I was unable to convince the triage team for Whidbey, however =(.&nbsp; The good news is, after fighting for this bug off-and-on for over a year and a half, it will now be fixed in the next version!</P>
<P>Bri</P>]]></content:encoded>
    </item>
    <item>
      <title>Using StringBuilder to improve performance of your apps</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/using-stringbuilder-to-improve-performance-of-your-apps</link>
      <pubDate>Tue, 26 Sep 2006 20:30:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2006/09/26/using-stringbuilder-to-improve-performance-of-your-apps/</guid>
      <description><![CDATA[TestSuites.cs file generated by my model, and parse it out into multiple .cs files each representing...]]></description>
      <content:encoded><![CDATA[<P>TestSuites.cs file generated by my model, and parse it out into multiple .cs files each representing one testcase.&nbsp; This sounded great to me, because my TestSuites.cs file was 113Mb, and splitting it out into around 300 testcase files sounded good to me.<BR>&nbsp;<BR>However, when I ran the tool for about 3 hours without it completing, I began to wonder what was going on.&nbsp; From debugging it with a friend of mine, David Owens, we discovered that the main reason it took so long was because the original tool author was using normal string concatenation during the parsing.&nbsp; Here is some sample code which illustrates the problem.<BR></P><!-- code formatted by https://manoli.net/csharpformat/ --><PRE class=csharpcode><SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>void</SPAN> Main(<SPAN class=kwrd>string</SPAN>[] args) {
    <SPAN class=kwrd>string</SPAN> contents = <SPAN class=str>""</SPAN>;
    DateTime dtStart = DateTime.Now;

    StreamReader sr = <SPAN class=kwrd>new</SPAN> StreamReader(<SPAN class=str>@"C:\TestSuites.cs"</SPAN>);
    <SPAN class=kwrd>while</SPAN> (!sr.EndOfStream) {
        contents += sr.ReadLine();  <SPAN class=rem>// Don’t do this =)</SPAN>
    }
    DateTime dtEnd = DateTime.Now;
    TimeSpan ts = dtEnd.Subtract(dtStart);
    Console.WriteLine(contents + <SPAN class=str>"\r\n"</SPAN> + ts.Seconds.ToString());
} 
</PRE>
<P><BR>If you’ve written code like this before, and you’re familiar with some of the static analysis tools like FxCop, you’ve probably been informed that this is bad.&nbsp; The offending line is “contents += sr.ReadLine();”.&nbsp; The root of the bug is that strings in .NET are “immutable.”&nbsp; Basically, what that means is, whenever you assign a new string to a variable, the old string gets marked for garbage collection, and new memory is allocated to house the new string.&nbsp; In this case, the code file is about 1.64 million lines, and memory allocation is bigger than the last.&nbsp; Based on an average line length, it would take approximately 87.3 terra-bytes of memory to store all the strings allocated in this example.&nbsp; Now you see why my laptop was thrashing for over 3 hours trying to parse this file.&nbsp; Time for Microsoft to upgrade my laptop, IMO =).<BR>&nbsp;<BR>Enter, the System.Text.StringBuilder class.&nbsp; The idea behind this class is to allocate a fixed chunk of memory to build the string, and only allocate a new buffer if the string you're building becomes too long for the original allocation.&nbsp; Once you're ready to use it, it allocates an immutable string object of the correct size.&nbsp; In this example, the fix is to use the Append() method to build up my uber string, like so:</P><!-- code formatted by https://manoli.net/csharpformat/ --><PRE class=csharpcode><SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>void</SPAN> Main(<SPAN class=kwrd>string</SPAN>[] args) {
    StringBuilder contents = <SPAN class=kwrd>new</SPAN> StringBuilder(<SPAN class=str>""</SPAN>);
    DateTime dtStart = DateTime.Now;
            
    StreamReader sr = <SPAN class=kwrd>new</SPAN> StreamReader(<SPAN class=str>@"C:\TestSuites.cs"</SPAN>);
    <SPAN class=kwrd>while</SPAN> (!sr.EndOfStream) {
        contents.Append(sr.ReadLine());
    }
 
    DateTime dtEnd = DateTime.Now;
    TimeSpan ts = dtEnd.Subtract(dtStart);
    Console.WriteLine(contents + <SPAN class=str>"\r\n"</SPAN> + ts.Seconds.ToString());
}
</PRE>
<P>Now, each time I read a new line from the file, rather than allocating a new immutable string to store the current contents, the StringBuilder class just stores a pointer to that substring in memory until the last line of my Main() function where it outputs the string to the console window.&nbsp; It takes quite a bit longer to output the 113Mb of my file to the console than it does to execute the while loop.&nbsp; But the perf improvement is amazing.&nbsp; My while loop now executes in 24 seconds instead of several hours!!<BR>&nbsp;<BR>Fun stuff,<BR>Bri</P>]]></content:encoded>
    </item>
    <item>
      <title>ISU Tech Talk on WPF and UIAutomation</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/isu-tech-talk-on-wpf-and-uiautomation</link>
      <pubDate>Fri, 24 Feb 2006 18:31:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2006/02/24/isu-tech-talk-on-wpf-and-uiautomation/</guid>
      <description><![CDATA[I had the pleasure of speaking to the ISU students on Tuesday this week.&nbsp; I gave a high-level...]]></description>
      <content:encoded><![CDATA[<P>I had the pleasure of speaking to the ISU students on Tuesday this week.&nbsp; I gave a high-level overview of WPF (Avalon)&nbsp;and Windows UIAutomation (vNext of MSAA).&nbsp; I wanted to go ahead and get my basic slide deck posted in case anyone wanted it.&nbsp; Sorry I don't have videos of the demos.</P>
<P>It was fun to show people some of the cool new features of Sparkle and Cider.&nbsp; I got some great questions from the students, and it was cool to see them really "get" Microsoft's WPF story.&nbsp; One of the students (Chris Sammis)&nbsp;has even been downloading WinFX betas and doing real development with it and supplying us with feedback and bug reports.&nbsp; Kudos to Chris!</P>
<P>I also got to play Micro-Santa and held a raffle to give away cool prizes including, but not limited to:&nbsp; MS Office 2003 Pro, Halo2, Fable, Age of Empires 3, Rise of Nations, MS Money, tons of T-Shirts, and an XBox 360!!&nbsp; Congratulations to Brandon Kennedy on winning the XBox.&nbsp; I hope he has fun w/that between mid-terms =).&nbsp; </P>
<P>Thanks a lot to the NSBE (National Society of Black Engineers) for sponsoring the event and providing the Pizza and pop.&nbsp; I appreciate the students who took the time to help organize and advertise this event.&nbsp; There were 85 people at the talk, which my MS recruiters tell me was a record attendance, so thanks to everyone who made it successful.&nbsp; I would definitely do this again!</P>
<P>Bri</P>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/00/53/89/42/ISU%20WPF%20Presentation.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-00-53-89-42/ISU-WPF-Presentation.zip">ISU WPF Presentation.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>PInvoke Declarations for My Sample Code</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/pinvoke-declarations-for-my-sample-code</link>
      <pubDate>Mon, 23 Jan 2006 16:40:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2006/01/23/pinvoke-declarations-for-my-sample-code/</guid>
      <description><![CDATA[Thanks to Ed from Comcast for pointing out that my 1/17/06 post regarding Windows Forms ID's was...]]></description>
      <content:encoded><![CDATA[<P>Thanks to Ed from Comcast for pointing out that my 1/17/06 post regarding Windows Forms ID's was missing the NativeMethods.cs file.&nbsp; Sorry for the inconvenience, Ed.&nbsp; Here's the NativeMethods.cs file that will help you get the code up and running.</P><!-- code formatted by https://manoli.net/csharpformat/ --><PRE class=csharpcode><SPAN class=kwrd>using</SPAN> System;
<SPAN class=kwrd>using</SPAN> System.Runtime.InteropServices;

<SPAN class=kwrd>namespace</SPAN> GetWinFormsId
{
    <SPAN class=rem>/// &lt;summary&gt;</SPAN>
    <SPAN class=rem>/// Summary description for NativeMethods.</SPAN>
    <SPAN class=rem>/// &lt;/summary&gt;</SPAN>
    <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>class</SPAN> NativeMethods
    {
        
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> IntPtr OpenProcess(<SPAN class=kwrd>uint</SPAN> dwDesiredAccess, <SPAN class=kwrd>bool</SPAN> bInheritHandle,
            <SPAN class=kwrd>uint</SPAN> dwProcessId);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
            UIntPtr dwSize, <SPAN class=kwrd>uint</SPAN> flAllocationType, PageProtection flProtect);
        [DllImport(<SPAN class=str>"user32.dll"</SPAN>, SetLastError=<SPAN class=kwrd>true</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>uint</SPAN> GetWindowThreadProcessId(IntPtr hWnd, <SPAN class=kwrd>out</SPAN> <SPAN class=kwrd>uint</SPAN> lpdwProcessId);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>bool</SPAN> VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress,
            UIntPtr dwSize, <SPAN class=kwrd>uint</SPAN> dwFreeType);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>bool</SPAN> CloseHandle(IntPtr hObject);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> IntPtr MapViewOfFile(IntPtr hFileMappingObject, <SPAN class=kwrd>uint</SPAN>
            dwDesiredAccess, <SPAN class=kwrd>uint</SPAN> dwFileOffsetHigh, <SPAN class=kwrd>uint</SPAN> dwFileOffsetLow,
            UIntPtr dwNumberOfBytesToMap);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>bool</SPAN> UnmapViewOfFile(IntPtr lpBaseAddress);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>, SetLastError=<SPAN class=kwrd>true</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> IntPtr CreateFileMapping(IntPtr hFile,
            IntPtr lpFileMappingAttributes, PageProtection flProtect, <SPAN class=kwrd>int</SPAN> dwMaximumSizeHigh,
            <SPAN class=kwrd>int</SPAN> dwMaximumSizeLow, <SPAN class=kwrd>string</SPAN> lpName);
        [DllImport(<SPAN class=str>"user32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> IntPtr SendMessage(IntPtr hwnd, <SPAN class=kwrd>int</SPAN> wMsg, IntPtr wParam, IntPtr lParam);
        [DllImport(<SPAN class=str>"kernel32.dll"</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>bool</SPAN> ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
            [Out] <SPAN class=kwrd>byte</SPAN> [] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);
        [DllImport(<SPAN class=str>"Kernel32.dll"</SPAN>, EntryPoint=<SPAN class=str>"RtlMoveMemory"</SPAN>, SetLastError=<SPAN class=kwrd>false</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>void</SPAN> MoveMemoryFromByte(IntPtr dest, <SPAN class=kwrd>ref</SPAN> <SPAN class=kwrd>byte</SPAN> src, <SPAN class=kwrd>int</SPAN> size);
        [DllImport(<SPAN class=str>"Kernel32.dll"</SPAN>, EntryPoint=<SPAN class=str>"RtlMoveMemory"</SPAN>, SetLastError=<SPAN class=kwrd>false</SPAN>)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>void</SPAN> MoveMemoryToByte(<SPAN class=kwrd>ref</SPAN> <SPAN class=kwrd>byte</SPAN> dest, IntPtr src, <SPAN class=kwrd>int</SPAN> size);
        [DllImport(<SPAN class=str>"user32.dll"</SPAN>, SetLastError=<SPAN class=kwrd>true</SPAN>, CharSet=CharSet.Auto)]
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>extern</SPAN> <SPAN class=kwrd>int</SPAN> RegisterWindowMessage(<SPAN class=kwrd>string</SPAN> lpString);



        <SPAN class=rem>//=========== Win95/98/ME Shared memory staff===============</SPAN>
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> STANDARD_RIGHTS_REQUIRED = 0xF0000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> SECTION_QUERY = 0x1;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> SECTION_MAP_WRITE = 0x2;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> SECTION_MAP_READ = 0x4;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> SECTION_MAP_EXECUTE = 0x8;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> SECTION_EXTEND_SIZE = 0x10;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS;

        <SPAN class=rem>//============NT Shared memory constant======================</SPAN>
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> PROCESS_VM_OPERATION = 0x8;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> PROCESS_VM_READ = 0x10;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> PROCESS_VM_WRITE = 0x20;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>long</SPAN> PROCESS_ALL_ACCESS = 0x1F0FFF;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> MEM_COMMIT = 0x1000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> MEM_RESERVE = 0x2000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>short</SPAN> MEM_DECOMMIT = 0x4000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> MEM_RELEASE = 0x8000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> MEM_FREE = 0x10000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> MEM_PRIVATE = 0x20000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> MEM_MAPPED = 0x40000;
        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> MEM_TOP_DOWN = 0x100000;


        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>const</SPAN> <SPAN class=kwrd>int</SPAN> INVALID_HANDLE_VALUE = -1;
        


    }

    [Flags]
    <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>enum</SPAN> PageProtection : <SPAN class=kwrd>uint</SPAN> 
    {
        NoAccess =     0x01,
        Readonly =     0x02,
        ReadWrite =    0x04,
        WriteCopy =    0x08,
        Execute =      0x10,
        ExecuteRead =      0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        Guard =        0x100,
        NoCache =      0x200,
        WriteCombine =     0x400,
    }
}
</PRE>]]></content:encoded>
    </item>
    <item>
      <title>Getting the WinForms ID of a Control</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/getting-the-winforms-id-of-a-control</link>
      <pubDate>Mon, 16 Jan 2006 19:35:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2006/01/16/getting-the-winforms-id-of-a-control/</guid>
      <description><![CDATA[Happy New Year and stuff! =)
If you've read my article on issues related to automating Windows...]]></description>
      <content:encoded><![CDATA[<P>Happy New Year and stuff! =)</P>
<P>If you've read my article on issues related to automating Windows Forms with traditional Win32-like UI Automation tools, then you know about what we refer to as the Windows Forms ID.&nbsp; If you're not familiar with the issue, here's a quick intro.&nbsp; Basically, when automating Win32 UI in the past, the typical way that you located a control through code was by using the Control ID.&nbsp; You probably had some method in your automation framework called "FindControlById()" or something similar that took a window handle and an integer as parameters, and then searched the descendants of that window handle for a window who's Control ID matched the one you passed in.&nbsp; Well that's all great, except this method is useless in automating Windows Forms.&nbsp; That's because the Control ID for Windows Forms UI is a mirror of the HWND&nbsp;of the control.&nbsp; Thus, it will not be the same on subsequent launches of the app.</P>
<P>The replacement for Control ID's in Windows Forms is "Windows Forms ID."&nbsp; When you develop a Windows Forms application in Visual Studio using the designer, it will automatically set the ".Name" property for your controls to default values (usually "button1," "button2," "listBox1," etc.).&nbsp; So what you really want to use in your automation is&nbsp;to be able to ask a particular control what it's Name property is set to.&nbsp;&nbsp;Windows Forms supports just that.&nbsp; If you send a&nbsp;WM_GETCONTROLNAME message using a standard SendMessage&nbsp;Windows API to any Windows&nbsp;Forms control, it will respond in the LPARAM with it's Name property.&nbsp; The code in my article is written in Rational Visual Test, which is&nbsp;kind of pseudo-Basic I would say.&nbsp; However, I often get asked for C# code to get the WinformsId, so I'm going to paste it in below.</P>
<P>As you can see, it has a public static method called GetWinFormsId() that takes an HWND as a parameter and returns a string representing the Name.&nbsp; So all you have to do is add this code to&nbsp;a C# project, and then write some code to walk the Windows Hierarchy using the GetWindow() Function&nbsp;or similar API's to find the HWNDs of the controls on your form.&nbsp; Then you can call WinFormsUtilities.GetWinFormsId() on those HWNDS to see if you've found the HWND of the control you're looking for.</P><!-- code formatted by https://manoli.net/csharpformat/ --><PRE class=csharpcode><SPAN class=kwrd>using</SPAN> System;
<SPAN class=kwrd>using</SPAN> System.Text;
<SPAN class=kwrd>using</SPAN> System.ComponentModel;

<SPAN class=kwrd>namespace</SPAN> GetWinFormsId
{
    <SPAN class=rem>/// &lt;summary&gt;</SPAN>
    <SPAN class=rem>/// Summary description for WinFormsUtilities.</SPAN>
    <SPAN class=rem>/// &lt;/summary&gt;</SPAN>
    <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>class</SPAN> WinFormsUtilities
    {
        <SPAN class=kwrd>private</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>int</SPAN> GetControlNameMessage = 0;

        <SPAN class=kwrd>static</SPAN> WinFormsUtilities()
        {
            GetControlNameMessage = NativeMethods.RegisterWindowMessage(<SPAN class=str>"WM_GETCONTROLNAME"</SPAN>);
        }

        <SPAN class=kwrd>public</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>string</SPAN> GetWinFormsId(IntPtr hWnd)
        {
            <SPAN class=kwrd>return</SPAN> XProcGetControlName(hWnd, GetControlNameMessage);
        }

        <SPAN class=kwrd>protected</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>string</SPAN> XProcGetControlName(IntPtr hwnd, <SPAN class=kwrd>int</SPAN> msg)
        {
            <SPAN class=rem>//define the buffer that will eventually contain the desired window's WinFormsId</SPAN>

            <SPAN class=kwrd>byte</SPAN>[] bytearray = <SPAN class=kwrd>new</SPAN> <SPAN class=kwrd>byte</SPAN>[65536];

            <SPAN class=rem>//allocate space in the target process for the buffer as shared memory</SPAN>
            IntPtr bufferMem = IntPtr.Zero; <SPAN class=rem>//base address of the allocated region for the buffer</SPAN>
            IntPtr written= IntPtr.Zero;  <SPAN class=rem>//number of bytes written to memory</SPAN>
            IntPtr retHandle= IntPtr.Zero;
            <SPAN class=kwrd>bool</SPAN> retVal;

            
            <SPAN class=rem>//creating and reading from a shared memory region is done differently in Win9x then in newer OSs</SPAN>
            IntPtr processHandle= IntPtr.Zero;
            IntPtr fileHandle= IntPtr.Zero;

            <SPAN class=kwrd>if</SPAN>(!(Environment.OSVersion.Platform == PlatformID.Win32Windows))
            {   
                <SPAN class=kwrd>try</SPAN>
                {
                    <SPAN class=kwrd>uint</SPAN> size; <SPAN class=rem>//the amount of memory to be allocated</SPAN>
                    size = 65536;

                    processHandle = NativeMethods.OpenProcess(NativeMethods.PROCESS_VM_OPERATION | NativeMethods.PROCESS_VM_READ | NativeMethods.PROCESS_VM_WRITE, <SPAN class=kwrd>false</SPAN>, GetProcessIdFromHWnd(hwnd));

                    <SPAN class=kwrd>if</SPAN>(processHandle.ToInt64() == 0)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }

                    bufferMem = NativeMethods.VirtualAllocEx(processHandle, IntPtr.Zero, <SPAN class=kwrd>new</SPAN> UIntPtr(size), NativeMethods.MEM_RESERVE | NativeMethods.MEM_COMMIT, PageProtection.ReadWrite);

                    <SPAN class=kwrd>if</SPAN>(bufferMem.ToInt64() == 0)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }

                    <SPAN class=rem>//send message to the control's hWnd for getting the specified control name</SPAN>
                    retHandle = NativeMethods.SendMessage(hwnd, msg, <SPAN class=kwrd>new</SPAN> IntPtr(size), bufferMem);

                    <SPAN class=rem>//now read the TVITEM's info from the shared memory location</SPAN>
                    retVal = NativeMethods.ReadProcessMemory(processHandle, bufferMem, bytearray, <SPAN class=kwrd>new</SPAN> UIntPtr(size), written);
                    <SPAN class=kwrd>if</SPAN>(!retVal)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }
                }
                <SPAN class=kwrd>finally</SPAN>
                {
                    <SPAN class=rem>//free the memory that was allocated</SPAN>
                    retVal = NativeMethods.VirtualFreeEx(processHandle, bufferMem, <SPAN class=kwrd>new</SPAN> UIntPtr(0), NativeMethods.MEM_RELEASE);
                    <SPAN class=kwrd>if</SPAN>(!retVal)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }
                    NativeMethods.CloseHandle(processHandle);
                }
            }
            <SPAN class=kwrd>else</SPAN>
            {
                <SPAN class=kwrd>try</SPAN>
                {
                    <SPAN class=kwrd>int</SPAN> size2; <SPAN class=rem>//the amount of memory to be allocated</SPAN>
                    size2 = 65536;

                    fileHandle = NativeMethods.CreateFileMapping(<SPAN class=kwrd>new</SPAN> IntPtr(NativeMethods.INVALID_HANDLE_VALUE), IntPtr.Zero, PageProtection.ReadWrite, 0, size2, <SPAN class=kwrd>null</SPAN>);
                    <SPAN class=kwrd>if</SPAN>(fileHandle.ToInt64() == 0)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }
                    bufferMem = NativeMethods.MapViewOfFile(fileHandle, NativeMethods.FILE_MAP_ALL_ACCESS, 0, 0, <SPAN class=kwrd>new</SPAN> UIntPtr(0));
                    <SPAN class=kwrd>if</SPAN>(bufferMem.ToInt64() == 0)
                    {
                        <SPAN class=kwrd>throw</SPAN> <SPAN class=kwrd>new</SPAN> Win32Exception();
                    }
                    NativeMethods.MoveMemoryFromByte(bufferMem, <SPAN class=kwrd>ref</SPAN> bytearray[0], size2);

                    retHandle = NativeMethods.SendMessage(hwnd, msg, <SPAN class=kwrd>new</SPAN> IntPtr(size2), bufferMem);

                    <SPAN class=rem>//read the control's name from the specific shared memory for the buffer</SPAN>
                    NativeMethods.MoveMemoryToByte(<SPAN class=kwrd>ref</SPAN> bytearray[0], bufferMem, 1024);

                }
                <SPAN class=kwrd>finally</SPAN>
                {
                    <SPAN class=rem>//unmap and close the file</SPAN>
                    NativeMethods.UnmapViewOfFile(bufferMem);
                    NativeMethods.CloseHandle(fileHandle);
                }
            }

            <SPAN class=rem>//get the string value for the Control name</SPAN>
            <SPAN class=kwrd>return</SPAN> ByteArrayToString(bytearray);

        }

        <SPAN class=kwrd>private</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>uint</SPAN> GetProcessIdFromHWnd(IntPtr hwnd)
        {
            <SPAN class=kwrd>uint</SPAN> pid;
            
            NativeMethods.GetWindowThreadProcessId(hwnd, <SPAN class=kwrd>out</SPAN> pid);

            <SPAN class=kwrd>return</SPAN> pid;
        }

        <SPAN class=kwrd>private</SPAN> <SPAN class=kwrd>static</SPAN> <SPAN class=kwrd>string</SPAN> ByteArrayToString(<SPAN class=kwrd>byte</SPAN>[] bytes)
        {
            <SPAN class=kwrd>if</SPAN>(Environment.OSVersion.Platform == PlatformID.Win32Windows)
            {
                <SPAN class=rem>// Use the Ansii encoder</SPAN>
                <SPAN class=kwrd>return</SPAN> Encoding.Default.GetString(bytes).TrimEnd(<SPAN class=str>'\0'</SPAN>);
            }
            <SPAN class=kwrd>else</SPAN>
            {
                <SPAN class=rem>// use Unicode</SPAN>
                <SPAN class=kwrd>return</SPAN> Encoding.Unicode.GetString(bytes).TrimEnd(<SPAN class=str>'\0'</SPAN>);
            }
        }
    }
}</PRE>]]></content:encoded>
    </item>
    <item>
      <title>Who am I and why should anyone care?</title>
      <link>https://docs.microsoft.com/archive/blogs/brianmcm/who-am-i-and-why-should-anyone-care</link>
      <pubDate>Mon, 12 Dec 2005 16:01:00 GMT</pubDate>
      <dc:creator><![CDATA[brianmcm]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brianmcm/2005/12/12/who-am-i-and-why-should-anyone-care/</guid>
      <description><![CDATA[The "why should you care?" part is much harder to answer, so I'll just start with who I am =).&nbsp;...]]></description>
      <content:encoded><![CDATA[<P>The "why should you care?" part is much harder to answer, so I'll just start with who I am =).&nbsp; I'm Brian McMaster, and I'm a Test Architect at Microsoft.&nbsp; I'm currently working on "Cider."&nbsp; Cider is the codename for the line of business application designer for Windows Presentation Foundation (aka Avalon) apps.&nbsp; I will continue to call WPF, "Avalon," because it's a much more elegant name and easier to type =).&nbsp; Avalon is an extremely cool framework, and Cider is shaping up to be an awesome designer for these types of applications.&nbsp; Some of the other products I have worked on in the past are Access, Visual Basic, Visual InterDev, and Windows Forms.&nbsp; </P>
<P>I've been working at Microsoft full-time for almost exactly 9 years (excluding a few internships that I worked while in college).&nbsp; In fact, that reminds me that I need to buy a bunch of M &amp; M's.&nbsp; There's a silly tradition at Microsoft where you put x number of pounds of M&amp;M's outside your office where x is equal to the number of years you've been working there.&nbsp; At 10 years, there's another silly tradition where the company gives you 10 shares of Microsoft stock.&nbsp; Of course, since the stock experts have told me that Microsoft is more of a value stock now instead of a growth stock, this means that my 10 shares will not appreciate in the way that shares have in the past.</P>
<P>When I first started working here, there were daily conversations about stock prices amongst the employees.&nbsp; Sample applications for app-writing contests often involved writing the coolest ticker controls, or stock option vesting applications.&nbsp; Back then the 10 shares might have become exceptionally valuable in short order due to splits.&nbsp; 10-20-40-80-160, possibly several thousand dollars worth =).&nbsp; Ah, but we must not give up.&nbsp; With XBox already out, and Vista coming out, and a new Office, and of course Visual Studio + Cider, we have a lot of potential.</P>
<P>So getting back to why you might care.&nbsp; My main expertise at Microsoft has revolved around automated testing.&nbsp; I've worked on various automated testing tools for technologies like HTML, Win32, Office, Windows Forms, and now Avalon.&nbsp; Windows Forms has some subtle (and some not-so-subtle) differences from Win32 which makes it tricky to automate your applications.&nbsp; So far, we've done a less than optimal job of helping our customers automate the testing of their Windows Forms applications.&nbsp; This is something we're trying to remedy as quickly as possible with our next version of Visual Studio Team System.&nbsp; In order to help explain the diferences and offer some guidance for our customers on how they might adapt their existing automated tools to Windows forms, I wrote this MSDN article.&nbsp; <SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 'Calibri','sans-serif'; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><A href="https://msdn2.microsoft.com/en-us/library/ms996405.aspx">https://msdn2.microsoft.com/en-us/library/ms996405.aspx</A></SPAN>.&nbsp; It's certainly not a great article, but it is pretty good at describing the Windows Forms technology from an automation perspective.</P>
<P>I have a few more blog entries in mind right now, so hopefully, I'll be able to provide some useful tips and articles in the future.</P>
<P>-Bri</P>]]></content:encoded>
    </item>
  </channel>
</rss>