Win32 API programming with C - Using the file system
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);
}
}
Subscribe to my newsletter
Read articles from Ciprian Fusa directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ciprian Fusa
Ciprian Fusa
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.