Windows C++ 桌面功能示例
Windows C++ 桌面专用功能示例,包括文件对话框、消息框和系统托盘
💻 文件对话框 cpp
🟢 simple
⭐⭐⭐
使用Windows通用对话框API创建打开和保存文件对话框
⏱️ 20 min
🏷️ 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;
}
💻 消息框 cpp
🟢 simple
⭐⭐
显示各种类型的消息框和对话框用于用户交互
⏱️ 15 min
🏷️ 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 <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;
}
💻 系统托盘 cpp
🟡 intermediate
⭐⭐⭐⭐
创建和管理系统托盘图标,具有气球工具提示和上下文菜单
⏱️ 30 min
🏷️ 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 <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;
}