Simple Main Window Class

Here’s another fairly trivial code snippet. I’ve stumbled across some borked attempts at initializing and maintaining rendering windows for games lately. Most failed to properly respond to window messages, either ignoring WM_CLOSE outright or letting DefWindowProc() call DestroyWindow() when WM_CLOSE was received, thereby not giving the rest of the game’s code any time to cleanly shut down before the window handle becomes invalid.

So I’ll provide a clean and well-behaved window class here. It doesn’t use any global variables – in fact, you could create any number of windows from any number of threads. WM_CLOSE simply causes the class’ WasCloseRequested() method to return true, so by polling this method you can first shut down graphics and input devices and then destroy the window in an orderly fashion.

For your convenience I also added some helper methods: one resizes the window in a way that ensures the client area will actually end up with the exact pixel size requested. Another will center the window on the screen without messing up if the user has extended his desktop over multiple monitors.

Read More

How to Delete Directories Recursively with Win32

Well, while I’m at it, here’s the counterpart to the recursive directory creation function from my last post, a function that recursively deletes a directory and all its contents.

Ordinarily, you could just use the shell API to achieve this on classic Win32:

/// <summary>Deletes a directory and everything in it</summary>
/// <param name="path">Path of the directory that will be deleted</param>
void deleteDirectory(const std::wstring &path) {
  std::vector doubleNullTerminatedPath;
  std::copy(path.begin(), path.end(), std::back_inserter(doubleNullTerminatedPath));
  doubleNullTerminatedPath.push_back(L'\0');
  doubleNullTerminatedPath.push_back(L'\0');

  SHFILEOPSTRUCTW fileOperation;
  fileOperation.wFunc = FO_DELETE;
  fileOperation.pFrom = &doubleNullTerminatedPath[0];
  fileOperation.fFlags = FOF_NO_UI | FOF_NOCONFIRMATION;

  int result = ::SHFileOperationW(&fileOperation);
  if(result != 0) {
    throw std::runtime_error("Could not delete directory");
  }
}

But WinRT/Metro applications cannot use the shell API and have to do it manually. So here’s a piece of code that takes care of directory deletion using nothing but Win32 API calls that are also available to WinRT/Metro applications:

/// <summary>Automatically closes a search handle upon destruction</summary>
class SearchHandleScope {

  /// <summary>Initializes a new search handle closer</summary>
  /// <param name="searchHandle">Search handle that will be closed on destruction</param>
  public: SearchHandleScope(HANDLE searchHandle) :
    searchHandle(searchHandle) {}

  /// <summary>Closes the search handle</summary>
  public: ~SearchHandleScope() {
    ::FindClose(this->searchHandle);
  }

  /// <summary>Search handle that will be closed when the instance is destroyed</summary>
  private: HANDLE searchHandle;

};

/// <summary>Recursively deletes the specified directory and all its contents</summary>
/// <param name="path">Absolute path of the directory that will be deleted</param>
/// <remarks>
///   The path must not be terminated with a path separator.
/// </remarks>
void recursiveDeleteDirectory(const std::wstring &path) {
  static const std::wstring allFilesMask(L"\\*");

  WIN32_FIND_DATAW findData;

  // We'll iterate over the direct contents of the directory in any order
  std::wstring searchMask = path + allFilesMask;
  HANDLE searchHandle = ::FindFirstFileExW(
    searchMask.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, 0
  );
  if(searchHandle == INVALID_HANDLE_VALUE) {
    DWORD lastError = ::GetLastError();
    if(lastError != ERROR_FILE_NOT_FOUND) { // or ERROR_NO_MORE_FILES, ERROR_NOT_FOUND?
      throw std::runtime_error("Could not start directory enumeration");
    }
  }

  // Did this directory have any contents? If so, delete them
  if(searchHandle != INVALID_HANDLE_VALUE) {
    SearchHandleScope scope(searchHandle);
    for(;;) {

      // Do not process the obligatory '.' and '..' directories
      if(findData.cFileName[0] != '.') {
        bool isDirectory = 
          ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ||
          ((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0);

        // Subdirectories need to be handled by deleting their contents first
        std::wstring filePath = path + L'\\' + findData.cFileName;
        if(isDirectory) {
          recursiveDeleteDirectory(filePath);
        } else {
          BOOL result = ::DeleteFileW(filePath.c_str());
          if(result == FALSE) {
            throw std::runtime_error("Could not delete file");
          }
        }
      }

      // Advance to the next entry in the directory
      BOOL result = ::FindNextFileW(searchHandle, &findData);
      if(result == FALSE) {
        DWORD lastError = ::GetLastError();
        if(lastError != ERROR_NO_MORE_FILES) {
          throw std::runtime_error("Error enumerating directory");
        }
        break; // All directory contents enumerated and deleted
      }

    } // for
  }

  // The directory is empty, we can now safely remove it
  BOOL result = ::RemoveDirectoryW(path.c_str());
  if(result == FALSE) {
    throw std::runtime_error("Could not remove directory");
  }
}

This code is free for the taking and you can use it however you want.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

How to Create Directories Recursively with Win32

As I just found out, the CreateDirectory function on Win32 can only create one directory at a time. If one, for example, specifies C:\Users\All Users\FirstNew\SecondNew as the directory to create, and both FirstNew and SecondNew do not exist, then CreateDirectory() fails.

That’s less than ideal for some cases. Recently, for example, I wanted my game to create the C:\Users\<Whoever>\Documents\My Games\<GameName> directory, where both My Games and <GameName> may not yet exist. Here’s a workaround:

/// <summary>Creates all directories down to the specified path</summary>
/// <param name="directory">Directory that will be created recursively</param>
/// <remarks>
///   The provided directory must not be terminated with a path separator.
/// </remarks>
void createDirectoryRecursively(const std::wstring &directory) {
  static const std::wstring separators(L"\\/");

  // If the specified directory name doesn't exist, do our thing
  DWORD fileAttributes = ::GetFileAttributesW(directory.c_str());
  if(fileAttributes == INVALID_FILE_ATTRIBUTES) {

    // Recursively do it all again for the parent directory, if any
    std::size_t slashIndex = directory.find_last_of(separators);
    if(slashIndex != std::wstring::npos) {
      createDirectoryRecursively(directory.substr(0, slashIndex));
    }

    // Create the last directory on the path (the recursive calls will have taken
    // care of the parent directories by now)
    BOOL result = ::CreateDirectoryW(directory.c_str(), nullptr);
    if(result == FALSE) {
      throw std::runtime_error("Could not create directory");
    }

  } else { // Specified directory name already exists as a file or directory

    bool isDirectoryOrJunction =
      ((fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ||
      ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0);

    if(!isDirectoryOrJunction) {
      throw std::runtime_error(
        "Could not create directory because a file with the same name exists"
      );
    }

  }
}

This code is free for the taking and you can use it however you want.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Targeting Win32 and WinRT/Metro at the Same Time

I’ve seen some developers assume that if you write an App for WinRT/Metro, you have to write it exclusively in C++/CX, a variant of C++ with lots of Microsoft-specific extensions. In reality, you only really need C++/CX to interface with WinRT, but everything under that layer can be clean ISO C++! In this post I’ll explain how I’m designing my Ogre game to run inside Windows’ Metro UI while still supporting other platforms such as Win32, Android and iPhone on the same code base.

A good start is to look at what’s different between a normal desktop application and a Metro application and then develop a design concept where these differences are abstracted or wrapped so the core game code does not need to know about them.

Read More