An exercise in discovering how to use Command Links in Windows Vista without documentation

This Thursday and Friday we are running a Vista lab for a number of our ISV early adopters. One area I am looking at for the lab is the Command Link control - and how ISVs can make use of it in Windows Vista.

What are Command Links and why should we care?
Command links allow for immediate and more expressive choices, eliminating the need to always use a combination of radio buttons and a Next button. Ultimately Command Links are a rather useful new style of button - that applications will increasingly start to use. Many of the newer applications in Windows Vista use Command Links which means users will start to expect this improved behavior. This ultimately means that soon you will also need to make careful and selective use of them

The challenge - guidance on use but no developer documentation
The draft of the UX Guide for Windows Vista has a page on Command Links  - yippee. Alas - this is currently a placeholder page - boo! Command Links are shown and discussed briefly as part of Aero Wizards and the new TaskDialog controls. The Command Link control is very simple and straight forward. BUT... there is no documentation on how you can use it. Here lies the problem for our ISVs.

What REALLY is a Command Link? UISpy to the rescue...
Thankfullt they turn out be just a normal Win32 button - but buttons in Vista respond to a few additional button messages which gives you the new style. How do I know that? If you bring up a dialog in Windows Vista which is using Command Links and then use UISpy (part of the Windows SDK) to look at the window, you will see the Command Links are ControlType.Button. That makes life easier. It means we just need to use normal Win32 buttons - and send them a few extra messages - but what messages?

Headers == Documentation
The trick is to get yourself down and dirty with the header files which come as part of the Windows SDK. Bring up a command prompt in the Includes directory (typically c:\Program Files\Microsoft sdks\Windows\v1.0\include) and type:
    findstr /si COMMANDLINK *.h

This will give you hits in:
   CommCtrl.h 
   credentialprovider.h
   vsstyle.h

If we look at CommCtrl.h we can see a button style of:
   #define BS_COMMANDLINK          0x0000000EL

With a little bit of inside knowledge, I also knew that you can attach notes to Command Links. Notes are the smaller sized text beneath the main text. Searching for Note gives us:
   #define BCM_SETNOTE              (BCM_FIRST + 0x0009)
   #define Button_SetNote(hwnd, psz) \
    (BOOL)SNDMSG((hwnd), BCM_SETNOTE, 0, (LPARAM)(psz))

   #define BCM_GETNOTE              (BCM_FIRST + 0x000A)
   #define Button_GetNote(hwnd, psz, pcc) \
    (BOOL)SNDMSG((hwnd), BCM_GETNOTE, (WPARAM)pcc, (LPARAM)psz)

   #define BCM_GETNOTELENGTH        (BCM_FIRST + 0x000B)
   #define Button_GetNoteLength(hwnd) \
    (LRESULT)SNDMSG((hwnd), BCM_GETNOTELENGTH, 0, 0)

Excellent - we can now see how to get a Command Link style and also how to set and get the note text. The last thing a Command Link can do is show the nifty little shield icon for something that needs Administrator rights. Low and behold CommCtrl.h has the answer again:
   #define BCM_SETSHIELD            (BCM_FIRST + 0x000C)
   #define Button_SetElevationRequiredState(hwnd, fRequired) \
    (LRESULT)SNDMSG((hwnd), BCM_SETSHIELD, 0, (LPARAM)fRequired)

We now have enough info to easily use Command Links from VC++ and enough info to start to think about how to use them from C# or VB.NET. Thats exactly what my next post on Command Links will cover.

Two related posts from Ian and yep - Ians posts predate mine as he is a heck of a lot smarter at all things UI than me :-)  The first shows you how to use the PowerShell to deliver a better findstr. The second details his own explore of Command Links using Spy++.