The curious behavior of CFileDialog::GetFolderPath function

In most of the implementations to get the folder path of the selected file from a file dialog, people tend implement their own implementation to find the last “\” character and trim the string. CFileDialog::GetFolderPath in fact it exposes the very same functionality but it shows different behavior across platform and MFC libraries.

The typical usage of a file dialog would be as follows

CFileDialog f (true);
if( IDOK == f.DoModal())
{
   CString str = f.GetFolderPath();
}

If you compile this code with Visual Studio 2008 and above the code will succeeds and give you the folder of the filename selected by the user. But if you compile the code with MFC version 8.0 (VS 2005) or the prior version the code you will eventually you will reach in exception.
On stepping in to the code, you can see the following code with the MFC 8.0 implementation.

CString strResult;

ASSERT(::IsWindow(m_hWnd));
ASSERT(m_ofn.Flags & OFN_EXPLORER);

if (GetParent()->SendMessage(CDM_GETFOLDERPATH, (WPARAM)MAX_PATH, (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
	strResult.Empty();
else
	strResult.ReleaseBuffer();
return strResult;

The internal implementation uses the typical window messaging system. The return of the message points to the string buffer which will be copied to the CString object and will be returned.
Though GetFolderPath can’t be used in a typical scenario, it can be used when you’ve your own implementation of the CFileDialog. You can use them in the internal callbacks and own implementations of override-able function as long as the window is being displayed.
E.g. see an implementation in a class derived from CFileDialog. Here the window is active. The call CFileDialog::OnOK will destroy the window object in the end.

void MyFileDialog::OnOK()
{
	CString str = GetFolderPath();

	// Do something like some validation
	MessageBox( str );
	CFileDialog::OnOK();
}

Changes in Windows Vista

In Windows Vista and above there are there several new shell interfaces introduced with extended functionality. The new changes in the file dialog and the Windows shell are incorporated in the new IFileDialog implementation. These interfaces are nothing but lightweight COM object and not part of MFC library. To provide the backward compatibility while exploiting the new features in the platform, Microsoft has changed the MFC implementation of CFileDialog with the help of using IFileDialog interface.
The constructor of the new CFileDialog now takes a new (default) parameter in the end called bVistaStyle. Inside the constructor of CFileDialog, the m_bVistaStyle parameter is set with this input parameter and the whole implementation of CFileDialog is implemented with condition checks. If it’s Vista Style File dialog, IFileDialog interface will be used throughout the life of the object.

See the description from MSDN

Both the appearance and the functionality of the CFileDialog with Windows Vista differ from the earlier versions of Windows. The default CFileDialog automatically uses the new Windows Vista style without code changes if a program is compiled and run under Windows Vista. Use the bVistaStyle parameter in the constructor to manually override this automatic update.

Obviously the old Open and Save file dialog API based implementations are remained intact and wrapped around with m_bVistaStyle condition check. You can find the implementation in the dlgfile.cpp (located underVC\atlmfc\src\mfc ).

Visual Studio 2008 (MFC 9.0) library has incorporated the above mentioned changes and behave properly.

For instance you can clearly see the code for GetFolderPath with the latest version of MFC library here. You can clearly see it uses m_pIFileDialog member of the class being used to get the folder path. The previous implementation is wrapped in the else case.

CString CFileDialog::GetFolderPath() const
{
	CString strResult;
	if (m_bVistaStyle == TRUE)
	{
		IShellItem *psiResult;
		HRESULT hr = (static_cast(m_pIFileDialog))->GetFolder(&psiResult);
		if (SUCCEEDED(hr))
		{
			LPWSTR wcFolderPath = NULL;
			hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &wcFolderPath);
			if (SUCCEEDED(hr))
			{
				strResult = wcFolderPath;
				CoTaskMemFree(wcFolderPath);
			}
			psiResult->Release();
		}
	}
	else
	{
		ASSERT(::IsWindow(m_hWnd));
		ASSERT(m_ofn.Flags & OFN_EXPLORER);

		if (GetParent()->SendMessage(CDM_GETFOLDERPATH, (WPARAM)MAX_PATH, (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
			strResult.Empty();
		else
			strResult.ReleaseBuffer();
	}
	return strResult;
}

Conclusion

You can make use of this call if you’re using Visual Studio 2008 (MFC 9.0) and above, you’re passing bVistaStyle as true in the constructor and the platform is Windows Vista and above. Also If it’s not required to provide backward compatibility, you can make use of IFileDialog interface than using CFileDialog class.

Links

CFileDialog::GetFolderPath
IFileDialog interface

C++: Erase-Remove Idiom

Erase-remove idiom is a common technique to eliminate the elements from a C++ STL container which satisfies a particular condition.

We can do the hand written loop to remove the elements from the container. For e.g. if you want to remove an element vector you can do something as below. (note erasing element from a C++ container within a standard for or while loop with simple iterator++ will end up undefined result)

vector::iterator it = vec.begin();
while(it != vec.end())
     if( *it == 5 )
         it = vec.erase(it); // Remove and take the return of the erase function to safely reassign
     else
         ++it;

The above code is simple as it appears, it simply iterate through the elements and find if a match there for the value then remove it from the container. And it takes back the value returned form erase where it returns the iterator of the next element. If no more elements, it will vector::end

Now, the containers will have different implementations for the same function. A map::erase return void. So it’s difficult to give a single and easy strategy for each type of containers.

remove is a handy function defined in algorthm It’s easy to get confused to know what it does and distinguish between erase. remove remove (move) the elements from the given range. Mostly push it towards the end of the container. The function returns an iterator to the location where the moved elements located within the container. It essentially won’t remove the elements as such from the container. Here is the sample demo of using remove

// remove algorithm example
#include 
using namespace std;

int main ()
{
  int data[] = {10,20,30,30,20,10,10,20};      // 10 20 30 30 20 10 10 20

  // bounds of range:
  int* pbegin = data;                          // ^
  int* pend = data+sizeof(data)/sizeof(int);   // ^                       ^

  pend = remove (pbegin, pend, 20); // 10 30 30 10 10 ?  ?  ?
                                    // ^              ^

  return 0;
}

Now this handy function has an alternative version to give a comparator function which can accept the object of the type specified for the container. Inside the function, you can make decision to remove or not by specifying in the return value. In simple words, rather giving a comparison hard coded value, we’ll give a function to make decision for us. See the documentation and example here.

Erase-Remove tequenique is accomplished in following ways.
1. Move the elements to be removed to the end with the help of remove function
2. Take the return of remove and pass to the erase function as beginning and containers::end as end.
3. Finally the contianer will contains the elements which are not satisfying the comparator function/value.

#include  // the general-purpose vector container
#include  // remove and remove_if

bool is_odd(int i) { // unary predicate returning true if and only if the argument is odd
  return i % 2;
}
bool is_even(int i) { // unary predicate returning true if and only if the argument is even
  return !is_odd(i);
}

int main() {
  using namespace std;
  int elements[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  // create a vector that holds the numbers from 0-9.
  vector v(elements, elements + 10); 

  // use the erase-remove idiom to remove all elements with the value 5
  v.erase(remove(v.begin(), v.end(), 5), v.end()); 

  // use the erase-remove idiom to remove all odd numbers
  v.erase( remove_if(v.begin(), v.end(), is_odd), v.end() );

  // use the erase-remove idiom to remove all even numbers
  v.erase( remove_if(v.begin(), v.end(), is_even), v.end() );
}

Reference:
Erase-remove idiom

C++: Why new to be used only when unavoidable?

Those who program with modern languages like C# or Java has a tendency to use each and every object declaration in C++ with new. Why we should avoid using new as much as possible?

  • Unlike Java/C#, C++ doesn’t employ any memory manager by its own to control the life time of dynamically allocated objects (using new).
  • C++ using operating system routines to allocate the memory and too much new/delete could fragment the available memory. The architecture and management of a garbage collector is entirely different from a native perspective.
  • Improper memory management could lead memory leaks and it’s really hard to track.
  • The stack objects implementation is foolproof.
  • With any application, if large chunk of memory is frequently being used, it’s advised to pre-allocate it and release when not required.
  • The downside of using stack objects are, it creates intermediate copies of objects on returning, passing to functions (by value) etc. But the memory management of C#/Java helps the (JIT)compiler to manage these tasks memory efficient. However modern C++ compilers are well aware of these situations and they’ve optimized for performance.
  • It’s really tedious in C++ if the memory being allocated and released in two different places. The responsibility for release is always a question and mostly we rely on some commonly accessible pointers, stack objects (maximum possible) and techniques like auto_ptr, shared_ptr (reference counted pointers – C++0x) (RAII objects)
  • The best thing in C++ is that, you’ve control over the memory and the worst thing is that you will not have any control over the memory if we employ an improper memory management for the application. The crashes caused due to memory corruptions are the nastiest one in the world.
In C++, the STL containers mostly rely on dynamically memory. In a way or other, they’re RAII objects, which automatically releases the resources upon destruction. In addition to that, it eases the programmers life by providing useful interfaces (services) to make best of OOP, (like operator+= with string objects, push_back function with containers, easy copying of containers by assignment etc.). It’s a good practice to make best use of the proven library classes/functions/algorithms to make your program work efficient. Also operating system memory routines are costly to handle. Hence there will be  a performance hit on using dynamic memory allocation.
Of course we can’t say a stack object is completely allocated in stack to improve the performance. Consider the example of std::string class which holds the actual string content in the heap memory but the advantage is that, the memory is automatically managed on reassigning, concatenation, destruction etc.
But there are situations where we’ve to use the dynamic memory allocations like reading  bytes from files where we don’t know the size of the buffer which we required to pass the read function. In such situations, either we’ve to use the dynamic memory and handle the it our self or, use the proven classes like ofstream/ifstream etc with required objects (like std::string) to read the content and thus let them manage the memory automatically.
See further on my answer in StackOverflow.com

Proudly powered by WordPress
Theme: Esquire by Matthew Buchanan.