Rick Brewster's blog

Performance, Windows Forms, and UI

  • Paint.NET blog has moved ! Also, there's a new BETA release (3.08)

    All future Paint.NET-related blog posts will now be posted at: http://blog.getpaint.net . If you are currently subscribed to this blog (that is, http://blogs.msdn.com/rickbrew) then I invite you to subscribe to this new one! I will still continue to post here for other topics.

    Also, you'll see over there that a new beta release is available! http://blog.getpaint.net/2007/05/29/paintnet-v308-beta-is-now-available/ 

  • RAM prices have sunk like a rock!

    http://www.newegg.com/Product/Product.aspx?Item=N82E16820134046

    2GB of DDR2-667 memory for $86 is very nice!

    I upgraded my media center PC this last weekend to a Core 2 Duo E4300. I was going to get 1 GB of RAM but the 2 GB kit was so cheap I thought, "why not?"

    My media center used to have a 3GHz Pentium 4 chip in it, and it was a Prescott so it ran really hot and the fan noise was noticable. Now with the E4300 in there not only is it faster, but it's super quiet and doesn't run very hot at all. Plus, the chip was quite cheap, at around $115 on newegg (http://www.newegg.com/Product/ProductList.aspx?Submit=ENE&DEPA=0&Description=E4300). And if you want it to run faster, just set the bus speed to 1066 and you've got it at 2.4 GHz :) I put a passively cooled eVGA GeForce 7600 GS in the system, which is perfect for the target noise level. And since I cancelled my cable TV (I just get TV shows from iTunes and XBOX Marketplace), I don't need the Hauppauge TV tuner cards anymore! Those things cluttered up the inside of the case and generated their fair share of heat as well.

    This post is made "AS IS" without warranties, and confers no rights.

  • Problems installing Adobe Photoshop CS3 on Vista x64?

    So I went to install Photoshop CS3 on my Vista x64 box at home, and got this nice error:

    Internal Error 2739

    Gee, thanks for the info.

    Anyway I searched online for ways to fix this, and they involved running regsvr32.exe on jscript.dll and vbscript.dll. Unfortunately, it didn't work! However, I found someone online who had fixed it: http://davidgardiner.blogspot.com/2007/02/internal-error-2739-on-vista-x64.html

    David had the critical insight, one that I'm slapping myself on the forehead for not realizing myself: you need to register the 32-bit versions of vbscript and jscript, not the 64-bit versions. The Photoshop installer is a 32-bit program, and thus needs access to all 32-bit DLL's and COM registrations. The instructions that are around the web will register whatever is in your SYSTEM32 directory, which oddly enough on 64-bit Windows is where all the 64-bit DLL's are. (And another oddity on top of that is that the 32-bit DLL's are in SysWOW64. Go figure.)

    The solution?

    1) Run cmd.exe with Administrator privilege (Start -> type "cmd", then right-click on the cmd.exe and select "Run as Administrator, then click Continue on the elevation consent dialog). This will open a command prompt in C:\Windows\System32 (or wherever your system directory is)

    2) cd ..\SysWOW64

    3) regsvr32 jscript.dll

    4) regsvr32 vbscript.dll

    Voila. Hope this helps anybody else who runs in to this.

  • I was interviewed! for DotNetRocks

    A few weeks ago they asked me to do an interview with them about Paint.NET, so I thought "Why not?"

    Anyway they've posted the interview today: http://www.dotnetrocks.com/default.aspx?showNum=229

  • Nine Inch Nails: Year Zero ... listen to it online NOW

    Ok so here's a completely new type of post from me. I've pretty much stuck to nerdy topics like Paint.NET, WinForms, and Performance over the last ~3 years.

    But anyone who knows me personally knows I'm super stoked about the new Nine Inch Nails album, Year Zero. It's hitting stores on April 17th. I've got my pre-order and my lithograph, I went to the listening party in Seattle, etc. etc. This is my favorite band, and The Downward Spiral is a staple in my car's CD player.

    And now you can listen to the full thing online, 2 weeks before it's available! Freaking awesome stuff.

    http://yearzero.nin.com <-- that's what you need to click on!

  • When the power goes out ...

    Like everyone else who lives on the eastside, my power got knocked out as part of the big huge windstorm that hit the pacific northwest (if you haven't heard about it yet somehow: http://www.cnn.com/2006/WEATHER/12/19/northwest.storm.ap/index.html). Thing is, when the power goes out the problem is not just that your TV won't work: the roads are jammed because the intersection lights are out (all-way stop), cell phone reception is slim-to-none, and it gets cold really fast.

    So imagine my elation when I heard that the Redmond campus had power restored on Saturday, while I was still in the dark at home. I grabbed some food, a gallon of milk, packed up my xbox360 ... and went to work! You see, at my building they have  microwaves, kitchens, heat, Internet, and hot showers. I was able to spend the day occupied and entertained (Geometry Wars!).

     Several other people were there with their families because it was a warm place to be. One guy I know is still without power and might not have it until Friday! So he's packed up his whole family and they're living at his office for the time being. This is definitely one of the unsung benefits of working at a place like Microsoft.

  • How to enable "click through" for .NET 2.0 ToolStrip and MenuStrip

    .NET 2.0's ToolStrip classes do not support "Click Through" between forms. For more information on what click through is, I recommend reading http://daringfireball.net/2003/05/interface_details_itunes_vs_safari . In Windows, pretty much all applications use "click through," whereby if you have one window active and click on to another one, the mouse click activates the window and the click is processed by whatever control you had the mouse over.

     

    However, you'll notice that Office 2003 and Visual Studio 2005 do not have this type of behavior for at least their menus and toolbars. If you have a window other than Word 2003 active, and hover your mouse over the Word toolbars, you will notice that they do not hot-track. Clicking will first activate the Word window after which you must click again on the toolbar item to activate it.

     

    This is fine and good, and I don't disagree with this user interface decision. However, the .NET 2.0 ToolStrip class makes one glaring omission: it doesn't allow you to disable this behavior. Or rather, it does not allow you to enable click-through. This is usually not important for the most common use of the ToolStrip class, that being to create an application with toolbars docking to the edges of its only Form.

     

    In Paint.NET we have 5 forms active. There's the main form (in code it is aptly called MainForm), then the four child or owned forms that host the Tools, History, Layers, and Colors windows. In Paint.NET I have done a lot of work to ensure that they all behave for the user as one active window.

     

    The problem for us is that the no-click-through behavior persists even within the same application. That is, if the focus is currently on the image canvas in Paint.NET, the moment you try to click on another tool in the Tools window it will actually set focus to the Tools window and not set the tool until you click again. Oops. Actually this isn't really so much of a problem except that you can not configure whether this behavior is used or not.

     

    Well I managed to fix that before we had a public release of v2.6, and I'd like to detail the code that's necessary to do this.

     

    One thing I highly recommend for anyone doing non-trivial Windows Forms development is to get a copy of Reflector (http://www.aisto.com/roeder/dotnet/) and the disassembly plugin by Denis Bauer (http://www.denisbauer.com/NETTools/FileDisassembler.aspx). Next, open up Reflector and add all of the core .NET assemblies. Then run the disassembler plugin over all of them. The code you get is not perfect -- some variable names are lost during compilation and end up being generic upon disassembly -- but the code flow and techniques are there and are very valuable to have. It's good to be able to answer questions such as, "When I set/get this property, is it copying just the reference or calling Clone()?" (hint: almost always the latter)

     

    It took me awhile, but I found that the way this no-click-through is implemented is via the WM_MOUSEACTIVATE notification, and is handled in an overridden WndProc() method. It supports 4 return values which are a 2x2 matrix of "activate" and "eat mouse click." Turns out that the ToolStrip is returning the value corresponding to "activate and eat" (MA_ACTIVATEANDEAT) whereas we want "activate but do NOT eat" (MA_ACTIVATE).

     

    Once we know this it is trivial to create a ToolStripEx class that implements this. This does require unmanaged code permission, and is something of a hack, so you should take that into consideration when using this code.

     

    /// <summary>

    /// This class adds on to the functionality provided in System.Windows.Forms.ToolStrip.

    /// </summary>

    public class ToolStripEx

        : ToolStrip

    {

        private bool clickThrough = false;

     

        /// <summary>

        /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does

        /// not have input focus.

        /// </summary>

        /// <remarks>

        /// Default value is false, which is the same behavior provided by the base ToolStrip class.

        /// </remarks>

        public bool ClickThrough

        {

            get

            {

                return this.clickThrough;

            }

     

            set

            {

                this.clickThrough = value;

            }

        }

     

        protected override void WndProc(ref Message m)

        {

            base.WndProc(ref m);

     

            if (this.clickThrough &&

                m.Msg == NativeConstants.WM_MOUSEACTIVATE &&

                m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT)

            {

                m.Result = (IntPtr)NativeConstants.MA_ACTIVATE;

            }

        }

    }

     

    internal sealed class NativeConstants

    {

        private NativeConstants()

        {

        }

     

        internal const uint WM_MOUSEACTIVATE = 0x21;

        internal const uint MA_ACTIVATE = 1;

        internal const uint MA_ACTIVATEANDEAT = 2;

        internal const uint MA_NOACTIVATE = 3;

        internal const uint MA_NOACTIVATEANDEAT = 4;

    }

     

    Then simply use ToolStripEx in place of ToolStrip.

     

    The important thing with this hack is that you let the ToolStrip base class process the message first, and only fudge the return value from the window message handling if it is returning the one value you are worried about. Otherwise you're overstepping what you're trying to do (and things don't work right).

     

    Also, the MenuStrip class has the same behavior (no click through). It's easy enough to take this hack and make a "MenuStripEx" class. In Paint.NET v2.6, I put the common WndProc functionality into a utility function that both of these classes make use of (PaintDotNet.SystemLayer.UI.ClickThroughWndProc()).


© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker