Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Icon Browser: An Exercise in Resource Management


September 2002/Icon Browser: An Exercise in Resource


The System::Runtime:: InteropServices namespace contains many useful classes, structures, and attributes that you can use to access your legacy libraries and resources. The .NET Framework as a whole also provides many services for migrating existing code and resources to managed code. This article explains how to use these services to extract resources from Win32 resource files, as well as how to write icon resources to .ICO files. It also covers many of the issues surrounding resource management and interoperating with unmanaged code, memory, and binary formats.

Introduction

Every so often, I find myself needing to extract an icon from an executable or DLL (dynamic-link library), and every time I end up bending over backwards to get this done, especially if the library contains hundreds of icons and I have to sift through all of them until I find the one I want. So I decided to write a little program to make the process of extracting an icon from a library much easier. Well, it started out simple. I wrote the Icon Browser application in Managed C++ using the .NET Framework, and, in about 45 minutes, I had a really cool icon viewer. The .NET Framework provides a vast library of classes that boosts productivity immensely by providing many of the building blocks you would normally have to write yourself. Then I attempted to implement the export feature that would allow the user to choose any icon in the library and save it to an external .ICO file. I hit a brick wall. It turns out there’s no simple way to save an icon to a file.

In this article, I present the Icon Browser application. It is a small desktop application that allows you to browse through the icons embedded in executables and DLLs and to save any of the icons to a .ICO file. I will use this application as a vehicle for exploring programming tasks such as reading and writing unmanaged resources and other issues related to porting or coexisting with legacy code and binaries. In addition, I’ll look at taking unmanaged C++ classes employing traditional deterministic finalization and show you how to implement them as Managed C++ and C# classes, ensuring that they behave well in the .NET environment where the garbage collector reigns.

Most of the functions, classes, and structures that are mentioned in this article are documented in the MSDN Library, which is available at Microsoft’s website. If you want to find out more about a particular point that I mention, the MSDN Library is a good place to start.

Icon Browser

Before I get into the programming details, let me quickly introduce the Icon Browser and show you how to use it. Even if you’re not too interested in resource management and interoperating with unmanaged code from .NET, you might find this application useful. Icon Browser is very easy to use (see Figure 1). You can type a filename in the edit box and click the Go button, and Icon Browser will search the given file and display any icons it finds in the list view. If you’re not sure about the name or location of the file, you can click the Browse button and search for a file using the familiar “Choose a File” dialog box. Once the icons have been loaded into Icon Browser, you can choose any one of the icons and click the Export Icon button to save the icon to a .ICO file. You will be presented with a “Save Icon As” dialog box so that you can indicate where to save the new .ICO file. I’ve also added a handy context menu to the list view so that you can just right click on an icon and select the Export Icon command.

If you are following along with me on your own computer, you will notice that there is a default filename in the “Save Icon As” dialog box, and it’s probably a number. That name or number is the resource name for the icon in the library. It’s just a unique way to identify a resource in a library. The resource name is also used as the title for each of the icons displayed in Icon Browser (see Figure 1).

And that’s the Icon Browser application, simple but effective! The application as well as its source code is available for download at <www.cuj.com/code>.

What Are Icons Anyway?

Most people think of icons as the little images that represent documents and other files in the Windows shell. Technically, an icon is a group of icon images. An icon image resembles a DIB (device-independent bitmap). So an icon can be represented by a number of different images tailored for different display configurations. In fact, when designing icons for Windows XP, you are encouraged to include nine different images. Figure 2 shows the images for Microsoft Notepad in GIF Movie Gear, which is a tool you can use to assemble icon images and save to a .ICO file.

When using an icon, you will typically only deal with a handle to the icon and not the actual icon resource. In C or C++, you will use HICON, which is simply an abstract handle to the icon, and pass it to the various Win32 API calls. This is the traditional way that resources are managed in C. In the managed world of .NET, you will use the Icon class.

Loading Icons, So Many Choices!

There are many different ways to load an icon. Two of the most common Win32 API functions you can use are ExtractIcon and LoadIcon. ExtractIcon will return an HICON given a filename and the zero-based index of the icon in the file. This is useful if you just want to enumerate all or some of the icons in a file. LoadIcon is a bit more useful in that you can identify an icon based on its resource name or identifier. In .NET, you don’t generally load icons from unmanaged executables or DLLs. Instead you will normally use the ResourceManager class to load resources from resource files as defined by the .NET Framework.

So how do you read icons from unmanaged libraries? Read on.

P/Invoke

P/Invoke (Platform Invoke) is the bridge between the managed world of .NET and unmanaged code like the Win32 APIs. P/Invoke is part of the .NET Framework’s extensive interoperability layer. To call an unmanaged function, you need to use the DllImport attribute to identify the function and the DLL that implements it. You can still of course use the linker to link to a .LIB file and include the appropriate headers, as has been done by C++ programmers for years. But P/Invoke provides an alternative for C++ programmers and is the only way to accomplish this from other managed languages like C#. Here is the declaration for the LoadIcon API:

// Original declared in: winuser.h
// HICON LoadIcon(HINSTANCE hInstance,
//                PCTSTR pName);

[DllImport("User32.dll", SetLastError=true,
           CharSet=CharSet::Auto)]
static void* LoadIcon(System::IntPtr hInstance,
                      System::IntPtr pName);

"User32.dll" is the single parameter to the DllImportAttribute instance constructor. It identifies the DLL implementing the unmanaged function. SetLastError and CharSet are public fields for the DllImportAttribute class.

Setting the SetLastError field to true informs the CLR (Common Language Runtime) that the unmanaged function may call the SetLastError Win32 API function. In response, the CLR will cache the value returned by the GetLastError Win32 API function so that you can retrieve it later. This avoids race conditions, as it is possible for another function used by the CLR to call SetLastError before you get around to retrieving the error code. The .NET Framework exposes the cached error code through the GetLastWin32Error static method on the Marshal class. So it is a good idea to set this field if you suspect your unmanaged functions may set the last error code and you are interested in retrieving it.

Setting the CharSet field to CharSet::Auto indicates that the unmanaged function has a Unicode and an ANSI version. Most Win32 API functions that deal in any way with strings qualify. For example, a function named LoadIcon doesn’t actually exist. It is actually #defined to LoadIconW if UNICODE is defined or LoadIconA if it is not. The -W, or Unicode, versions of the functions were introduced with Windows NT as Windows NT and it successors, Windows 2000 and XP, deal natively with Unicode strings. Windows 9x and its successor Windows ME mostly only support the -A, or ANSI, versions. Setting CharSet to CharSet::Auto instructs the CLR to pick the right version based on the operating system that the code is running on. If you don’t explicitly set the CharSet field, it defaults to CharSet::Ansi, which won’t give you the best performance on Windows XP as the operating system will have to convert any strings from ANSI to Unicode before it can use them. This is an improvement over unmanaged C++ where you had to create separate builds to optimize for ANSI and Unicode, using the _T macro to create text-generic literals.

The next thing you’ll notice is that I’ve changed the parameter types to the IntPtr value type. You will normally use IntPtr for opaque unmanaged types that can’t be represented by corresponding managed types. Although pName is a PCTSTR, which is a constant pointer to a TCHAR (in other words a string), it is more commonly used to pass an integer identifier using the MAKEINTRESOURCE macro. For this reason, pName is also declared as an IntPtr.

LoadIcon, as with many of the resource management functions, requires an instance handle. If you’re programming in C++, then this is no problem. The operating system will assign your process an instance handle when it first starts up. And if you need to get resources from another DLL or executable, you simply call LoadLibraryEx and pass the LOAD_LIBRARY_AS_DATAFILE flag to indicate that you just want access to the resources within the library and don’t want to execute any code it may contain. Here’s an example of using the LoadLibraryEx function to load the Windows Explorer shell executable from unmanaged C++:

HMODULE hModule = ::LoadLibraryEx
    (_T("C:\\Windows\\Explorer.exe"),
     0, // must be zero.
     LOAD_LIBRARY_AS_DATAFILE);

Although LoadLibraryEx returns a module handle, it is generally interchangeable with an instance handle, so you can freely pass it to functions that expect a HINSTANCE. In fact, a HMODULE is typedefed to be a HINSTANCE in windef.h. In the world of .NET however, you don’t deal with instance handles but rather with assemblies. An assembly, which is usually packaged as an executable or DLL, can be loaded using the Assembly::LoadFrom method as shown here:

Assembly* assembly =
    Assembly::LoadFrom(S"C:\\MyResources.dll");

The Assembly class contains a host of properties and methods for accessing the various types defined in an assembly and can be used with the classes in the System::Resources namespace to retrieve any resources.

Resource Management

Let’s get back to the problem at hand. To retrieve resources from unmanaged libraries, you need to declare a few of the Win32 API functions for use in .NET. I tend to put all my declarations in a single class that I call WindowsAPI. This way I can check at a glance what dependencies my project may have to ensure that they are available on any platforms that I support. You can download the WindowsAPI class at <www.cuj.com/articles/2002/0209/cnet_code.htm>. Because resource management is so important (yes, even when using .NET), you should avoid using these functions directly as your code will end up getting quite messy as you try to free the various resources when you’re done using them. Remember that you must always write your code to be resilient to exceptions. The best way to do this is to wrap any resource management functions inside a class. If you are a traditional C++ programmer, your first pass at writing a Managed C++ class to wrap the library functions might look something like Figure 3, with error handling code omitted for brevity. The __gc keyword indicates that the class is garbage collected, and its lifetime is managed by the CLR.

This is perfectly acceptable from an unmanaged C++ point of view, and it will even compile and work in Managed C++. There’s only one problem. The .NET Framework uses non-deterministic finalization. What this means is that .NET’s garbage collector will call your object’s destructor (called a finalizer in .NET speak) in a non-deterministic fashion, most likely when it notices you’re low on memory. So unlike in unmanaged C++ where your destructor is guaranteed to be called when execution leaves the scope in which the object was created, in .NET you cannot rely on a destructor to free your resources in such a timely fashion. Remember that all reference types in the CLR are created on the managed heap and the managed heap is controlled by the garbage collector. Fortunately .NET defines a pattern for resource management, which if followed consistently makes resource management a breeze. The .NET Framework defines the IDisposable interface, which has a single method called Dispose. When used in conjunction with the C# using statement, it provides precise control over when your class will be disposed. So I’ll rewrite the Library class to make use of the IDisposable interface, again with error handling omitted for brevity (see Figure 4). This is a simplification of the Dispose pattern, but it effectively illustrates the point without sacrificing too many trees. My new Library class can now be used as follows from C#:

using (Library library = new Library
    (@"C:\Windows\Explorer.exe"
     WindowsAPI.LOAD_LIBRARY_AS_DATAFILE))
{
    // use the library
}

Before execution leaves the using scope, the library will be freed. But what about using it from Managed C++? Well, although managed C++ doesn’t have a using keyword, you can use the __finally statement (which Visual C++ has had for many years to support Win32 structured exception handling) to call Library::Dispose as shown here. This ensures that the Library object will be freed even if an exception is thrown at any point after creating the object.

Library* library = 0; 

try
{
    library = new Library
        (S"C:\\Windows\\Explorer.exe",
         WindowsAPI::LOAD_LIBRARY_AS_DATAFILE);

    // Use the library
}
__finally
{
    if (0 != library)
    {
        library->Dispose();
    }
}

Note that this doesn’t free the memory held by the Library object, it merely frees the resources held by that object. The memory for the object itself will still be freed by the garbage collector eventually. If you’re like me, you love the elegance of C++, and looking at the code fragment above will make you feel gloomy and want to go back to unmanaged code where you can use the “resource acquisition is initialization” technique to release your resources deterministically and elegantly. Well don’t despair, because there is a solution: templates. Even though the CLR doesn’t support generics yet, you are still programming in C++, so there’s nothing stopping you from employing them to solve this problem. I wrote a template class called Using that can be employed to achieve the same affect as C#’s using statement (see Figure 5). The Using class is an unmanaged C++ class, so it is not controlled by the garbage collector and can be trusted to free your resources when it goes out of scope. It’s basically an unmanaged wrapper for any IDisposable-derived class, such as my Library class presented above. The Using class makes use of the gcroot class that ships with the .NET Framework SDK. gcroot is basically a smart pointer for managed pointers in unmanaged C++. gcroot does nothing more than wrap the managed pointer, but it can easily be extended to provide more interesting behavior as shown here. Many of the .NET Framework classes implement IDisposable too, so the Using class is a very handy class to have in your tool chest. When the Using object goes out of scope, it ensures that the object’s Dispose method gets called. This is kind of like deterministic finalization for managed objects! Now using the Library class becomes much simpler:

void UseLibrary()
{
    Using<Library*> library = new Library
        (S"C:\\Windows\\Explorer.exe",
         WindowsAPI::LOAD_LIBRARY_AS_DATAFILE);

    // Use library
}

And that’s the basics of resource management in .NET using C# and Managed C++.

So Where Are the Icons?

Now that you know how to load an unmanaged library, you need to determine whether a library contains any icons. As I mentioned before, you can use the LoadIcon function to load an icon from a library as long as you have the name or identifier for the icon resource. If you don’t know the name of a particular icon, you can enumerate all the icons until you find the one you want. This is done using the EnumResourceNames function, which is declared as follows in Kernel32.dll:

BOOL EnumResourceNames(HMODULE hModule,
                       PCTSTR pType,
                       ENUMRESNAMEPROC pCallback,
                       LONG_PTR lParam);

The hModule parameter is a module handle, which you can get by calling LoadLibraryEx, so I can use my Library class for this. The pType parameter identifies the type of resource. Although you can define your own resource types, you will generally use one of the standard resource types. Two resource types of interest in this discussion are RT_GROUP_ICON and RT_ICON. An RT_GROUP_ICON resource represents an icon. It is basically just a directory of icon images. Each directory entry refers to a RT_ICON resource, which contains the actual image data (see Figure 6). So to enumerate the icons in a library, you pass RT_GROUP_ICON as the type of resource to enumerate. The next parameter is the callback function, which is the traditional way of implementing an enumerator in C. You simply pass the address of a function to EnumResourceNames, and it will call that function for each matching resource. Simple. Well not really. The problem is that .NET has no notion of a function pointer. Fortunately, the .NET Framework has a thing called a delegate, which is much more powerful and can be used to implement callback functions, too. A delegate can refer to a static or instance method. You can’t pass EnumResourceNames a pointer to a function, but you certainly can pass it a delegate, assuming you declared the EnumResourceNames function appropriately and declared the matching delegate. Here’s how you would do that. This discussion assumes you’re using Managed C++ for everything. You could of course have simply #included Windows.h and used a callback function; however, using delegates provides benefits even for the C++ programmer.

__delegate bool EnumResNameProc(System::IntPtr hModule,
                                System::IntPtr pType,
                                System::IntPtr pName,
                                System::IntPtr param);

[DllImport("Kernel32.dll", SetLastError=true,
    CharSet=CharSet::Auto)]
static bool EnumResourceNames(System::IntPtr hModule,
                              System::IntPtr pType,
                              EnumResNameProc* enumFunc,
                              System::IntPtr param);

Since EnumResourceNames really operates on a library, I’ve added a method to my Library class that calls this import. This saves you from having to pass it a module handle every time. And of course this is the more object-oriented way to do it. Now enumerating the icon resources in a library becomes very easy (see Figure 7). At this point, you can call LoadIcon to get a handle to an icon tailored for the current display configuration. This can then be passed to the Icon::FromHandle method to get an Icon object, which in turn can be displayed in various ways in a .NET application. If you recall, one of my objectives for the Icon Browser application is to be able to save an icon to a .ICO file. To do this, I need to dig a little deeper and get at the actual resource data.

To get the resource data, you need to use the FindResource and LoadResource functions to locate and load the resource. This is different from calling LoadIcon, which generates a displayable icon based on the icon resource. Once the resource is loaded, you call the LockResource function to get a pointer to the actual resource bytes. This pointer is valid until such time as the library containing the resource is freed. I’ve declared structures to represent the resource data (see Figure 8). The __nogc keyword informs the compiler that these are unmanaged C++ structures. You won’t find these data structures defined in the Platform SDK documentation. It is worth noting that although this poses no challenges to C++, you will run into a number of issues if you try to do the same thing in C# or even Managed C++. What complicates matters, when trying to use them from C#, is that MEMICONDIR is actually a variable-length structure. The length of the arEntries array is defined by wCount. In other words, arEntries is an inline array as opposed to a pointer to the first element of an array. So to get to the various elements of the array, you need to perform a bit of pointer arithmetic. Although this is no problem to a seasoned C or C++ developer, it poses a challenge as C# does not encourage the use of pointers. In addition, managed structures cannot have inline arrays. So, if I had declared the C++ structures as managed structures, the compiler would have refused to compile them. If you are dealing with this problem, there is a solution. You do however need to explicitly mark code blocks as unsafe before you can make use of pointers in C#. This can be done using the C# unsafe keyword. Please bear in mind that it is called unsafe for a reason. Misuse of pointers often leads to very buggy code. This is why even in C++ the use of pointers is discouraged and should usually be localized to C++ classes employing the “resource acquisition is initialization” idiom. If you use any unsafe code in a .NET assembly, the entire assembly is marked as unsafe. Figure 9 contains a simple C# console application that demonstrates how to load the icon resource for the Microsoft Notepad application and how to use pointer arithmetic to access the last entry in the arEntries array. This code assumes you declared the managed structures in C# like this:

[StructLayout(LayoutKind.Sequential, Pack=2)]
public struct MEMICONDIR
{
    public ushort wReserved;
    public ushort wType;
    public ushort wCount;
    public MEMICONDIRENTRY arEntries; // inline array
}

Now that you know how to access these structures, lets take a closer look at them. Both MEMICONDIR and MEMICONDIRENTRY have been decorated in both the C# and C++ form. The C# structures have the StructLayout attribute applied to them. LayoutKind::Sequential is the single parameter to the StructLayoutAttribute instance constructor. It indicates that the members of the structure must be laid out sequentially in memory so as to be memory-compatible with unmanaged code. Otherwise, the CLR is free to move the object’s members around in memory for efficiency. The Pack field indicates the alignment of the members in memory. The Pack field defaults to 8, which is convenient as this is what Visual C++ 6 uses. And since most unmanaged structures you might encounter were probably declared and implemented using Visual C++ 6, it is a safe default. However the icon resource uses a Pack value of 2, which is why you need to declare it explicitly. This results in a slightly smaller memory footprint, as most of the structure members are two-byte words or smaller. To put this in perspective, the same affect is achieved in C++ using the pack pragma.

The MEMICONDIRENTRY structure contains information about an individual icon image. The wID member is of particular interest as it contains the resource identifier for the RT_ICON resource within the library that contains the actual image bitmap information. You can use this identifier with the FindResource and LoadResource functions to locate and load the RT_ICON resource. Then you can use the LockResource function to get at the bitmap information. Finally, you’ve found the images! The RT_ICON resource data is stored in memory similar to a DIB. So much so that you can use the BITMAPINFO structure, which defines a DIB in memory, to access the RT_ICON resource data. For more information about DIBs and the BITMAPINFO structure, consult the Platform SDK documentation. Technically the icon image uses the same format as the CF_DIB clipboard format where the DIB bits follow the BITMAPINFO header and color table. You will need to know this if you want to render the image yourself using the icon resource. For the purpose of this discussion, you can ignore this fact except to remember that the BITMAPINFO is yet another variable-length structure, and you must treat it accordingly. One thing to keep in mind is that icons deviate slightly from the BITMAPINFOHEADER semantics in that the biHeight member is double the actual height. Figure 6 illustrates how the RT_GROUP_ICON and RT_ICON resources are laid out in memory.

Next, I’ll show how you can wrap all this resource management code in a few well-defined classes to reduce this complexity.

Resource Management Revisited

I have written two classes: IconResource and IconImage. The IconResource class takes care of loading an RT_GROUP_ICON resource from a library and populates an array of IconImage objects. Each IconImage object represents an RT_ICON resource, which is a single image for the icon resource. As a user of the IconResource class is entitled to keep a reference to an IconResource object long after the library that it originated from has been freed, you need to be careful about the memory that gets returned by calls to LockResource. Although you don’t have to worry about releasing this memory (the operating system will ensure that it is freed once its parent library is unloaded from the process), you do need to concern yourself with any pointers to this memory that you may hold on to. The IconImage class needs to hold on to its resource data so that it can be used to write it to a .ICO file. I will talk more about this later. To satisfy this requirement, the IconImage class makes a local copy of the image bits. When the IconImage object is constructed, it loads the RT_ICON resource, which is just the DIB bits for the image. It then copies these image bits into a managed byte array using the Copy method on the Marshal class. Now that the IconImage class contains its own copy of the resource data, the library where the resource was originally retrieved from can be freed without affecting the IconImage class.

Let’s See What You’ve Got!

Icons aren’t much fun if you can’t see them. So let’s take a look at the Icon Browser’s MainWindow class and how it employs the classes that I’ve discussed so far to implement icon browsing. I first wrote the Icon Browser application in C#. For this article, I rewrote the entire application in Managed C++. The MainWindow class from the original C# version was generated using the Visual Studio Forms Designer. The C++ version I wrote completely by hand. You can judge for yourself which one is cleaner. The source code for both versions is available at <www.cuj.com/code>. Although I am generally weary of computer-generated code, the Visual Studio Forms Designer does a remarkable job of generating user-interface code. It is a huge boon to productivity if handled correctly. The trick is to be conscious of the code it generates and to maintain your coding and naming standards. For example, if you drag three text boxes onto a form, it will name them textBox1, textBox2, and textBox3. Be sure to give them meaningful names in the context of your application, as well as following any naming conventions you may be employing for your project. Further, for any non-trivial user-interface component, you need to employ standard design practices to ensure separation of data and presentation. This can be done using design patterns such as the Document/View pattern employed by MFC or the MVC (Model/View/Controller) pattern.

As shown in Figure 1, the Icon Browser is a simple forms-based application. It’s made up of a resizable window that contains a list view for displaying the icons, as well as a toolbar of sorts exposing the functionality supported by the Icon Browser application. The code of interest is in the GoEventHandler method, which is called in response to the Click event on the Go button. This brings everything you have learnt so far together. The GoEventHandler method uses the Library class to load the user-provided file. It then calls the Library class’ EnumResourceNames method to enumerate the RT_GROUP_ICON resources. AddIconToList is the delegate called by EnumResourceNames for each icon resource that is found. It uses the IconResource class to load the resource data and adds an IconItem to the ListView to represent the icon to the user. IconItem is a simple class that derives from ListViewItem that is used to initialize the ListViewItem text and image index.

Exporting Icons

There’s one more thing left to do. At the beginning of this article, I mentioned that the Icon Browser would allow the user to export any icon to a .ICO file. Unfortunately, the .ICO file format is different to the format used to store icons in resource files. Figure 10 illustrates how an icon is stored in a .ICO file. It somewhat resembles the memory layout of the RT_GROUP_ICON resource. So, with a little bit of translation code, you can convert the one to the other. The major difference with the way the .ICO file format is written is that the icon image directory entry for each image stores a byte offset to the location of the image, whereas the RT_GROUP_ICON resource stores the resource name that you use to load the image. For the purposes of writing a .ICO file, I have added a Save method to the IconResource class. This method takes a single string parameter that indicates the file to write the icon data to. It uses the BinaryWriter class to write the .ICO file header information. It then delegates to the IconImage class to write the directory entry information, as well as the image bits.

A Note about Managed and Unmanaged C++

Although I have focused this article on writing Managed C++ code, one of the great advantages of C++ over other languages targeted at the CLR is that in C++ you can freely mix managed and unmanaged code. On the other hand, using managed code entirely allows you to isolate yourself from third-party source code, such as header files that you must include, which may populate the global namespace with definitions that you are not interested in and do other nasty things to your code (such as, what happens when you include a Windows header and name a method of your own with a name that is used by a Win32 API function).

Conclusion

Reading and writing Win32 resources is a non-trivial exercise in C++. Being able to pull it off entirely in managed code displays some of the power and flexibility of the .NET Framework. Resource management code should always be written carefully. Using the .NET Framework’s IDisposable class lends a helping hand by providing a common pattern for resource management. I hope that this exercise of walking through the development of the Icon Browser application helped you understand some of the services provided by the .NET Framework for writing code to interoperate with unmanaged code and resources.

About the Author

Kenny Kerr specializes in component-based development of desktop and distributed applications for the Microsoft Windows platform. He works at PlateSpin, Inc. in Toronto, Canada where he heads up the Windows development. Reach Kenny at [email protected] or visit his website: <www.kennyandkarin.com/Kenny/>


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.