Win32 API programming with C - Using the file system
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);
}
}