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;
}