Skip to main content

Command Palette

Search for a command to run...

Win32 API programming with C - Using the file system

Updated
5 min read
C

I am a .NET Developer and Consultant with over 15 years of experience, I specialize in crafting scalable, high-performance applications that drive business growth and innovation.

When we looked at common controls library we added an Edit control. Let's say we want to save the text that we write to a file on disk, for this we need to use the File System API.

First, we need a method to open the File Save dialog:

void OpenFileSaveDialog(HWND hwnd)
{
    OPENFILENAME ofn;
    char szFileName[MAX_PATH] = "";

    ZeroMemory(&ofn, sizeof(ofn));

    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = "txt";
    ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;

    if (GetSaveFileName(&ofn))
    {
        HWND hEdit = GetDlgItem(hwnd, IDC_MY_EDIT);
        SaveTextFile(hEdit, szFileName);
    }
}

The SaveTextFile method reads the text inside the Edit control and creates a .txt file on disk. The CreateFile function can create a new file or open an existing file. You must specify the file name, creation instructions, and other attributes. When an application creates a new file, the operating system adds it to the specified directory.

The following example uses CreateFile to create a new file and open it for writing and WriteFile to write the content of the Edit control to the file.

BOOL SaveTextFile(HWND hEdit, LPCTSTR pszFileName)
{
    HANDLE hFile;
    BOOL bSuccess = FALSE;

    hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        DWORD dwTextLength;

        dwTextLength = GetWindowTextLength(hEdit);
        if (dwTextLength > 0)
        {
            LPSTR pszText;
            DWORD dwBufferSize = dwTextLength + 1;

            pszText = (LPSTR)GlobalAlloc(GPTR, dwBufferSize);
            if (pszText != NULL)
            {
                if (GetWindowText(hEdit, pszText, dwBufferSize))
                {
                    DWORD dwWritten;

                    if (WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
                        bSuccess = TRUE;
                }
                GlobalFree(pszText);
            }
        }
        CloseHandle(hFile);
    }
    return bSuccess;
}

Full code below:

#include <windows.h>
#include <commctrl.h>
#include "resource.h"

#pragma comment (lib, "comctl32")

// global variables
const char g_szClassName[] = "myWindowClass";

#define IDC_MY_EDIT        103
#define ID_MYBUTTON        104

// function declarations
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL SaveTextFile(HWND hEdit, LPCTSTR pszFileName);
void OpenFileSaveDialog(HWND hwnd);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG msg;

    //Step 1: Register the Window Class
    wc.cbSize         = sizeof(WNDCLASSEX);                                                                           // The size, in bytes, of this structure
    wc.style         = 0;                                                                                            // The class style(s)
    wc.lpfnWndProc     = WndProc;                                                                                      // A pointer to the window procedure.
    wc.cbClsExtra     = 0;                                                                                            // The number of extra bytes to allocate following the window-class structure.
    wc.cbWndExtra     = 0;                                                                                            // The number of extra bytes to allocate following the window instance.
    wc.hInstance     = hInstance;                                                                                    // A handle to the instance that contains the window procedure for the class.
    wc.hIcon         = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON));                                 // A handle to the class icon. This member must be a handle to an icon resource. If this member is NULL, the system provides a default icon.
    wc.hCursor         = LoadCursor(NULL, IDC_ARROW);                                                                  // A handle to the class cursor. This member must be a handle to a cursor resource. If this member is NULL, an application must explicitly set the cursor shape whenever the mouse moves into the application's window.
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);                                                                     // A handle to the class background brush.
    wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MYMENU);                                                                  // Pointer to a null-terminated character string that specifies the resource name of the class menu.
    wc.lpszClassName = g_szClassName;                                                                                // A string that identifies the window class.
    wc.hIconSm         = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON, 32, 32, 0);  // A handle to a small icon that is associated with the window class.

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        0,                      // Optional window styles.
        g_szClassName,          // Window class
        "My application",       // Window text
        WS_OVERLAPPEDWINDOW,    // Window style
        CW_USEDEFAULT,          // Position X
        CW_USEDEFAULT,          // Position Y
        800,                    // Width
        600,                    // Height
        NULL,                   // Parent window
        NULL,                   // Menu
        hInstance,              // Instance handle
        NULL                    // Additional application data
    );

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_STANDARD_CLASSES;  // Enables a set of common controls.
    InitCommonControlsEx(&icex);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            // Add Edit control
            HFONT hfDefault;
            HWND hEdit;

            hEdit = CreateWindowEx(
                WS_EX_CLIENTEDGE,                                      
                "EDIT",                                               
                "Default text to save on disk.",                                        
                WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
                0, 0, 400, 300, 
                hwnd,
                (HMENU)IDC_MY_EDIT,(HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
            if (hEdit == NULL)
                MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);

            hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
            SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));

            // Add Button control
            HWND hButton = CreateWindowEx(
                0,                                                     // Optional window styles.
                "BUTTON",                                              // Predefined class; Button.
                "Save",                                                // Button text.
                WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles.
                450, 50, 100,30,                                                    
                hwnd,                                                  // Parent window.
                (HMENU)ID_MYBUTTON,                                    // Button ID.
                (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE),
                NULL);                                                 // Pointer not needed.

            if (hButton == NULL)
                MessageBox(hwnd, "Could not create button.", "Error", MB_OK | MB_ICONERROR);

        }
        break;
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case ID_MYBUTTON:
                    OpenFileSaveDialog(hwnd);
                    break;
                case ID_FILE_ABOUT:
                    MessageBox(hwnd, "About menu item clicked", "Notice", MB_OK | MB_ICONINFORMATION);
                    break;
                case ID_FILE_EXIT:
                    DestroyWindow(hwnd);
                    break;
                }
            break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
        }
    return 0;
}

BOOL SaveTextFile(HWND hEdit, LPCTSTR pszFileName)
{
    HANDLE hFile;
    BOOL bSuccess = FALSE;

    hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        DWORD dwTextLength;

        dwTextLength = GetWindowTextLength(hEdit);
        if (dwTextLength > 0)
        {
            LPSTR pszText;
            DWORD dwBufferSize = dwTextLength + 1;

            pszText = (LPSTR)GlobalAlloc(GPTR, dwBufferSize);
            if (pszText != NULL)
            {
                if (GetWindowText(hEdit, pszText, dwBufferSize))
                {
                    DWORD dwWritten;

                    if (WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
                        bSuccess = TRUE;
                }
                GlobalFree(pszText);
            }
        }
        CloseHandle(hFile);
    }
    return bSuccess;
}

void OpenFileSaveDialog(HWND hwnd)
{
    OPENFILENAME ofn;
    char szFileName[MAX_PATH] = "";

    ZeroMemory(&ofn, sizeof(ofn));

    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = "txt";
    ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;

    if (GetSaveFileName(&ofn))
    {
        HWND hEdit = GetDlgItem(hwnd, IDC_MY_EDIT);
        SaveTextFile(hEdit, szFileName);
    }
}

More from this blog

Ciprian's blog

12 posts

I am a .NET Developer and Consultant with over 15 years of experience, I specialize in crafting scalable, high-performance applications that drive business growth and innovation.