Elysia Tools
Navigation
C++
Windows Desktop Features C++ Samples
Windows C++ desktop-specific features including file dialogs, message boxes, and system tray
Samples
Entries inside this sample collection
File Dialog
Create open and save file dialogs using Windows Common Dialog Boxes API
Difficulty
5/10
Estimated time
20 min
Tags
cpp, desktop, file dialog, windows
Prerequisites
Intermediate C++, Windows API, COM
// Windows C++ File Dialog Examples
// Using Common Dialog Boxes API
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <comdef.h>
#include <shlobj.h>
#include <shobjidl.h>
// 1. Basic Open File Dialog
class OpenFileDialog {
public:
struct FileDialogResult {
bool success;
std::wstring filePath;
std::wstring fileName;
std::wstring directory;
};
static FileDialogResult showOpenFile(HWND hWnd = nullptr) {
FileDialogResult result;
result.success = false;
// Create File Open Dialog
IFileOpenDialog* pFileOpen = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileOpenDialog,
nullptr,
CLSCTX_ALL,
IID_IFileOpenDialog,
reinterpret_cast<void**>(&pFileOpen)
);
if (SUCCEEDED(hr)) {
// Show the dialog
hr = pFileOpen->Show(hWnd);
if (SUCCEEDED(hr)) {
// Get the file name from the dialog
IShellItem* pItem = nullptr;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr)) {
result.filePath = pszFilePath;
result.fileName = getFileNameFromPath(result.filePath);
result.directory = getDirectoryFromPath(result.filePath);
result.success = true;
std::wcout << L"Selected file: " << result.filePath << std::endl;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
return result;
}
static std::vector<std::wstring> showOpenMultipleFiles(HWND hWnd = nullptr) {
std::vector<std::wstring> files;
IFileOpenDialog* pFileOpen = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileOpenDialog,
nullptr,
CLSCTX_ALL,
IID_IFileOpenDialog,
reinterpret_cast<void**>(&pFileOpen)
);
if (SUCCEEDED(hr)) {
// Allow multiple selections
DWORD dwFlags;
pFileOpen->GetOptions(&dwFlags);
pFileOpen->SetOptions(dwFlags | FOS_ALLOWMULTISELECT);
// Show the dialog
hr = pFileOpen->Show(hWnd);
if (SUCCEEDED(hr)) {
IShellItemArray* pItems = nullptr;
hr = pFileOpen->GetResults(&pItems);
if (SUCCEEDED(hr)) {
DWORD count = 0;
pItems->GetCount(&count);
std::wcout << L"Selected " << count << L" files:" << std::endl;
for (DWORD i = 0; i < count; i++) {
IShellItem* pItem = nullptr;
hr = pItems->GetItemAt(i, &pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr)) {
files.push_back(pszFilePath);
std::wcout << L" - " << pszFilePath << std::endl;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pItems->Release();
}
}
pFileOpen->Release();
}
return files;
}
private:
static std::wstring getFileNameFromPath(const std::wstring& path) {
size_t pos = path.find_last_of(L'/\\');
if (pos != std::wstring::npos) {
return path.substr(pos + 1);
}
return path;
}
static std::wstring getDirectoryFromPath(const std::wstring& path) {
size_t pos = path.find_last_of(L'/\\');
if (pos != std::wstring::npos) {
return path.substr(0, pos);
}
return L"";
}
};
// 2. Save File Dialog
class SaveFileDialog {
public:
static std::wstring showSaveFile(HWND hWnd = nullptr, const std::wstring& defaultName = L"") {
std::wstring filePath;
IFileSaveDialog* pFileSave = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileSaveDialog,
nullptr,
CLSCTX_ALL,
IID_IFileSaveDialog,
reinterpret_cast<void**>(&pFileSave)
);
if (SUCCEEDED(hr)) {
// Set default file name
if (!defaultName.empty()) {
pFileSave->SetFileName(defaultName.c_str());
}
// Show the dialog
hr = pFileSave->Show(hWnd);
if (SUCCEEDED(hr)) {
IShellItem* pItem = nullptr;
hr = pFileSave->GetResult(&pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr)) {
filePath = pszFilePath;
std::wcout << L"Save to: " << filePath << std::endl;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileSave->Release();
}
return filePath;
}
static std::wstring showSaveFileWithFilter(HWND hWnd = nullptr, const std::wstring& defaultName = L"") {
std::wstring filePath;
IFileSaveDialog* pFileSave = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileSaveDialog,
nullptr,
CLSCTX_ALL,
IID_IFileSaveDialog,
reinterpret_cast<void**>(&pFileSave)
);
if (SUCCEEDED(hr)) {
// Set file type filter
COMDLG_FILTERSPEC rgSpec[] = {
{ L"Text Documents", L"*.txt" },
{ L"All Documents", L"*.*" },
{ L"JSON Files", L"*.json" },
{ L"XML Files", L"*.xml" }
};
pFileSave->SetFileTypes(4, rgSpec);
pFileSave->SetFileTypeIndex(1);
pFileSave->SetDefaultExtension(L"txt");
if (!defaultName.empty()) {
pFileSave->SetFileName(defaultName.c_str());
}
hr = pFileSave->Show(hWnd);
if (SUCCEEDED(hr)) {
IShellItem* pItem = nullptr;
hr = pFileSave->GetResult(&pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr)) {
filePath = pszFilePath;
std::wcout << L"Save to: " << filePath << std::endl;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileSave->Release();
}
return filePath;
}
};
// 3. Folder Selection Dialog
class FolderDialog {
public:
static std::wstring showBrowseFolder(HWND hWnd = nullptr, const std::wstring& title = L"Select Folder") {
std::wstring folderPath;
IFileOpenDialog* pFileOpen = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileOpenDialog,
nullptr,
CLSCTX_ALL,
IID_IFileOpenDialog,
reinterpret_cast<void**>(&pFileOpen)
);
if (SUCCEEDED(hr)) {
// Configure as folder picker
DWORD dwOptions;
pFileOpen->GetOptions(&dwOptions);
pFileOpen->SetOptions(dwOptions | FOS_PICKFOLDERS);
if (!title.empty()) {
pFileOpen->SetTitle(title.c_str());
}
hr = pFileOpen->Show(hWnd);
if (SUCCEEDED(hr)) {
IShellItem* pItem = nullptr;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFolderPath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFolderPath);
if (SUCCEEDED(hr)) {
folderPath = pszFolderPath;
std::wcout << L"Selected folder: " << folderPath << std::endl;
CoTaskMemFree(pszFolderPath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
return folderPath;
}
};
// 4. File Dialog with Custom Settings
class CustomFileDialog {
public:
struct DialogOptions {
std::wstring title;
std::vector<std::pair<std::wstring, std::wstring>> filters;
int defaultFilterIndex = 1;
std::wstring defaultExtension;
std::wstring defaultFileName;
std::wstring initialDirectory;
};
static std::wstring showOpenWithOptions(const DialogOptions& options, HWND hWnd = nullptr) {
std::wstring filePath;
IFileOpenDialog* pFileOpen = nullptr;
HRESULT hr = CoCreateInstance(
CLSID_FileOpenDialog,
nullptr,
CLSCTX_ALL,
IID_IFileOpenDialog,
reinterpret_cast<void**>(&pFileOpen)
);
if (SUCCEEDED(hr)) {
// Set title
if (!options.title.empty()) {
pFileOpen->SetTitle(options.title.c_str());
}
// Set filters
if (!options.filters.empty()) {
std::vector<COMDLG_FILTERSPEC> filterSpecs;
for (const auto& filter : options.filters) {
COMDLG_FILTERSPEC spec;
// Note: In production, ensure strings persist
filterSpecs.push_back({filter.first.c_str(), filter.second.c_str()});
}
pFileOpen->SetFileTypes(static_cast<UINT>(filterSpecs.size()), filterSpecs.data());
pFileOpen->SetFileTypeIndex(options.defaultFilterIndex);
pFileOpen->SetDefaultExtension(options.defaultExtension.c_str());
}
// Set default file name
if (!options.defaultFileName.empty()) {
pFileOpen->SetFileName(options.defaultFileName.c_str());
}
hr = pFileOpen->Show(hWnd);
if (SUCCEEDED(hr)) {
IShellItem* pItem = nullptr;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr)) {
filePath = pszFilePath;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
return filePath;
}
};
// Main demonstration
int main() {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
std::cout << "=== Windows C++ File Dialog Examples ===" << std::endl;
// 1. Open single file
std::cout << "\n--- Open File Dialog ---" << std::endl;
// OpenFileDialog::showOpenFile();
// 2. Open multiple files
std::cout << "\n--- Open Multiple Files ---" << std::endl;
// auto files = OpenFileDialog::showOpenMultipleFiles();
// 3. Save file
std::cout << "\n--- Save File Dialog ---" << std::endl;
// SaveFileDialog::showSaveFile(nullptr, L"document.txt");
// 4. Save file with filter
std::cout << "\n--- Save with Filter ---" << std::endl;
// SaveFileDialog::showSaveFileWithFilter(nullptr, L"data.json");
// 5. Browse folder
std::cout << "\n--- Browse Folder ---" << std::endl;
// FolderDialog::showBrowseFolder(nullptr, L"Select a folder");
// 6. Custom dialog
std::cout << "\n--- Custom File Dialog ---" << std::endl;
CustomFileDialog::DialogOptions options;
options.title = L"Open Image File";
options.filters = {
{L"PNG Images", L"*.png"},
{L"JPEG Images", L"*.jpg;*.jpeg"},
{L"All Files", L"*.*"}
};
// CustomFileDialog::showOpenWithOptions(options);
std::cout << "\nNote: Dialogs require GUI interaction" << std::endl;
CoUninitialize();
std::cout << "\n=== All File Dialog Examples Completed ===" << std::endl;
return 0;
}Message Box
Display various types of message boxes and dialogs for user interaction
Difficulty
3/10
Estimated time
15 min
Tags
cpp, desktop, message box, windows
Prerequisites
Basic C++, Windows API
// Windows C++ Message Box Examples
// Using Windows API for message boxes and dialogs
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
// 1. Basic Message Box
class MessageBox {
public:
enum class Icon {
None = 0,
Error = MB_ICONERROR,
Question = MB_ICONQUESTION,
Warning = MB_ICONWARNING,
Information = MB_ICONINFORMATION
};
enum class Button {
OK = MB_OK,
OKCancel = MB_OKCANCEL,
YesNo = MB_YESNO,
YesNoCancel = MB_YESNOCANCEL,
RetryCancel = MB_RETRYCANCEL,
AbortRetryIgnore = MB_ABORTRETRYIGNORE
};
enum class Result {
OK = IDOK,
Cancel = IDCANCEL,
Yes = IDYES,
No = IDNO,
Abort = IDABORT,
Retry = IDRETRY,
Ignore = IDIGNORE
};
static Result show(const std::string& text, const std::string& title = "Message",
Icon icon = Icon::Information, Button buttons = Button::OK) {
int result = ::MessageBoxA(
nullptr,
text.c_str(),
title.c_str(),
static_cast<int>(icon) | static_cast<int>(buttons)
);
return static_cast<Result>(result);
}
static void showInfo(const std::string& message) {
show(message, "Information", Icon::Information);
}
static void showWarning(const std::string& message) {
show(message, "Warning", Icon::Warning);
}
static void showError(const std::string& message) {
show(message, "Error", Icon::Error);
}
static bool showQuestion(const std::string& message) {
Result result = show(message, "Question", Icon::Question, Button::YesNo);
return result == Result::Yes;
}
};
// 2. Custom Message Box Builder
class MessageBoxBuilder {
private:
std::string m_text;
std::string m_title;
MessageBox::Icon m_icon;
MessageBox::Button m_buttons;
public:
MessageBoxBuilder()
: m_title("Message")
, m_icon(MessageBox::Icon::Information)
, m_buttons(MessageBox::Button::OK) {}
MessageBoxBuilder& text(const std::string& t) {
m_text = t;
return *this;
}
MessageBoxBuilder& title(const std::string& t) {
m_title = t;
return *this;
}
MessageBoxBuilder& icon(MessageBox::Icon i) {
m_icon = i;
return *this;
}
MessageBoxBuilder& buttons(MessageBox::Button b) {
m_buttons = b;
return *this;
}
MessageBox::Result show() {
return MessageBox::show(m_text, m_title, m_icon, m_buttons);
}
};
// 3. Confirm Dialog
class ConfirmDialog {
public:
enum class Action {
Yes,
No,
Cancel
};
static Action confirm(const std::string& message, const std::string& title = "Confirm") {
MessageBox::Result result = MessageBox::show(
message,
title,
MessageBox::Icon::Question,
MessageBox::Button::YesNoCancel
);
switch (result) {
case MessageBox::Result::Yes:
return Action::Yes;
case MessageBox::Result::No:
return Action::No;
default:
return Action::Cancel;
}
}
static bool confirmDelete(const std::string& itemName) {
std::string message = "Are you sure you want to delete \"" + itemName + "\"?";
return MessageBox::showQuestion(message);
}
static bool confirmSave(const std::string& fileName) {
std::string message = "Do you want to save changes to \"" + fileName + "\"?";
return MessageBox::showQuestion(message);
}
static bool confirmExit() {
return MessageBox::showQuestion("Are you sure you want to exit?");
}
};
// 4. Progress Dialog (Simulated)
class ProgressDialog {
public:
static void showProgress(const std::string& title, const std::string& message) {
// Simple message box showing progress start
MessageBox::show(message, title, MessageBox::Icon::Information);
// In a real application, you would use:
// - IProgressDialog interface
// - Custom window with progress bar
// - Task dialog (Windows Vista+)
}
static bool confirmContinue(const std::string& operation, int current, int total) {
char buffer[256];
sprintf_s(buffer, "%s: %d of %d complete. Continue?",
operation.c_str(), current, total);
return MessageBox::showQuestion(buffer);
}
};
// 5. Task Dialog (Windows Vista+)
class TaskDialog {
public:
static void showTaskDialog() {
// Task Dialog requires Windows Vista or later
// Using HRESULT hr = TaskDialogIndirect();
// For this example, we'll use a standard message box
MessageBox::show(
"This is a task dialog simulation.\n"
"Use TaskDialogIndirect API for modern task dialogs.",
"Task Dialog",
MessageBox::Icon::Information
);
}
struct TaskDialogButton {
int id;
std::wstring text;
std::wstring instruction;
std::wstring content;
};
static int showCustomTask(const std::wstring& title,
const std::wstring& instruction,
const std::wstring& content,
const std::vector<TaskDialogButton>& buttons) {
// Simplified task dialog
std::string msg = std::string(instruction.begin(), instruction.end()) + "\n" +
std::string(content.begin(), content.end());
MessageBox::show(msg, std::string(title.begin(), title.end()),
MessageBox::Icon::Information);
return IDOK;
}
};
// 6. Error Dialog with Details
class ErrorDialog {
public:
static void showError(const std::string& message, const std::string& details = "") {
std::string fullMessage = message;
if (!details.empty()) {
fullMessage += "\n\nDetails: " + details;
}
MessageBox::show(fullMessage, "Error", MessageBox::Icon::Error);
}
static void showLastError(const std::string& context) {
DWORD error = GetLastError();
if (error == 0) {
MessageBox::show(context + " completed successfully", "Success");
return;
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer,
0,
nullptr
);
std::string fullMessage = context + "\n\nError: " + std::to_string(error);
if (size > 0) {
fullMessage += "\n" + std::string(messageBuffer, size);
LocalFree(messageBuffer);
}
MessageBox::show(fullMessage, "Error", MessageBox::Icon::Error);
}
static void showException(const std::string& exceptionType, const std::string& what) {
std::string message = "Exception occurred:\n"
"Type: " + exceptionType + "\n"
"What: " + what;
MessageBox::show(message, "Exception", MessageBox::Icon::Error);
}
};
// 7. Input Dialog (Simulated)
class InputDialog {
public:
static std::string getText(const std::string& prompt,
const std::string& title = "Input",
const std::string& defaultValue = "") {
// For a real input dialog, you would create a custom dialog window
// This is a simplified version using console
std::cout << prompt << std::endl;
if (!defaultValue.empty()) {
std::cout << "[Default: " << defaultValue << "]" << std::endl;
}
std::cout << "> ";
std::string input;
std::getline(std::cin, input);
if (input.empty() && !defaultValue.empty()) {
return defaultValue;
}
MessageBox::show("You entered: " + input, title, MessageBox::Icon::Information);
return input;
}
static std::string getPassword(const std::string& prompt) {
// In a real application, use a secure input method
return getText(prompt, "Password Input");
}
};
// 8. Notification Dialog
class NotificationDialog {
public:
enum class NotificationType {
Info,
Warning,
Error,
Success
};
static void show(const std::string& message, NotificationType type = NotificationType::Info) {
std::string title;
MessageBox::Icon icon;
switch (type) {
case NotificationType::Info:
title = "Information";
icon = MessageBox::Icon::Information;
break;
case NotificationType::Warning:
title = "Warning";
icon = MessageBox::Icon::Warning;
break;
case NotificationType::Error:
title = "Error";
icon = MessageBox::Icon::Error;
break;
case NotificationType::Success:
title = "Success";
icon = MessageBox::Icon::Information;
break;
}
MessageBox::show(message, title, icon);
}
static void showToast(const std::string& message, int durationSeconds = 3) {
// Simulated toast notification
MessageBox::show(message, "Toast Notification", MessageBox::Icon::Information);
// In a real application, use:
// - Shell_NotifyIcon with balloon tooltips
// - Windows 10 toast notifications
}
};
// Main demonstration
int main() {
std::cout << "=== Windows C++ Message Box Examples ===" << std::endl;
// 1. Basic message boxes
std::cout << "\n--- Basic Message Boxes ---" << std::endl;
MessageBox::showInfo("This is an informational message");
// MessageBox::showWarning("This is a warning message");
// MessageBox::showError("This is an error message");
// 2. Question dialog
std::cout << "\n--- Question Dialog ---" << std::endl;
bool answer = MessageBox::showQuestion("Do you want to continue?");
std::cout << "User answer: " << (answer ? "Yes" : "No") << std::endl;
// 3. Message box builder
std::cout << "\n--- Message Box Builder ---" << std::endl;
MessageBoxBuilder builder;
// builder.text("File has been modified")
// .title("Save Changes?")
// .icon(MessageBox::Icon::Question)
// .buttons(MessageBox::Button::YesNoCancel)
// .show();
// 4. Confirm dialogs
std::cout << "\n--- Confirm Dialogs ---" << std::endl;
// ConfirmDialog::confirmDelete("important_file.txt");
// ConfirmDialog::confirmSave("document.docx");
// ConfirmDialog::confirmExit();
// 5. Error dialogs
std::cout << "\n--- Error Dialogs ---" << std::endl;
// ErrorDialog::showError("Failed to open file", "File not found: data.txt");
// ErrorDialog::showLastError("File operation");
// 6. Notifications
std::cout << "\n--- Notifications ---" << std::endl;
// NotificationDialog::show("Operation completed successfully", NotificationDialog::NotificationType::Success);
// NotificationDialog::showToast("New message received", 5);
std::cout << "\n=== All Message Box Examples Completed ===" << std::endl;
return 0;
}System Tray
Create and manage system tray icons with balloon tooltips and context menus
Difficulty
7/10
Estimated time
30 min
Tags
cpp, desktop, system tray, windows
Prerequisites
Intermediate C++, Windows API, Window messaging
// Windows C++ System Tray Examples
// Using Shell_NotifyIcon API
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <tuple>
#include <windows.h>
#include <shellapi.h>
#include <resource.h>
// 1. Basic System Tray Icon
class SystemTrayIcon {
private:
NOTIFYICONDATAA m_nid;
HWND m_hWnd;
bool m_added;
std::string m_tooltip;
public:
SystemTrayIcon(HWND hWnd = nullptr)
: m_hWnd(hWnd), m_added(false) {
ZeroMemory(&m_nid, sizeof(m_nid));
m_nid.cbSize = sizeof(NOTIFYICONDATAA);
m_nid.hWnd = m_hWnd;
m_nid.uID = 1;
m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
m_nid.uCallbackMessage = WM_USER + 1;
m_nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
strcpy_s(m_nid.szTip, "Application");
}
~SystemTrayIcon() {
remove();
}
bool add() {
if (m_added) return true;
m_added = Shell_NotifyIconA(NIM_ADD, &m_nid) != FALSE;
if (m_added) {
std::cout << "System tray icon added" << std::endl;
}
return m_added;
}
bool remove() {
if (!m_added) return true;
bool result = Shell_NotifyIconA(NIM_DELETE, &m_nid) != FALSE;
m_added = !result;
if (result) {
std::cout << "System tray icon removed" << std::endl;
}
return result;
}
bool setTooltip(const std::string& tooltip) {
m_tooltip = tooltip;
strncpy_s(m_nid.szTip, tooltip.c_str(), sizeof(m_nid.szTip) - 1);
m_nid.szTip[sizeof(m_nid.szTip) - 1] = '\0';
if (m_added) {
return Shell_NotifyIconA(NIM_MODIFY, &m_nid) != FALSE;
}
return true;
}
bool setIcon(HICON hIcon) {
m_nid.hIcon = hIcon;
if (m_added) {
return Shell_NotifyIconA(NIM_MODIFY, &m_nid) != FALSE;
}
return true;
}
bool showBalloon(const std::string& title, const std::string& message,
int timeout = 5000, BalloonIcon icon = Info) {
if (!m_added) return false;
m_nid.uFlags = NIF_INFO;
strncpy_s(m_nid.szInfoTitle, title.c_str(), sizeof(m_nid.szInfoTitle) - 1);
strncpy_s(m_nid.szInfo, message.c_str(), sizeof(m_nid.szInfo) - 1);
m_nid.dwInfoFlags = icon;
m_nid.uTimeout = timeout;
bool result = Shell_NotifyIconA(NIM_MODIFY, &m_nid) != FALSE;
// Reset flags
m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
return result;
}
enum BalloonIcon {
None = NIIF_NONE,
Info = NIIF_INFO,
Warning = NIIF_WARNING,
Error = NIIF_ERROR,
User = NIIF_USER
};
bool hide() {
if (!m_added) return false;
return Shell_NotifyIconA(NIM_DELETE, &m_nid) != FALSE;
}
bool show() {
if (m_added) return true;
return add();
}
};
// 2. Animated System Tray Icon
class AnimatedTrayIcon : public SystemTrayIcon {
private:
std::vector<HICON> m_icons;
size_t m_currentIcon;
UINT m_timerId;
public:
AnimatedTrayIcon(HWND hWnd) : SystemTrayIcon(hWnd), m_currentIcon(0), m_timerId(0) {}
void addIcon(HICON hIcon) {
m_icons.push_back(hIcon);
}
void startAnimation(UINT intervalMs = 500) {
if (m_icons.empty() || m_timerId) return;
m_timerId = SetTimer(nullptr, 0, intervalMs, [](HWND hwnd, UINT uiMsg,
UINT_PTR idEvent, DWORD dwTime) {
// Timer callback - would update icon
});
}
void stopAnimation() {
if (m_timerId) {
KillTimer(nullptr, m_timerId);
m_timerId = 0;
}
}
void nextFrame() {
if (m_icons.empty()) return;
m_currentIcon = (m_currentIcon + 1) % m_icons.size();
setIcon(m_icons[m_currentIcon]);
}
};
// 3. System Tray with Context Menu
class TrayIconWithMenu : public SystemTrayIcon {
public:
TrayIconWithMenu(HWND hWnd) : SystemTrayIcon(hWnd) {}
void showContextMenu(int x, int y) {
HMENU hMenu = CreatePopupMenu();
if (!hMenu) return;
// Add menu items
AppendMenuA(hMenu, MF_STRING, 1, "Show");
AppendMenuA(hMenu, MF_STRING, 2, "Hide");
AppendMenuA(hMenu, MF_SEPARATOR, 0, nullptr);
AppendMenuA(hMenu, MF_STRING, 3, "Settings");
AppendMenuA(hMenu, MF_SEPARATOR, 0, nullptr);
AppendMenuA(hMenu, MF_STRING, 4, "Exit");
// Show menu
SetForegroundWindow(m_hWnd);
UINT result = TrackPopupMenu(
hMenu,
TPM_RETURNCMD | TPM_NONOTIFY,
x, y,
0,
m_hWnd,
nullptr
);
DestroyMenu(hMenu);
// Handle result
handleMenuSelection(result);
}
private:
void handleMenuSelection(UINT itemId) {
switch (itemId) {
case 1:
std::cout << "Menu: Show" << std::endl;
break;
case 2:
std::cout << "Menu: Hide" << std::endl;
break;
case 3:
std::cout << "Menu: Settings" << std::endl;
break;
case 4:
std::cout << "Menu: Exit" << std::endl;
PostQuitMessage(0);
break;
}
}
};
// 4. Status Monitoring Tray Icon
class StatusTrayIcon : public SystemTrayIcon {
private:
enum class Status {
OK,
Warning,
Error,
Busy
};
Status m_status;
public:
StatusTrayIcon(HWND hWnd) : SystemTrayIcon(hWnd), m_status(Status::OK) {}
void setStatus(Status status, const std::string& message = "") {
m_status = status;
switch (status) {
case Status::OK:
setIcon(LoadIcon(nullptr, IDI_WINLOGO));
showBalloon("Status OK", message, 3000, BalloonIcon::Info);
break;
case Status::Warning:
setIcon(LoadIcon(nullptr, IDI_WARNING));
showBalloon("Warning", message, 5000, BalloonIcon::Warning);
break;
case Status::Error:
setIcon(LoadIcon(nullptr, IDI_ERROR));
showBalloon("Error", message, 10000, BalloonIcon::Error);
break;
case Status::Busy:
setIcon(LoadIcon(nullptr, IDI_APPLICATION));
setTooltip("Working...");
break;
}
}
void updateProgress(int percent, const std::string& operation) {
char tooltip[128];
sprintf_s(tooltip, "%s: %d%%", operation.c_str(), percent);
setTooltip(tooltip);
}
};
// 5. Notification Manager
class NotificationManager {
private:
SystemTrayIcon* m_trayIcon;
std::queue<std::tuple<std::string, std::string>> m_notifications;
bool m_showing;
public:
NotificationManager(SystemTrayIcon* icon) : m_trayIcon(icon), m_showing(false) {}
void enqueue(const std::string& title, const std::string& message) {
m_notifications.push(std::make_tuple(title, message));
processNext();
}
void processNext() {
if (m_showing || m_notifications.empty()) return;
m_showing = true;
auto& notification = m_notifications.front();
m_trayIcon->showBalloon(
std::get<0>(notification),
std::get<1>(notification),
5000
);
// Schedule next notification
SetTimer(nullptr, 0, 6000, [](HWND hwnd, UINT msg, UINT_PTR id, DWORD time) {
// Mark as done and process next
});
}
void clear() {
while (!m_notifications.empty()) {
m_notifications.pop();
}
}
};
// 6. Quick Actions from Tray
class QuickActionsTray : public TrayIconWithMenu {
public:
QuickActionsTray(HWND hWnd) : TrayIconWithMenu(hWnd) {}
void showQuickActions() {
HMENU hMenu = CreatePopupMenu();
AppendMenuA(hMenu, MF_STRING, 100, "New Document");
AppendMenuA(hMenu, MF_STRING, 101, "Open Recent");
AppendMenuA(hMenu, MF_SEPARATOR, 0, nullptr);
AppendMenuA(hMenu, MF_STRING, 102, "Search");
AppendMenuA(hMenu, MF_STRING, 103, "Settings");
AppendMenuA(hMenu, MF_SEPARATOR, 0, nullptr);
AppendMenuA(hMenu, MF_STRING, 104, "About");
AppendMenuA(hMenu, MF_STRING, 105, "Exit");
POINT pt;
GetCursorPos(&pt);
UINT result = TrackPopupMenu(
hMenu,
TPM_RETURNCMD,
pt.x, pt.y,
0,
m_hWnd,
nullptr
);
DestroyMenu(hMenu);
executeQuickAction(result);
}
private:
void executeQuickAction(UINT actionId) {
switch (actionId) {
case 100:
std::cout << "Action: New Document" << std::endl;
break;
case 101:
std::cout << "Action: Open Recent" << std::endl;
break;
case 102:
std::cout << "Action: Search" << std::endl;
break;
case 103:
std::cout << "Action: Settings" << std::endl;
break;
case 104:
std::cout << "Action: About" << std::endl;
break;
case 105:
std::cout << "Action: Exit" << std::endl;
PostQuitMessage(0);
break;
}
}
};
// 7. Tray Icon Helper
class TrayIconHelper {
public:
static HICON createIconFromResource(int resourceId) {
return LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(resourceId));
}
static HICON createColoredIcon(COLORREF color) {
// Create a simple colored icon
HDC hdc = GetDC(nullptr);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 16, 16);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);
// Fill with color
HBRUSH hBrush = CreateSolidBrush(color);
RECT rect = {0, 0, 16, 16};
FillRect(hdcMem, &rect, hBrush);
SelectObject(hdcMem, hOldBitmap);
DeleteObject(hBrush);
DeleteDC(hdcMem);
ReleaseDC(nullptr, hdc);
ICONINFO iconInfo = {};
iconInfo.fIcon = TRUE;
iconInfo.hbmMask = hBitmap;
iconInfo.hbmColor = hBitmap;
HICON hIcon = CreateIconIndirect(&iconInfo);
DeleteObject(hBitmap);
return hIcon;
}
};
// Main demonstration
int main() {
std::cout << "=== Windows C++ System Tray Examples ===" << std::endl;
// Note: System tray requires a window handle
// These examples demonstrate the API usage
// 1. Basic tray icon
std::cout << "\n--- Basic System Tray Icon ---" << std::endl;
// SystemTrayIcon tray(nullptr);
// tray.add();
// tray.setTooltip("My Application");
// tray.showBalloon("Welcome", "Application started!", 3000);
// 2. Status monitoring
std::cout << "\n--- Status Monitoring ---" << std::endl;
// StatusTrayIcon statusIcon(nullptr);
// statusIcon.add();
// statusIcon.setStatus(StatusTrayIcon::Status::OK, "All systems operational");
// statusIcon.setStatus(StatusTrayIcon::Status::Warning, "Low memory");
// statusIcon.setStatus(StatusTrayIcon::Status::Error, "Connection failed");
// 3. Quick actions
std::cout << "\n--- Quick Actions ---" << std::endl;
// QuickActionsTray actions(nullptr);
// actions.add();
// actions.showQuickActions();
// 4. Animated icon
std::cout << "\n--- Animated Icon ---" << std::endl;
// AnimatedTrayIcon animated(nullptr);
// animated.add();
// animated.addIcon(LoadIcon(nullptr, IDI_APPLICATION));
// animated.addIcon(LoadIcon(nullptr, IDI_HAND));
// animated.startAnimation(1000);
std::cout << "\nNote: System tray requires a window message loop" << std::endl;
std::cout << "\n=== All System Tray Examples Completed ===" << std::endl;
return 0;
}Tools
Tools frequently paired with this sample
Related