Welcome to shell: revealed Sign in | Join | Help
in Search

Shell Blog

Building Your First TaskDialog (Part 1)

Building Your First TaskDialog (Part 1)
Jeff Miller - September 19, 2006

A TaskDialog is a new control for Windows Vista which can be thought of as a MessageBox on steroids.  If you have information you need to present to a user using a dialog, you will find that using a TaskDialog will make it trivial to present choices in a clear and consistent way, with a standardized look and layout.

Preparation

I’m not going to make any assumptions as to your how your development environment is set up, and as such, I’ll start by describing how you can build and test TaskDialogs starting with a clean environment.  If you already have a build environment set up, you can modify the instructions below accordingly.

The first thing you’ll need is Windows Vista, of course.  TaskDialogs are only available on Windows Vista, and while you can compile TaskDialog code on any Windows platform, I find it convenient to build and test on a single machine. As of this writing, you can download and install Windows Vista from http://www.microsoft.com/windowsvista/getready/preview.mspx -- go ahead and do that now, I’ll wait until you’re done.

Okay, now that you have Windows Vista running and installed (make sure you check out the cool new games included in Vista!), you’ll need to download the Windows SDK.  Some of you old timers might know the Windows SDK by its former name, the Platform SDK.  Go ahead and download and install it from http://www.microsoft.com/downloads/details.aspx?familyid=117ecfd3-98ad-4d67-87d2-e95a8407fa86 onto your Windows Vista machine.  I recommend installing it to the default location of %ProgramFiles%\Microsoft SDKs\Windows\v6.0.  You can either do a full install of the Platform SDK, or just install the components that are required for this tutorial, which include:

  • Developer Tools > Windows Vista Headers and Libs
  • Visual C++ Compilers > x86 C++ Compiler

Setting up the build environment

Once you have the Windows SDK installed, you’ll want to set up a build environment.  To do this, open a command window (in Vista, click on the Start pearl, and type in command.  Thanks to the wonderful search and organize feature of Vista, you should be presented with “command prompt” as an option) and type the following commands:

cd /d %ProgramFiles%\Microsoft SDKs\Windows\v6.0\bin
setenv.cmd /vista

Now you’re ready to build your first TaskDialog application!

Creating a MessageBox application

Before we get to a TaskDialog, let’s check that the build environment is set up correctly by creating a simple application that displays a MessageBox.  We’ll build upon this application when we start making a TaskDialog application.

Inside of your build environment, create a new directory.  You’re going to be creating some project files in this directory.  The first file to create will be named “MessageBox.mak”, which is the makefile for the project.  If you’re not familiar with makefiles, you can find more information in MSDN under the path “Development Tools and Languages > Visual Studio > Visual C++ > Building a C/C++ Program > Building on the Command Line > NMAKE Reference” (online at http://msdn2.microsoft.com/en-us/library/dd9y37ha.aspx).  Here are the contents of the makefile:

MessageBox.mak

!INCLUDE <WIN32.MAK>
ALL: MESSAGEBOX.EXE

.C.OBJ:
  $(CC) $(CDEBUG) $(CFLAGS) $(CVARS) $*.C

MESSAGEBOX.EXE: MESSAGEBOX.OBJ
  $(LINK) $(LDEBUG) $(CONFLAGS) -OUT:MESSAGEBOX.EXE MESSAGEBOX.OBJ $(CONLIBS)

If you’re interested in learning what all of those variables (such as “$(CC)”) translate to, open up %ProgramFiles%\Microsoft SDKs\Windows\v6.0\Include\Win32.mak in a text editor.  It should be (somewhat) obvious as to what the values mean.

The next file to create is the source code file:

MessageBox.c

#define UNICODE
#define _UNICODE
#include <windows.h>

int CALLBACK WinMain(
    __in HINSTANCE hInstance,
    __in_opt HINSTANCE hPrevInstance,
    __in_opt LPSTR lpCmdLine,
    __in int nShowCmd
    )
{
    int nButton;
    nButton = MessageBox(NULL, L"Hello, World!", L"MessageBox Test", MB_OK | MB_ICONINFORMATION);
    return nButton;
}

Some things to note are:

  1. We’re building a Unicode application.  Any modern Windows application should be built as Unicode, and not ANSI, and in fact, the TaskDialog API is only available in a Unicode form.
  2. We’re using SAL annotations (such as “__in”) on the WinMain function.  These annotations allow tools to validate assumptions about the parameters that are passed to methods in your code.  For more information on SAL Annotations, see the MSDN article under the path “Development Tools and Languages > Visual Studio > Visual C++ > Reference > Libraries Reference > Run-Time Library > C Run-Time Libraries > SAL Annotations” (online at http://msdn2.microsoft.com/en-us/library/ms235402.aspx)

Nmake

Now that we have a makefile and a source code file, we’re ready to build.  Inside of your build environment, type:

nmake /f MessageBox.mak

If all goes well, you will now have an executable named MessageBox.exe.  Go ahead and run it, and you will see the following output:

If you’re used to versions of Windows prior to Windows Vista, you’ll note that the standard Windows MessageBox is a lot snazzier than in the past.  The layout is cleaner, and the icon has a more modern look to it.

Creating a TaskDialog application

Okay, now that we have a basic project working, let’s modify it to display a TaskDialog.  Let’s go ahead and modify the source code to read as follows:

MessageBox.c

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <commctrl.h>

int CALLBACK WinMain(
    __in HINSTANCE hInstance,
    __in_opt HINSTANCE hPrevInstance,
    __in_opt LPSTR lpCmdLine,
    __in int nShowCmd
    )
{
    int nButton;
    TaskDialog(NULL, NULL, L"TaskDialog Test", L"Hello, World!", L"This is a TaskDialog demonstration", TDCBF_OK_BUTTON, TD_INFORMATION_ICON, &nButton);
    return nButton;
}

Note that we’ve included a new header file, commctrl.h, which is where the TaskDialog API is defined. Now build the updated source code using:

nmake /f MessageBox.mak

You should see output (and an error) that looks like this:

Microsoft (R) Program Maintenance Utility Version 8.00.50727.42
Copyright (C) Microsoft Corporation.  All rights reserved.

        cl -Zi -Od -DDEBUG -c -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -nologo -GS -D_X
86_=1  -DWIN32 -D_WIN32 -W3 -D_WINNT -D_WIN32_WINNT=0x0600 -DNTDDI_VERSION=0x060
00000 -D_WIN32_IE=0x0700 -DWINVER=0x0600  -D_MT -MTd MessageBox.c
MessageBox.c
        link /DEBUG /DEBUGTYPE:cv  /INCREMENTAL:NO /NOLOGO -subsystem:windows,6.0 -out:MessageBox.exe MessageBox.obj MessageBox.res  kernel32.lib  ws2_32.lib mswsock.lib advapi32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib
MessageBox.obj : error LNK2019: unresolved external symbol
__imp__TaskDialog@32 referenced in function _WinMain@16
MessageBox.exe : fatal error LNK1120: 1 unresolved externals
NMAKE : fatal error U1077: '"E:\Program Files\Microsoft SDKs\Windows\v6.0\VC\Bin\link.EXE"' : return code '0x460'
Stop.

What this is telling you is that the method “__imp__TaskDialog@32” (which is the decorated name for the TaskDialog method) could not be found in any of the libraries you are linking to. If you look at the MSDN documentation for TaskDialog, you will note that the TaskDialog method is located in the comctl32.lib library, so we need to explicitly link to that library as well.  To do that, modify the makefile to read as follows:

MessageBox.mak

!INCLUDE <WIN32.MAK>

ALL: MESSAGEBOX.EXE

.C.OBJ:
  $(CC) $(CDEBUG) $(CFLAGS) $(CVARS) $*.C

MESSAGEBOX.EXE: MESSAGEBOX.OBJ
  $(LINK) $(LDEBUG) $(CONFLAGS) -OUT:MESSAGEBOX.EXE MESSAGEBOX.OBJ $(CONLIBS) COMCTL32.LIB

All we’ve done is add “COMCTL32.LIB” to the end of the link command line. Now build the updated source code and makefile again:

nmake /f MessageBox.mak

You will now have an updated executable named MessageBox.exe.  Run it, and you will get the following output:


That’s probably not what you were expecting, right?  So what on earth does “The ordinal 344 could not be located in the dynamic link library COMCTL32.dll” mean?  The short answer is that there are two versions of COMCTL32.dll on Windows Vista systems, one (version 5) which is a “legacy” control DLL, and one (version 6) which contains all of the cool new controls for Windows Vista.  Your application needs to “opt in” to version 6, and to do so you will need to specify a manifest file.  Before we do that however, we can verify that this is indeed the problem.

Running Depends

In the build environment, type the following command:

depends.exe MessageBox.exe

(If depends isn’t on your system, you can download it at http://www.dependencywalker.com/)
Depends will show an error for comctl32.dll, as there’s a missing export for that DLL.  Choose “Properties” for the comctl32.dll that is displayed, and the path will show:

“C:\windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.5721.0_none_a9f56da8f3ae70be”.

Note that the version shown for this DLL is “5.82.5721.0”, which indicates that this is comctl32.dll version 5.  We want to bring in version 6 using a manifest file.

Opting in to COMCTL32.DLL version 6

To opt into comctl32 version 6, please first read the article entitled “Using Windows XP Visual Styles”, located in the MSDN library under “Win32 and COM Development > Windows XP > Using Windows XP Visual Styles” (online at http://msdn.microsoft.com/library/en-us/dnwxp/html/xptheming.asp).  This article provides much more information and background on Visuals Styles and comctl32 version 6 than I could do justice here.  For now, let’s update our makefile accordingly:

MessageBox.mak

!include <win32.mak>

all: MessageBox.exe

.c.obj:
  $(cc) $(cdebug) $(cflags) $(cvars) $*.c

.rc.res:
  $(rc) $(rcflags) $(rcvars) $*.rc

MessageBox.exe: MessageBox.obj MessageBox.res
  $(link) $(ldebug) $(guilflags) -out:MessageBox.exe MessageBox.obj MessageBox.res $(guilibs) comctl32.lib

Note that we’ve added a new rule for making .res files from .rc files, as well as adding a new file (“MessageBox.res”) to the link line.

As described in the MSDN article, we’ll need a manifest file added to our binary to opt into comctl version 6.  Here’s what it should look like:

MessageBox.exe.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
        version="1.0.0.0"
        processorArchitecture="X86"
        name="Microsoft.TestApps.TaskDialog"
        type="win32"
    />
    <description>TaskDialog Test Application</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                processorArchitecture="X86"
                publicKeyToken="6595b64144ccf1df"
                language="*"
        />
        </dependentAssembly>
    </dependency>
</assembly>

Lastly, we’ll need a resource (“.rc”) file to reference the manifest file, so create a new file for that:

MessageBox.rc

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "MessageBox.exe.manifest"

Now rebuild the updated project using nmake as we did before…

nmake /f MessageBox.mak

…and run the executable that’s created, MessageBox.exe.  You should see your first TaskDialog:


Okay, so it looks a lot like the Window Vista MessageBox, but don’t fret, we’re just getting started!  In the next part of this series, I’ll show the advanced features of TaskDialog that set it apart from the MessageBox, and frankly, just about any other control that’s been delivered in Windows so far.  Until then, read the documentation, modify the test application I’ve provided, and see what you discover.

 

Published Tuesday, September 19, 2006 3:33 PM by uisamurai

Comments

 

Jason Haley said:

September 19, 2006 11:01 PM
 

Jason Haley said:

September 19, 2006 11:06 PM
Anonymous comments are disabled

About uisamurai

I'm the development lead for the Windows Shell Visuals team. I've been at Microsoft since May 1995. I'm known for my coding, not my bio writing.
Powered by Community Server, by Telligent Systems © 2006 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement.