The ColorPicker WinForms Control

Finishing Up

There were several other minor issues that I had to solve and I've described them in the ColorPicker.vb source file. There was one issue, however, that I'd like to discuss here in more detail.

When the drop-down color selector is displayed by calling the IWindowsFormsEditorService.DropDownControl method, it is expected not to return only until after the user either selects a new color or she cancels the selection. The cancellation can be performed in a variety of ways: by pressing the Esc key, by clicking outside of the drop-down box, by pressing the Ctrl+Esc system key combination or by clicking the ColorPicker button once again.

In other words, the DropDownControl method implementation should block while dispatching windows messages caused by the user interaction with Windows (including the drop-down color selector).

Do you remember the old pal, DoEvents?

This time, however, it is exposed as the DoEvents method of the System.Windows.Forms.Application class. Calling the method causes processing of all the Windows messages in the current thread's message queue. Here is a pseudocode for my first DropDownControl implementation, which uses the DoEvents method:

Namespace LaMarvin.Windows.Forms
...
Public Class ColorPicker
...
Private Class EditorService
    Public Sub DropDownControl(ByVal control As Control) _
    Implements IWindowsFormsEditorService.DropDownControl

    ' Display the drop-down color selector, which
    ' is hosted within a _DropDownHolder Form instance.
   
    ' Wait until the drop-down is closed.
    Do While _DropDownHolder.Visible
        Application.DoEvents()
    Loop
        ...
End Sub

The code shows the drop-down UI and then it enters a loop calling Application.DoEvents until the drop-down form is closed. This way, the DropDownControl method blocks (ignoring the possible reentrancy issues for the moment) while Windows messages are still being dispatched.

It worked fine this way until I realized that when the drop-down color selector is displayed, the process hosting the ColorPicker control eats 100% of the CPU.

Too bad!

Once again, I've turned to the .NET Reflector tool in order to see how the DropDownControl method is implemented within the PropertyGrid itself (which, obviously, doesn't eat 100% CPU while displaying the color selector).

Here is what I found out:

Namespace System.Windows.Forms.PropertyGridInternal
Private Class PropertyGridView
    Private Class DropDownHolder
    Public Sub DoModalLoop()
        Do While MyBase.Visible
        Application.DoEvents
        UnsafeNativeMethods.MsgWaitForMultipleObjects( _
        1, 0, 1, 250, 255)
        Loop
    End Sub
...

The same code as above plus the MsgWaitForMultipleObjects function call. The function is a standard part of the Win32 API. Here is the function's prototype taken from the MSDN documentation (comments mine):

DWORD MsgWaitForMultipleObjects(
DWORD nCount, // number of handles pointed to by the
    // pHandles argument
const HANDLE* pHandles, // pointer to an array of object
    // handles whose signaled state is checked
BOOL bWaitAll, // all object handles should be
    // signaled (TRUE) or any one of them (FALSE)
DWORD dwMilliseconds, // wait timeout
DWORD dwWakeMask // which input events (messages)
    // should cause the function to return (in addition
    // to signaling objects pointed to by pHandles)
);

The purpose of the function is to suspend the calling thread until one or all of the object handles become signaled, OR, until a message appears in the thread's input queue according to the dwWakeMask value. The weird thing is that .NET framework calls the function with the number of object handles equal to ONE, while the pointer to the array of handles is ZERO (Nothing in VB nomenclature).

This way of calling the function is not documented (AFAIK). One can only guess that such a call is used to suspend the calling thread until a message has to be processed WITHOUT checking the signaled state of any object handle. Nevertheless, because the call is used within WinForms implementation itself, I find it quite safe to use it within your own applications. I've used it with ColorPicker and the problem with the drop-down form consuming 100% CPU cycles disappeared.

You can download the ColorPicker control project along with the accompanying demo project here.

The ColorPicker.vb source code is listed on the next page. Enjoy!

You might also like...

Comments

About the author

Palo Mraz

Palo Mraz United States

I live in Slovakia with my wife, two sons (fulltime), one daughter (occasionally) and a dog. I've been doing Microsoft Windows development since 1988; primarily in VB. I'm a big fan of the MS .N...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone” - Bjarne Stroustrup