Common Dialogs

Windows provides a set of built-in dialog boxes (often referred to as "Common Dialogs") that handle frequently used functionality such as opening and saving files, selecting folders, picking colors, etc. These dialogs typically require you to fill out and pass a corresponding structure, which they then use to display a standardized UI and return relevant data. This page will cover some of the dialogs used commonly in gamedev.

Each dialog has its own function, structure, and flags, but they all follow a similar pattern: create and populate the structure, call the function, and handle the user's input (or canceled operation). Let's take a look at these in action.

Open File

The Open File Dialog allows users to select a file to open. Internally, this is implemented using the GetOpenFileNameA function from the Windows Common Dialog Box Library. You fill out an OPENFILENAMEA structure, specifying filters, default paths, flags (like requiring the file to exist), and a buffer to store the result.

In the following example, the OPENFILENAMEA structure stores the user's file choice in the fileName buffer. If the user cancels the operation, GetOpenFileNameA returns FALSE.

#include <windows.h>
#include <commdlg.h>
#include <stdio.h>

void main() {
    char fileName[MAX_PATH] = "";
    OPENFILENAMEA ofn = { 0 };

    ofn.lStructSize = sizeof(OPENFILENAMEA);
    ofn.hwndOwner = NULL;
    ofn.lpstrFilter = "Text Files\0*.txt\0All Files\0*.*\0";
    ofn.lpstrFile = fileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;

    if (GetOpenFileNameA(&ofn)) {
        printf("Selected file: %s\n", fileName);
    }
    else {
        printf("No file selected.\n");
    }
}

Save File

The Save File Dialog is similar, but uses GetSaveFileNameA. This dialog is typically used to prompt the user for a location and file name where you can save data. You can provide different flags such as OFN_OVERWRITEPROMPT to warn users if they're about to overwrite an existing file.

#include <windows.h>
#include <commdlg.h>
#include <stdio.h>

void main() {
    char fileName[MAX_PATH] = "";
    OPENFILENAMEA ofn = { 0 };

    ofn.lStructSize = sizeof(OPENFILENAMEA);
    ofn.hwndOwner = NULL;
    ofn.lpstrFilter = "Text Files\0*.txt\0All Files\0*.*\0";
    ofn.lpstrFile = fileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_OVERWRITEPROMPT;

    if (GetSaveFileNameA(&ofn)) {
        printf("File to save: %s\n", fileName);
    }
    else {
        printf("Save operation canceled.\n");
    }
}

Open Folder

The Open Folder Dialog helps users pick a directory rather than a file. Older code often uses SHBrowseForFolderA for this. You fill out the BROWSEINFOA structure, which describes the dialog's title and flags. When the user hits OK, SHBrowseForFolderA returns an item id list LPITEMIDLIST that references the chosen folder. That needs to be converted it into a normal file path using SHGetPathFromIDListA.

#include 
#include 
#include 

void main() {
    char folderPath[MAX_PATH] = "";
    BROWSEINFOA bi = { 0 };
    bi.lpszTitle = "Select a folder:";
    bi.ulFlags = BIF_RETURNONLYFSDIRS;

    LPITEMIDLIST pidl = SHBrowseForFolderA(&bi);
    if (pidl) {
        SHGetPathFromIDListA(pidl, folderPath);
        printf("Selected folder: %s\n", folderPath);
        CoTaskMemFree(pidl);
    }
    else {
        printf("No folder selected.\n");
    }
}

SHBrowseForFolderA can feel a bit dated. In newer applications, you might consider modern shell APIs, but this approach still works in many Win32 tools and games.

Color Picker

For selecting a color, Win32 provides the ChooseColorA dialog. You prepare a CHOOSECOLORA structure, supply an optional array for custom colors, then call ChooseColorA. The user can pick a color, or cancel.

#include <windows.h>
#include <commdlg.h>
#include <stdio.h>

void main() {
    CHOOSECOLORA cc = { 0 };
    COLORREF acrCustClr[16] = { 0 };
    cc.lStructSize = sizeof(CHOOSECOLORA);
    cc.hwndOwner = NULL;
    cc.lpCustColors = acrCustClr;
    cc.Flags = CC_FULLOPEN | CC_RGBINIT;

    if (ChooseColorA(&cc)) {
        printf("Selected color: 0x%06X\n", cc.rgbResult);
    }
    else {
        printf("Color selection canceled.\n");
    }
}

Here, cc.rgbResult will hold the RGB color chosen by the user, and acrCustClr stores 16 custom colors that the user can adjust in the UI.