DCSIMG
August 2009 - Posts - All Your Base Are Belong To Us

All Your Base Are Belong To Us

Mostly .NET internals and other kinds of gory details

August 2009 - Posts

GC Helper for Obtaining Live Instances of a Type, or How I Implemented GC.GetAliveInstancesOf<T>()

Patrick humbly asks for a method tentatively called GC.GetAliveInstancesOf<T>() that returns a collection of referenced instances of a specific type.

While useful, this is something that doesn’t belong in the .NET framework, much more so in the API of the garbage collector, but it’s still very useful for diagnostic scenarios (e.g. SOS yields this information easily through the !dumpheap –type command).

The following is a quick and dirty suggestion at an implementation that “automagically” tracks live object instances and returns them on demand. The idea is that the object’s constructor can add a weak reference to the object to a static hash table, and the object’s finalizer can remove the weak reference from that table. Because we’re using weak references, they in themselves do not prevent the objects from being collected.

The code is rather long for a blog post and includes four significant parts:

  • SynchronizedWeakHashSet<T> is a collection of weak references that is thread-safe and offers only a small subset of operations. The Remove operation is especially inefficient as it iterates through all the objects, and to resolve this we would have to introduce a token that uniquely identifies the object without storing its reference.
  • InstanceTracker<T> is designed as a base class for objects that require instance tracking. Its constructor and finalizer do the actual magic of storing the object’s reference, and the GetLiveInstances static method waits for GC and finalizers to complete and then returns the live objects.
  • MyClass is a sample class that conditionally derives from InstanceTracker<MyClass> so that its instances are tracked at runtime.
  • The main program creates three instances of MyClass and shows the live ones (there should be only one live instance, rooted at the static member variable).

public sealed class SynchronizedWeakHashSet<T> where T : class

{

    private readonly object _syncRoot = new object();

    private readonly HashSet<WeakReference> _hash =
        new HashSet<WeakReference>();

 

    public int Count

    {

        get

        {

            lock (_syncRoot)

                return _hash.Count;

        }

    }

 

    public T[] ToArray()

    {

        lock (_syncRoot)

        {

            T[] arr = new T[_hash.Count];

            int curr = 0;

            var toRemove = new List<WeakReference>();

            foreach (WeakReference wr in _hash)

            {

                T inst = wr.Target as T;

                if (inst == null)

                {

                    //Remove any dead references.

                    toRemove.Add(wr);

                }

                else

                {

                    arr[curr++] = inst;

                }

            }

            foreach (WeakReference wr in toRemove)

                _hash.Remove(wr);

            return arr;

        }

    }

 

    public void Add(T instance)

    {

        lock (_syncRoot)

            _hash.Add(new WeakReference(instance));

    }

 

    public void Remove(T instance)

    {

        //This is not efficient, but to do better we need a token

        //that can identify the weak reference for us.

        lock (_syncRoot)

        {

            var toRemove = new List<WeakReference>();

            foreach (WeakReference wr in _hash)

            {

                object target = wr.Target;

                if (target != null &&
                    Object.ReferenceEquals(target, instance))

                {

                    toRemove.Add(wr);

                    break;

                }

                else if (target == null)

                {

                    //Remove any dead references.

                    toRemove.Add(wr);

                }

            }

            foreach (WeakReference wr in toRemove)

                _hash.Remove(wr);

        }

    }

}

 

#if DEBUG

public abstract class InstanceTracker<T>
    where T : InstanceTracker<T>

{

    private static readonly SynchronizedWeakHashSet<T> _instances
        = new SynchronizedWeakHashSet<T>();

 

    public static IEnumerable<T> GetLiveInstances()

    {

        GC.Collect();

        GC.WaitForPendingFinalizers();

 

        return _instances.ToArray();

    }

 

    protected InstanceTracker()

    {

        _instances.Add((T)this);

    }

    ~InstanceTracker()

    {

        _instances.Remove((T)this);

    }

}

#endif

 

class MyClass

#if DEBUG

    : InstanceTracker<MyClass>

#endif

{

    public int Id { get; set; }

}

 

class Program

{

    static MyClass _root;

 

    static void Foo()

    {

        _root = new MyClass { Id = 5 };

        _root = new MyClass { Id = 3 };

        _root = new MyClass { Id = 4 };

    }

 

    static void Main(string[] args)

    {

        Foo();

        foreach (MyClass mc in
                 InstanceTracker<MyClass>.GetLiveInstances())

            Console.WriteLine(mc.Id);

    }

}

This code is conditionally compiled only into the Debug build. (There are obviously cleaner alternatives, the key is that the finalizer must not be present in Release builds because of its performance hit.)

Remember that this is nothing more than a quick and dirty demo, but it proves the point and might turn out useful for diagnostic purposes.

Windows 7 Taskbar: Tabbed Thumbnails and Previews in Native Code

A few months ago, we’ve taken a look at how you can extend your MDI or TDI application with an individual thumbnail and live preview for each tab (or document) that will be displayed in the Windows 7 taskbar. We’ve seen the temporary managed wrapper that makes this possible, and in the final 1.0 release of the Windows API Code Pack there is a more polished managed API that does the same thing.

However, in this post I’d like to focus on the underlying details which you will have to deal with if you’re writing your GUI application in C++. There’s a hands-on lab that I wrote for the latest release of the Windows 7 Training Kit that shows how to take a Win32 dialog with a tab control and multiple tab pages, and turn each tab page into a thumbnail with a preview.

You can go ahead and do the hands-on lab—there’s a fairly comprehensive document that tells you everything you need to along the way—or you can read this (more brief) description.

What you need to do to support “tabbed thumbnails” is the following:

  1. If your application process has a high integrity level (e.g. if it’s usually launched as administrator), make sure that the DWM messages can pass through, or else they will be filtered by UIPI. Specifically, call the ChangeWindowMessageFilter API and enable the WM_DWMSENDICONICTHUMBNAIL and the WM_DWMSENDICONICLIVEPREVIEWBITMAP window messages to pass through.
  2. Figure out a way to grab a live bitmap rendering of each individual tab—this bitmap must be 32-bit ARGB. This sounds easy, and it indeed might be easy if you have your own custom rendering code. This isn’t easy, however, if you’re just using standard Win32 controls—if the control is not currently visible, you might have to go through hoops to grab a preview of it (e.g. in a TDI application, you could grab a preview of a tab just before switching to another tab).
  3. For each tab window (which is usually a child window), create a top-level proxy invisible window that will deal with the window messaging required to make the thumbnail work. As far as the taskbar and the DWM are concerned, these top-level proxy windows are the ones showing the tab thumbnails, not your application’s “real” tab windows, so all the API calls below have to be performed with the proxy window handles as the parameters. (The reason for this is a limitation of the DWM, which can’t interact with non-top-level windows.)
  4. As you create your proxy windows:
    1. Call the DwmSetWindowAttribute method to set the DWMWA_FORCE_ICONIC_REPRESENTATION and the DWMWA_HAS_ICONIC_THUMBNAIL window attributes. This instructs the DWM to poll your proxy windows for the taskbar thumbnail and live preview.
    2. Register them to appear in the taskbar by calling the ITaskbarList4::RegisterTab method, and set their relative order with regard to the other tabs by calling the ITaskbarList4::SetTabOrder method. (ITaskbarList4 is a minor extension of ITaskbarList3.)
  5. When a tab becomes active, call the ITaskbarList4::SetTabActive method so that this tab’s thumbnail appears as active.
  6. When the proxy window’s procedure receives the WM_DWMSENDICONICTHUMBNAIL message, call the DwmSetIconicThumbnail method and pass to it the window’s thumbnail bitmap. Note that the dimensions of the thumbnail are specified as the high-word and low-word of the lParam message parameter, and you must adhere to these dimensions.
  7. When the proxy window’s procedure receives the WM_DWMSENDICONICLIVEPREVIEWBITMAP message, call the DwmSetIconicLivePreviewBitmap method and pass to it the window’s live preview bitmap. If the window does not overlap the entire application frame, you can use an additional offset parameter to specify the offset of the provided bitmap from the top-left corner of the application’s window. The rest of the window will be captured by DWM automatically for you. (This means that Internet Explorer, for example, doesn’t have to grab a bitmap of the entire window, only of the tab itself. The menus and toolbars could be taken care of by DWM.)
  8. When the proxy window’s procedure receives the WM_ACTIVATE message, switch to the corresponding tab window in your application UI.
  9. When the proxy window’s procedure receives the WM_SYSCOMMAND message, check wParam for the SC_CLOSE code. Any other codes should be forwarded to the application’s main window; SC_CLOSE should be handled by the proxy window’s window procedure (e.g. you can call DefWindowProc that will send you a WM_CLOSE message).

As you can see, there’s a lot of manual labor in having to implement all of this logic every time you want tabbed thumbnails. Even though it’s obviously your responsibility to obtain the thumbnail bitmap and live preview bitmap, and to calculate their offset from the application frame, at least some of the proxy windowing work can be streamlined. For this purpose, the hands-on lab I’ve mentioned earlier provides a TabWindow class, that I will cover in a subsequent post.

Windows 7 RTM Training Kit Updates

Windows 7 RTM is out for a few days now for MSDN and TechNet subscribers, and together with the release of the final bits, Microsoft DPE released the final bits of the Windows 7 Training Kit.

Our team at Sela worked days and nights to meet the RTM deadline. Specifically, Alon wrote new multi touch and Libraries hands-on labs, Dima (with Ariel’s help) wrote new labs for the Sensors and Location platform, and I wrote a pair of new labs for taskbar features, one using the final 1.0 release of the Windows API Code Pack and WPF and another using pure Win32 C and C++ code.

Other materials that made it to the training kit have to do with application compatibility on Windows 7. You might have already heard that are hardly any breaking changes from Vista to Windows 7, but if you never made the move to Vista you might find some compatibility problems when testing your app on Windows 7.

To help you with those, the training kit now includes presentations and labs on High DPI, Installer Detection, Session 0 Isolation, UAC Redirection, UIPI and Version Checking—which are among the most common issues developers and testers encounter on Vista and Windows 7, and most of them have been written by our team at Sela.

If you haven’t done so yet, go ahead and install Windows 7 and its SDK, download the training kit and start going through the multitude of features and the hands-on labs that accompany them!

Windows 7 on 512 MB of RAM

My parents’ three year old PC (running Windows XP) was giving them some trouble lately. Specifically, it was so bloated with odd application installations, crapware of all sorts, and years of careless usage, that I figured that only a clean install could salvage the box. So I asked them to make a backup of all the movies, photos and music they had on their computer, and suggested that we do a clean install of Windows 7.

The one catch here was that their machine has 512 MB of RAM. If you look at the Windows 7 hardware requirements, you’ll see that you need 1 GB of physical memory. It doesn’t prevent you from installing the system, but as they say, it’s not recommended.

So first I installed a VM of Windows 7 and gave it 512 MB of physical memory. True, I didn’t install all kinds of apps inside the VM but I did have multiple browser tabs open, some downloads going on in the background, a movie streaming into the VM from the Media Center in the living room—and all in all, it was OK.

So I decided to take the plunge and installed Windows 7 on their PC yesterday. The box has 512 MB of RAM, as I said, and it also has a 2.4 GHz Pentium 4 (single core) processor, a very slow and very old 70 GB hard drive, and a fairly old ATI graphics card. Nonetheless, the setup took less than 30 minutes to complete (these days I’m usually doing Windows installations from a USB disk on key) and we had a Windows 7 box in front of us.

The amazing thing is that it worked. It gave us a Windows Experience Index of 2.9 (with the weakest link being the memory), but it even agreed to switch to the Aero theme and wasn’t sluggish at all. Even after installing Office 2007 and a couple of other productivity apps, the machine was totally usable. In fact, even with Internet Explorer and Word open, there were still some 150 MB of physical memory available, and disk paging was nowhere to be heard.

My 9” Eee netbook (with a slow 16 GB SSD and a 900 MHz processor) was the first; this is yet another testimony to the amazing performance and resource utilization improvements in Windows 7.