On of the most important challenges nowadays in programming is concurrency. If we don’t learn to write programs that are able to run on multiple cores the progress in hardware will be pointless. But when you run multiple threads for various processing you might face the situation when you have to write over and over again same or similar code for creating the threads, setting up the parameters for the threads, joining the threads, checking the result, cleaning-up, etc.

In this post I will show how you can create some helpers in C++ to simplify this process. This is not going to be a full solution, neither a solution that fits all needs, but can be a start.

What I would like to have is a helper class that will take care of:

  • finding how many threads can run (considering each available core can run a thread)
  • creating and starting the threads
  • joining the threads
  • checking the result of the threads execution
  • cleaning up

The class show bellow does just that.

#include < windows.h >

class ThreadHelper
{
	LPVOID* m_Params;
	int m_ThreadsNo;

private:
	int GetProcessorsCount()
	{
		SYSTEM_INFO info;
		::GetSystemInfo(&info);
		return info.dwNumberOfProcessors;
	}

public:
	ThreadHelper()
	{
		m_ThreadsNo = GetProcessorsCount();

		m_Params = new LPVOID[m_ThreadsNo];
		for(int i = 0; i < m_ThreadsNo; ++i)
			m_Params[i] = NULL;
	}

	ThreadHelper(int threadsNo)
	{
		if(threadsNo < 1)
			m_ThreadsNo = GetProcessorsCount();
		else
			m_ThreadsNo = threadsNo;

		m_Params = new LPVOID[m_ThreadsNo];
		for(int i = 0; i < m_ThreadsNo; ++i)
			m_Params[i] = NULL;
	}

	~ThreadHelper()
	{
		delete [] m_Params;
	}

	int GetThreadsNo() const {return m_ThreadsNo;}
	bool SetThreadParams(int threadIndex, LPVOID lpData)
	{
		if(threadIndex >= 0 && threadIndex < m_ThreadsNo)
		{
			m_Params[threadIndex] = lpData;
			return true;
		}

		return false;
	}

	bool Run(LPTHREAD_START_ROUTINE threadProc, BOOL startImmediatelly, DWORD timeout = INFINITE)
	{
		bool success = false;

		HANDLE* hThreads = new HANDLE[m_ThreadsNo];
		DWORD* dwThreadIds = new DWORD[m_ThreadsNo];

		bool allThreadsOK = true;

		// create the threads
		for(int i = 0; i < m_ThreadsNo && allThreadsOK; ++i)
		{
			hThreads[i] = ::CreateThread(
				NULL,
				0,
				threadProc,
				m_Params[i],
				startImmediatelly ? 0 : CREATE_SUSPENDED,
				&dwThreadIds[i]);

			if(hThreads[i] == NULL)
			{
				for(int j = 0; j < i; ++j)
				{
					::CloseHandle(hThreads[j]);
				}

				allThreadsOK = false;
			}
		}

		if(allThreadsOK)
		{
			// start the threads if they were suspended first
			if(!startImmediatelly)
			{
				for(int i = 0; i < m_ThreadsNo; ++i)
				{
					::ResumeThread(hThreads[i]);
				}
			}

			// wait for all threads
			DWORD joinret = ::WaitForMultipleObjects(
				m_ThreadsNo,
				hThreads,
				TRUE,
				timeout);

			if(joinret == WAIT_FAILED)
			{

			}
			else if(joinret = WAIT_TIMEOUT)
			{

			}
			else if(joinret >= WAIT_OBJECT_0 && joinret < WAIT_OBJECT_0 + m_ThreadsNo)
			{
				success = true;
			}
			else if(joinret >= WAIT_ABANDONED_0 && joinret < WAIT_ABANDONED_0 + m_ThreadsNo)
			{

			}

			// close the thread handles
			for(int i = 0; i < m_ThreadsNo; ++i)
			{
				::CloseHandle(hThreads[i]);
			}
		}

		delete [] hThreads;
		delete [] dwThreadIds;

		return success;
	}
};

This helper class contains:

  • one parameter-less constructor that identifies the number of available processors and sets the threads count equal to the processors count
  • one constructor that takes the number of threads that should be created
  • one method (SetThreadParams) for setting the parameters for each thread that will be created
  • one method (Run) that creates and runs the thread, waits for them and checks the result of the execution

As you can see the Run() method is simplistic. It does not handle for instance timed out or abandoned thread executions. Also it joins all threads, waiting until all of them finished execution. A more flexible method could wait only until the first thread finishes and then maybe closes the other threads. But as I said, this is a sample and not a complete solution.

Having this helper set up, I will start several threads to find the prime numbers in a sequence and print them in the console.

The following function computes whether a number is prime/

#include < cmath >

bool IsPrime(int number)
{
	const int max = static_cast< int >(
		std::sqrt(static_cast< double >(number))) + 1;

	for (int i=2; i!=max; ++i)
	{
		if (number % i == 0) return false;
	}

	return true;
}

The thread procedure will run through a sub-sequence of a vector of integers and verify if each element is prime. I will use the following structure to pass the sequence bounds to the thread procedure:

struct vector_bounds
{
	std::vector< int >::const_iterator begin;
	std::vector< int >::const_iterator end;
};

The thread procedure could look like this:

static CRITICAL_SECTION cs;

DWORD WINAPI FindPrimes(LPVOID lpData)
{
	vector_bounds* bounds = static_cast< vector_bounds* >(lpData);
	if(bounds == NULL)
		return 1;

	for(std::vector< int >::const_iterator cit = bounds->begin;
		cit != bounds->end; ++cit)
	{
		if(IsPrime(*cit))
		{
			EnterCriticalSection(&cs);

			std::cout << *cit << std::endl;

			LeaveCriticalSection(&cs);
		}
	}

	return 0;
};

To print to the console a locking mechanism is necessary, otherwise prints from two different threads could collide. The critical section will be initialized before the threads are started.

What remains to be done is generating a sequence of integers, setting up the parameters with the sequence bounds for each thread and run the threads using the helper.

int main()
{
	// generate some random numbers
	srand((unsigned long)time(NULL));
	std::vector< int > numbers;
	std::generate_n(std::back_inserter(numbers), 1000, rand);

	// create the thread helper
	ThreadHelper helper(4);
	int threads = helper.GetThreadsNo();

	// create the parameters for the threads
	std::vector< vector_bounds > params;
	std::vector< int >::const_iterator begin = numbers.begin();
	size_t partitionsize = numbers.size()/threads;

	for(int i = 0; i < threads; ++i)
	{
		vector_bounds bound;
		bound.begin = begin;
		bound.end = (i == threads - 1) ? numbers.end() : begin + partitionsize;
		params.push_back(bound);

		begin = bound.end;
	}

	for(int i = 0; i < threads; ++i)
		helper.SetThreadParams(i, &params[i]);

	// run the threads
	InitializeCriticalSection(&cs);

	std::cout << "start running..." << std::endl;

	bool success = helper.Run(FindPrimes, FALSE);

	std::cout << "finished " << (success? "successfully" : "failed") << std::endl;

	DeleteCriticalSection(&cs);

	return 0;
}

Having this threads helper class, what I need to do when running some processing in several threads is:

  • setup thread parameters (if the case)
  • write the thread procedure
  • create a ThreadHelper object and initialize it
  • run the threads and collect the results

The helper class prevents writing same code over and over again and helps focusing on the most important tasks: writing the thread procedure. As I said earlier it is not a full solution, nor one that fits all scenarios, but you can develop it to suit your needs.

Hits for this post: 903 .

With VC++ Feature Pack Microsoft has added new classes to MFC to provide support for new controls. However, these controls were not available from the designer. One had to manually wrote all the code for enabling an application to use these controls. Visual Studio 2010 Beta 2, released a couple of weeks ago, provides support in the designer for these controls.

MFC controls in the Toolbar

MFC controls in the Toolbar

Here is a screen shot of a dialog application with these controls:

New MFC Controls

New MFC Controls

The controls are:

  • Color button (CMFCColorButton): represent a color picker control allowing users to select a color
  • Font combo box (CMFCFontComboBox) : represent a combo control that displays a list of fonts available in the system
  • Edit browse (CMFCEditBrowseCtrl): an editable control with a button that displays a dialog for selecting a file or a folder
  • Visual Studio list box (CVSListBox): an editable list control with buttons for adding, removing or rearranging items in the list
  • Masked edit (CMFCMaskedEdit): a masked edit control that has a string template representing the structure of the allowed input, which is validated against the value provided by the user
  • Menu button (CMFCMenuButton): displays a pop-up menu (from a menu resource) and reports the command selected by the user
  • Property grid (CMFCPropertyGridCtrl): an editable property grid control
  • Shell list (CMFCShellListCtrl): a list control that displays the files and folders from you system just list Windows Explorer list view does
  • Shell tree (CMFCShellTreeCtrl): a tree control that displays the folder from your system just like the Windows Explorer folder view does
  • Link control (CMFCLinkCtrl): is a special button that has the appearance of a hyperlink and invokes the target link when pressed

Not all the properties for these controls are available from the designer. For instance the properties list still needs hand coding, it is not possible to select a menu resource for the menu button nor the starting point for the shell tree and list. However, having them available in the toolbar is a good step forward.

, , , , Hits for this post: 5077 .

Sometimes you want to customize a file dialog, maybe to provide a preview for images or files in general. Fortunately, the common file dialog can be easily extended to achieve this. I will explain in this post how to do that.

There are several things one needs to do to extend the file dialog. First step is to create a dialog template. There are several properties (styles that have to be set on this template).

  • WS_CHILD, necessary because this dialog is a child of the original file dialog
  • WS_CLIPSIBLINGS, required so that the child dialog box does not paint over the original file dialog
  • DS_3DLOOK, so that consistency of the look of the controls in the child dialog and the original dialog is preserved
  • DS_CONTROL, allows the user to navigate through the controls of the customized dialog with TAB or navigation keys

When using the template, the following should be done for the OPENFILENAME structure:

  • if the template is a resource in an application or DLL library, then:
    • Flags should contain OFN_ENABLETEMPLATE
    • hInstance must point to the module containing the resource
    • lpTemplateName should contain the template name
  • if the template is already in memory then
    • Flags should contain OFN_ENABLETEMPLATEHANDLE
    • hInstance member must identify the memory object that contains the template

The following code shows how to display a customized file dialog with a template with the ID set to “DIALOG_PREVIEW”:

	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("All files (*.*)|*.*||"));

	fileDialog.m_ofn.Flags |= OFN_ENABLETEMPLATE;
	fileDialog.m_ofn.hInstance = AfxGetInstanceHandle();
	fileDialog.m_ofn.lpTemplateName = _T("DIALOG_PREVIEW");

	fileDialog.DoModal();

The common file dialog is expanded on the sides so that the new controls have enough space. There are several rules that apply to this repositioning. I will explain them and exemplify with some images.

  • By default all the controls from the custom dialog are placed below the controls from the original file dialog. The following images show a simple dialog template with a check box and a static control (for a preview). By default, these controls are placed at the bottom of the dialog.
    Simple dialog template

    Simple dialog template


    Custom dialog with preview controls placed at the bottom

    Custom dialog with preview controls placed at the bottom

  • If the dialog template contains a static control with the id stc32 (defined in DLG.h), the controls will be positioned relative to this control (with the original dialog being displayed in its placed, in the original size).
    • all controls above and to the left of stc32 are positioned above and to the left of the original controls, with the same amount.
      Template with stc32 control position on the right and middle

      Template with stc32 control position on the right and middle


      Custom File Fialog with Preview controls on the top left

      Custom File Fialog with Preview controls on the top left

    • all controls below and to the right of stc32 are positioned below and to the right of the original controls.
      Template with stc32 control position on the left and middle

      Template with stc32 control position on the left and middle


      Custom File Fialog with Preview controls on the top and on the right

      Custom File Fialog with Preview controls on the top and on the right

Base on that, if you want to place the preview controls on the right (as I would do), you’d have to place the stc32 control on the left of all the controls from your template. In other words, the template needs to look like this:

Template with stc32 on the left of all controls

Template with stc32 on the left of all controls

The resulting file dialog would look like this:

Custom File Dialog with Preview Controls on the right side

Custom File Dialog with Preview Controls on the right side

Note: In the above images the stc32 control had the border style set one one hand to make the control visible on the dialog template and on the other hand to have the the original file dialog controls more visible within the resulting file dialog. You wouldn’t do that with an actual file dialog.

As you could see from the sample code above, it’s very simple to extend the common file dialog. Of course, the part I haven’t shown so far is how to make use of these additional controls. But that is very simple. You just derive CFileDialog, add handlers for the new controls, implement all the logic you want, and instead of instantiating a CFileDialog object you instantiate an object of your derived class. In a following post I will explain how you can add preview functionality to such a custom file dialog.

You can read more about this topic in the following articles:

, , , , Hits for this post: 5388 .

Concepts were supposed to be an important new feature in C++0x. They were meant to allow programmers to specify properties (like constraints) for templates, allow compilers to do some optimization and tools to do some formal checking on the code. After years of debate, the standard committee found them “untried, risky and controversial” and ruled them out last month during their meeting in Frankfurt.

Danny Kalev, a former member of the C++ standard committee, wrote about this controversial removal, and later interviewed Bjarne Stroustrup about the concepts and the future of C++. You can read this interview, published on DevX.com, here.

You can find more about concepts in this paper by Bjarne Stroustrup.

, , , Hits for this post: 2965 .

.NET allows you to expose components as COM and consume them from unmanaged code. There are many references on how to this (and you can only start with MSDN), and I will not talk about that part. What I want to explain here is something different. Suppose you have this interface:

[Guid("2F8433FE-4771-4037-B6B2-ED5F6585ED04")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IAccounts
{
      [DispId(1)]
      string[] GetUsers();
}

Method GetUsers() returns an array on string representing the user names. But what if you also wanted the user passwords or addresses? Since this is exposed as COM, you cannot return an array of User. But you can return multiple arrays of string. So, how would you deal with out string[]? This is what I want to show you in this tutorial.

This is a .NET interface exposed to COM. It has two methods, GetUsers() that returns an array of string representing user names, and GetUsers2() that returns an array of strings as an output parameters and a bool as return type, indicating whether any user was found.

namespace SampleLibrary
{
   [Guid("2F8433FE-4771-4037-B6B2-ED5F6585ED04")]
   [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
   public interface IAccounts
   {
      [DispId(1)]
      string[] GetUsers();

      [DispId(2)]
      bool GetUsers2(out string [] users);
   }
}

And this is the implementation:

namespace SampleLibrary
{
   [Guid("C4713144-5D29-4c65-BF9C-188B1B7CD2B6")]
   [ClassInterface(ClassInterfaceType.None)]
   [ProgId("SampleLibrary.DataQuery")]
   public class Accounts : IAccounts
   {
      List< string > m_users;

      public Accounts()
      {
         m_users = new List< string > {
            "marius.bancila",
            "john.doe",
            "anna.kepler"
         };
      }

      #region IDataQuery Members

      public string[] GetUsers()
      {
         return m_users.ToArray();
      }

      public bool GetUsers2(out string[] users)
      {
         users = m_users.ToArray();

         return users.Length > 0;
      }

      #endregion
   }
}

Note: If you are trying this example make sure you set the ComVisible attribute to true, either for each type or per assembly (in AssemblyInfo.cs)

[assembly: ComVisible(true)]

Second, you have to check the “Register for COM interop” setting in the Build page of the project properties.

The first thing to do in C++ is importing the .TLB file that was generated by regasm.exe.

#import "SampleLibrary.tlb"
using namespace SampleLibrary;

If we look in the .TLB file, we can see how the IAccounts interface looks like:

struct __declspec(uuid("2f8433fe-4771-4037-b6b2-ed5f6585ed04"))
IAccounts : IDispatch
{
    //
    // Wrapper methods for error-handling
    //

    // Methods:
    SAFEARRAY * GetUsers ( );
    VARIANT_BOOL GetUsers2 (
        SAFEARRAY * * users );
};

The following C++ functions, GetUsers1() retrieves the users users list using method GetUsers() from IAccounts. It puts the users in a CStringArray (notice that this container does not have an assignment operator, so the only way to return such an array is with a reference in the parameters list).

void GetUsers1(CStringArray& arrUsers)
{
   IAccountsPtr pAccounts(__uuidof(Accounts));

   SAFEARRAY* sarrUsers = pAccounts->GetUsers();

   _variant_t varUsers;
   varUsers.parray = sarrUsers;
   varUsers.vt = VT_ARRAY | VT_BSTR;

   UnpackBstrArray(varUsers, arrUsers);
   SafeArrayDestroy(sarrUsers);

   pAccounts->Release();
}

UnpackBstrArray() is a function (see below) that extracts the elements of a SAFEARRAY and adds them to a CStringArray.

Function GetUsers2() uses the second method, GetUsers2() from IAccounts. This needs the address of a pointer to a SAFEARRAY (i.e. SAFEARRAY**) that will hold the values returned by the COM method. This time we have to create an empty SAFEARRAY and then pass its address to the COM method. The rest is similar to the previous case.

void GetUsers2(CStringArray& arrUsers)
{
   IAccountsPtr pAccounts(__uuidof(Accounts));

   SAFEARRAYBOUND aDim[1];
   aDim[0].lLbound = 0;
   aDim[0].cElements = 0;

   SAFEARRAY* sarrUsers = SafeArrayCreate(VT_BSTR, 1, aDim);

   VARIANT_BOOL ret = pAccounts->GetUsers2(&sarrUsers);
   if(ret != VARIANT_FALSE)
   {
      _variant_t varUsers;
      varUsers.parray = sarrUsers;
      varUsers.vt = VT_ARRAY | VT_BSTR;
      UnpackBstrArray(varUsers, arrUsers);
   }

   SafeArrayDestroy(sarrUsers);

   pAccounts->Release();
}

The helper method UnpackBstrArray() used previous looks like this:

void UnpackBstrArrayHelper(VARIANT* pvarArrayIn, CStringArray* pstrarrValues)
{
   if (!pstrarrValues || !pvarArrayIn || pvarArrayIn->vt == VT_EMPTY)
      return;

   pstrarrValues->RemoveAll();

   VARIANT* pvarArray = pvarArrayIn;
   SAFEARRAY* parrValues = NULL;

   SAFEARRAYBOUND arrayBounds[1];
   arrayBounds[0].lLbound = 0;
   arrayBounds[0].cElements = 0;

   if((pvarArray->vt & (VT_VARIANT|VT_BYREF|VT_ARRAY)) == (VT_VARIANT|VT_BYREF) &&
      NULL != pvarArray->pvarVal &&
      (pvarArray->pvarVal->vt & VT_ARRAY))
   {
      pvarArray = pvarArray->pvarVal;
   }

   if (pvarArray->vt & VT_ARRAY)
   {
      if (VT_BYREF & pvarArray->vt)
         parrValues = *pvarArray->pparray;
      else
         parrValues = pvarArray->parray;
   }
   else
      return;

   if (parrValues != NULL)
   {
      HRESULT hr = SafeArrayGetLBound(parrValues, 1, &arrayBounds[0].lLbound);
      hr = SafeArrayGetUBound(parrValues, 1, (long*)&arrayBounds[0].cElements);
      arrayBounds[0].cElements -= arrayBounds[0].lLbound;
      arrayBounds[0].cElements += 1;
   }

   if (arrayBounds[0].cElements > 0)
   {
      for (ULONG i = 0; i < arrayBounds[0].cElements; i++)
      {
         LONG lIndex = (LONG)i;
         CString strValue = _T("");

         VARTYPE vType;
         BSTR bstrItem;

         ::SafeArrayGetVartype(parrValues, &vType);
         HRESULT hr = ::SafeArrayGetElement(parrValues, &lIndex, &bstrItem);

         if(SUCCEEDED(hr))
         {
            switch(vType)
            {
            case VT_BSTR:
               strValue = (LPCTSTR)bstrItem;
               break;
            }

            ::SysFreeString(bstrItem);
         }

         pstrarrValues->Add(strValue);
      }
   }
}

void UnpackBstrArray( const _variant_t &var, CStringArray &strarrValues  )
{
   UnpackBstrArrayHelper( &(VARIANT)const_cast< _variant_t & >(var), &strarrValues );
}

Attached you can find a demo project (C# and C++) with the complete example show in this tutorial.

[download id="4"]

Hits for this post: 6982 .

Visual Studio 2010, currently in beta 1, replaces VCBuild with MSBuild as the build system, aligning C++ with the other languages that already used MSBuild. The VC++ team has already posted several articles on it’s blog about the new build system. Channel 9 has published recently a video with Bogdan Mihalcea, a developer in the VC++ build and system project team, talking about MSBuild. You can watch the video here.

, , , Hits for this post: 4250 .

It is often that I see people using namespace directives in header files. This is a bad practice maybe not enought explained, so I will try to clarify why one should always avoid this.

When you are using a using directive (such as using namespace std) or using declarations (such as using std::cout) you are bringing into the current namespace (either the global one or a named one) all the entities from the specified namespace (in the case of a using directive) or the entities specified with using declarations. Header files are meant to be included in sources files (usually more that just one source file) and the order of the include statements is most likely different.
If entities (types, functions, constants, etc.) with coliding names are brought into the same translation unit (source file) via different header files then the compiler will trigger errors due to ambiguities.

The following example will demonstrate this aspect. Suppose that you have an own list implementation in a file called mylist.h.

#pragma once 

namespace mycontainers
{
   class list
   {

   };
}

and you make use of this container in a class called foo, but in the header you are using a namespace directive to avoid writing the fully qualified name for list.

#pragma once
#include "mylist.h"

using namespace mycontainers;

class foo
{
   list mylist_;
};

However, a second class, called bar, is using the STL list, and also using a namespace directive.

#pragma once
#include < list >

using namespace std;

class bar
{
   list< int > mylist_;
};

All good as long as you use foo and bar separatelly. But the moment you need to include them both in the same source file (maybe directly, maybe via another headers) errors arise.

#include "foo.h"
#include "bar.h"

int main()
{
   foo f;

   return 0;
}

Here are the errors:

1>d:mariusvc++win32_testbar.h(9) : error C2872: 'list' : ambiguous symbol
1>        could be 'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'
1>        or       'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'
1>d:mariusvc++win32_testbar.h(9) : error C2872: 'list' : ambiguous symbol
1>        could be 'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'
1>        or       'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'

Of course, if you switch the order of #includes in you get another error:

1>d:mariusvc++win32_testfoo.h(8) : error C2872: 'list' : ambiguous symbol
1>        could be 'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'
1>        or       'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'

A second, more hard to spot error is explained by Sutter and Alexandrescu in C++ Coding Standards – 101 Rules, Guidelines, and Best Practices.
When you make use of a using declaration (using std::list), a snapshot of the used entity is taken. All later references to this entity are based on this snapshot. They provide the following example:

// sample 1
namespace A
{
   int f(double);
}

// sample 2
namespace B
{
   using A::f;
   void g();
}

// sample 3
namespace A
{
   int f(int);
}

// sample 4
void B::g()
{
   f(1);
}

When using A::f is encounted, a snapshot of A::f is taken from what was found so far. Only f(double) was declared already, f(int) is found only later.
So though this later overload was a better match for f(1) it would be ignored, because it wasn’t known at the time of the using declaration.

This issue complicates more if each of the first 3 samples were in different files. Then the order of the $include directives in the file that contains the 4th sample would dictate which overload of f() to be used.
And if sample 4 was itself in a header, other that the first 3, the order of the includes would become even more critical.

For these reasons, you should keep in mind never to use namespace directives or declarations in a header file. Instead use the fully qualified name for the types, functions, constants, etc. that you use, and leave the using directives for the source file exclusively.

, , , Hits for this post: 3836 .

I’ve found myself in situations when I spent lots of time debugging because of some variables declared in a base class were written in tens or maybe hundreds of places in the whole hierarchy, across one or multiple projects even. How could you find the right place where the value of such a variable changes? Well, not easy unless you make some changes to the code. In this article I’m going to show how to create a small wrapper to help you there.

But first, some rules of thumb:

  • Don’t make your variables public. This is pretty basic, but I’ve seen experienced people ignoring it; breaking it is a certain cause for maintenance problems.
  • When you have member variables in a base class that can potentially be assigned in many places across the hierarchy make it private, not protected, and provide Get/Set accessors to read and write it. Moreover, prefer to use this accessors in the base class too, instead of accessing it directly. This way you get only one entry point for reading/writing it, so spotting the places where the value changes will be trivial.

If you decide to go with the second rule that I mentioned I can bet you might be tempted to avoid the last advice and write it directly in the base class. Or if you won’t, one of your teammates will. To enforce that, you can use a wrapper class like the one show below.

template < typename T >
class ExplicitWriteVariable
{
	T value_;

	// do not allow assigning values
	T& operator=(const T& val);

public:
	ExplicitWriteVariable()
	{
	}

	explicit ExplicitWriteVariable(const T& val): value_(val)
	{
	}

	bool operator==(const ExplicitWriteVariable< T >& rhv)
	{
		return value_ == rhv.value_;
	}

	bool operator!=(const ExplicitWriteVariable< T >& rhv)
	{
		return value_ != rhv.value_;
	}

	bool operator==(const T& rhv)
	{
		return value_ == rhv;
	}

	bool operator!=(const T& rhv)
	{
		return value_ != rhv;
	}

	// allow assignment of the wrapper objects, and use Set for modifying the wrapper value
	ExplicitWriteVariable< T >& operator=(const ExplicitWriteVariable< T >& rhv)
	{
		if(this != &rhv)
		{
			Set(rhv.value_);
		}
		return *this;
	}

	// operator T is used for getting the wrapped value
	operator T () const
	{
		return value_;
	}

	// this is the only entry point for setting the value of the variable
	void Set(const T& val)
	{
		value_ = val;
	}
};

This template class has the following characteristics:

  • provides a default constructor and an explicit constructor
  • the assignment operator is made private and not implemented, which means you cannot use an object of this type on the left side of an assignment
  • provides the operator T() which allows to read the value without needing an explicit Get accessor
  • provides a Set accessor for changing the wrapper value; this is the only possible entry point for writing
  • has some comparison operators

If you use this to wrap variables in a base class you don’t make it private, but protected in the base class, otherwise you’ll have to provide get/set accessors for the ExplicitWriteVariable object itself. The lacking of operator= will force you though to use the Set() method explicitly.

Here are some samples for using the class:

void Print(int val)
{
	std::cout << val << std::endl;
}

int main()
{
	ExplicitWriteVariable< int > val(10);

	Print(val);
	if(val % 10 == 0) std::cout << "multiple of 10" << std::endl;

	val.Set(43);

	Print(val);
	if(val % 2 == 1) std::cout << "odd number" << std::endl;

	return 0;
}
10
multiple of 10
43
odd number

The following produces an error:

ExplicitWriteVariable< int > val(10);
val = 43; // error C2248

, , , Hits for this post: 2988 .

The new MFC library from Visual Studo 2010 supports another Vista specific feature, the task dialog. This is meant as a replacement for the classic dialog box, and can display command links, customized buttons, customized icons, and a footer.

Here is an example of such a dialog (from Windows Server 2008).

MFC contains a new class called CTaskDialog that implements the task dialog. You must include afxtaskdialog.h in your files to be able to use it. Since the task dialog is available only on Vista or newer versions (Server 2003, Server 2008, Windows 7) you must check whether you can use it or not. For that the class CTaskDialog provides a static method called IsSupported() that returns true if the task dialog is available on the running operating system. In addition, the task dialog is only available when you build for UNICODE.

The code below shows how to create and display the task dialog from the previous image.

void CTasksDemoDlg::OnBnClickedButtonTasks1()
{
   CString strMessage("Do you want to save your changes to the document?");
   CString strDialogTitle("Save document");
   CString strMainInstruction("Save document options");

   CString expandedLabel("Hide extra information");
   CString collapsedLabel("Show extra information");
   CString expansionInfo("You can select to save your document either as XML or binary. You should prefer to save as XML as this is the new standard format.");

   if (CTaskDialog::IsSupported())
   {
      CTaskDialog taskDialog(strMessage, strMainInstruction, strDialogTitle, TDCBF_OK_BUTTON);
      taskDialog.SetMainIcon(TD_INFORMATION_ICON);

      taskDialog.SetCommonButtons(TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON);
      taskDialog.LoadCommandControls(IDS_SAVE_OPTION1, IDS_SAVE_OPTION2);
      taskDialog.SetExpansionArea(expansionInfo, collapsedLabel, expandedLabel);
      taskDialog.SetFooterText(L"Note: If you don't chose to save your changes will be lost.");
      taskDialog.SetVerificationCheckboxText(L"Remember your selection");

      INT_PTR result = taskDialog.DoModal();

      if (taskDialog.GetVerificationCheckboxState() )
      {
         // PROCESS IF the user selects the verification checkbox
      }

      switch (result)
      {
         case IDS_SAVE_OPTION1:
            AfxMessageBox(L"You chose to save as XML");
            break;
         case IDS_SAVE_OPTION2:
            AfxMessageBox(L"You chose to save as binary");
            break;
         case IDNO:
            AfxMessageBox(L"You chose not to save");
            break;
         case IDCANCEL:
            AfxMessageBox(L"You chose to cancel");
            break;
         default:
            // this case should not be hit
            ASSERT(FALSE);
            break;
      }

   }
   else
   {
      AfxMessageBox(strMessage);
   }
}

In this sample IDS_SAVE_OPTION1 (“Save in XML based format”) and IDS_SAVE_OPTION2 (“Save in binary format (old version)”) are two strings defined in the string table from the Resource editor.

There are several predefined icons in commctrl.h that can be used as the main icon.

#define TD_WARNING_ICON         MAKEINTRESOURCEW(-1)
#define TD_ERROR_ICON           MAKEINTRESOURCEW(-2)
#define TD_INFORMATION_ICON     MAKEINTRESOURCEW(-3)
#define TD_SHIELD_ICON          MAKEINTRESOURCEW(-4)

The following flags for default buttons are defined in the same header:

enum _TASKDIALOG_COMMON_BUTTON_FLAGS
{
    TDCBF_OK_BUTTON            = 0x0001, // selected control return value IDOK
    TDCBF_YES_BUTTON           = 0x0002, // selected control return value IDYES
    TDCBF_NO_BUTTON            = 0x0004, // selected control return value IDNO
    TDCBF_CANCEL_BUTTON        = 0x0008, // selected control return value IDCANCEL
    TDCBF_RETRY_BUTTON         = 0x0010, // selected control return value IDRETRY
    TDCBF_CLOSE_BUTTON         = 0x0020  // selected control return value IDCLOSE
};
typedef int TASKDIALOG_COMMON_BUTTON_FLAGS;

An easier way to create a task dialog, but with fewer customization options is using the static method ShowDialog() from CTaskDialog. The following example displays a dialog similar to the first one.

void CTasksDemoDlg::OnBnClickedButtonTasks2()
{
   HRESULT result2 = CTaskDialog::ShowDialog(
      L"Do you want to save your changes to the document?",
      L"Save document options",
      L"Save document",
      IDS_SAVE_OPTION1,
      IDS_SAVE_OPTION2,
      TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON,
      TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS,
      L"Note: If you don't chose to save your changes will be lost.");
}

, , Hits for this post: 10133 .

One of the new features available in MFC in the Visual Studio 2010 CTP is the Restart Manager. This was introduced with Windows Vista to offer support for restarting application when a crash occurs or when an automatic update needs to close and then restart an application.

When you create a new MFC project in Visual Studio 2010, in the Advanced Features property page you can specify the level of support you want for the restart manager.

You can select one of the following:

  • Support Restart Manager: restarts after crash or upgrade
  • Reopen previously open documents: reopens previously open documents
  • Support application recovery: recovers auto saved documents

There are three flags defined for these three options:

  • AFX_RESTART_MANAGER_SUPPORT_RESTART for Support Restart Manager
  • AFX_RESTART_MANAGER_SUPPORT_RESTART_ASPECTS for Reopen previously open documents
  • AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS for Support application recovery

These are defined in the afxwin.h header.

// Restart Manager support flags
#define AFX_RESTART_MANAGER_SUPPORT_RESTART           0x01  // restart support, means application is registered via RegisterApplicationRestart
#define AFX_RESTART_MANAGER_SUPPORT_RECOVERY          0x02  // recovery support, means application is registered via RegisterApplicationRecoveryCallback
#define AFX_RESTART_MANAGER_AUTOSAVE_AT_RESTART       0x04  // auto-save support is enabled, documents will be autosaved at restart by restart manager
#define AFX_RESTART_MANAGER_AUTOSAVE_AT_INTERVAL      0x08  // auto-save support is enabled, documents will be autosaved periodically for crash recovery
#define AFX_RESTART_MANAGER_REOPEN_PREVIOUS_FILES     0x10  // reopen of previously opened documents is enabled, on restart all previous documents will be opened
#define AFX_RESTART_MANAGER_RESTORE_AUTOSAVED_FILES   0x20  // restoration of auto-saved documents is enabled, on restart user will be prompted to open auto-saved documents intead of last saved
#define AFX_RESTART_MANAGER_SUPPORT_NO_AUTOSAVE       AFX_RESTART_MANAGER_SUPPORT_RESTART |
                                                      AFX_RESTART_MANAGER_SUPPORT_RECOVERY |
                                                      AFX_RESTART_MANAGER_REOPEN_PREVIOUS_FILES
#define AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS       AFX_RESTART_MANAGER_SUPPORT_NO_AUTOSAVE |
                                                      AFX_RESTART_MANAGER_AUTOSAVE_AT_RESTART |
                                                      AFX_RESTART_MANAGER_AUTOSAVE_AT_INTERVAL |
                                                      AFX_RESTART_MANAGER_RESTORE_AUTOSAVED_FILES
#define AFX_RESTART_MANAGER_SUPPORT_RESTART_ASPECTS   AFX_RESTART_MANAGER_SUPPORT_RESTART |
                                                      AFX_RESTART_MANAGER_AUTOSAVE_AT_RESTART |
                                                      AFX_RESTART_MANAGER_REOPEN_PREVIOUS_FILES |
                                                      AFX_RESTART_MANAGER_RESTORE_AUTOSAVED_FILES
#define AFX_RESTART_MANAGER_SUPPORT_RECOVERY_ASPECTS  AFX_RESTART_MANAGER_SUPPORT_RECOVERY |
                                                      AFX_RESTART_MANAGER_AUTOSAVE_AT_INTERVAL |
                                                      AFX_RESTART_MANAGER_REOPEN_PREVIOUS_FILES |
                                                      AFX_RESTART_MANAGER_RESTORE_AUTOSAVED_FILES

Enabling this support is done with a single line in the constructor of the CWinAppEx derived class.

CRecoveryDemoApp::CRecoveryDemoApp()
{
	m_bHiColorIcons = TRUE;

	// support Restart Manager
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;

	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

Here is an application with the full support for restart enabled. There are two opened documents, one that is saved (on the left) and one that is not saved (on the right).

When I hit the crash button, the application uses a null pointer and crashes.

Now, when I press the Ignore button of the crash report window, I get the restart manager window tha allows me to Restart the program.

The restart manager will attempt to restart the program and reopen my documents, which it successfully does.

However, you can see that though the support for recovering auto saved documents was enabled, the second, unsaved document was not recovered. The reason was that this document was not auto saved, because the default interval for the auto save is 5 minutes and I crashed the program immediatelly after writing into the document. This default interval can be changed by calling the SetAutosaveInterval() method of the data recovery handler. In the following example I change this interval to one minute.

BOOL CRecoveryDemoApp::InitInstance()
{
   // ...

   CDataRecoveryHandler* autohandler = AfxGetApp()->GetDataRecoveryHandler();
   autohandler->SetAutosaveInterval(60000);

   return TRUE;
}

Here is another instance of the application with the first document saved, and the second not directly saved, but auto saved after one minute of inactivity.

When the application restarts, because there was an auto saved document that can be recovered, a new window is displayed.

If I choose Recover the auto-saved documents my unsaved (but auto saved) document is recovered.

These options for restarting the application and saving and loading the application data (documents) are exposed through virtual methods in the CWinAppEx class.

virtual void PreLoadState() {}    // called before anything is loaded
virtual void LoadCustomState() {} // called after everything is loaded
virtual void PreSaveState() {}    // called before anything is saved
virtual void SaveCustomState() {} // called after everything is saved

You can override these methods in your application for custom handling of the save and load operations.

To learn more about this new feature I suggest you read the Visual C++ team’s blog.

, , Hits for this post: 8840 .