トレイアイコンの実装 (CTrayIconImpl) [WTL]

(2004.03.25)
#pragma once
 
// WAC.com Class Liblary for Visual C++
// Copyright (C) WAC.com Inc. All rights reserved.
//
// This file is a part of the WAC.com Class Liblary.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license. You must not remove this notice, or
// any other, from this software.
 
// '07.04.06 : UNICODE対応 (sha)
// '07.06.21 : コードの整備 (sha)
 
 
/////////////////////////////////////////////////////////////////////////////
// CNotifyIconData
 
class CNotifyIconData : public NOTIFYICONDATA
{
public:    
    CNotifyIconData()
    {
        ::ZeroMemory(this, sizeof(NOTIFYICONDATA));
//        cbSize = sizeof(NOTIFYICONDATA);
#if _UNICODE
        cbSize = 936;
#else
        cbSize = 488;
#endif
        ATLTRACE(_T("%d\n"), sizeof(NOTIFYICONDATA));
    }
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CTrayIconImpl
 
template <class T>
class CTrayIconImpl
{
protected:
    typedef CTrayIconImpl                        thisClass;
 
public:    
    CTrayIconImpl()
    {
        WM_TRAYICON = ::RegisterWindowMessage(_T("WM_TRAYICON"));
        WM_TASKBARCREATED = ::RegisterWindowMessage(_T("TaskbarCreated"));
 
        m_bRegistered = false;
        m_nDefaultID = 0;
    }
    virtual ~CTrayIconImpl()
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        hr = pT->UnregisterIcon();
        if (FAILED(hr))
        {
            // 無視する。。
        }
    }
 
BEGIN_MSG_MAP(CTrayIconImpl)
    MESSAGE_HANDLER(WM_TRAYICON, OnTrayIcon)
    MESSAGE_HANDLER(WM_TASKBARCREATED, OnTaskBarCreated)
END_MSG_MAP()
 
// ハンドラ プロパティ:
//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
 
// Window Message Handles
public:
    LRESULT OnTrayIcon(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
    {
        T* pT = static_cast<T*>(this);
 
        // Is this the ID we want?
        if (wParam != m_notifyIconData.uID)
        {
            return 0;
        }
 
        LRESULT lResult = 0;
 
        if      (LOWORD(lParam) == WM_RBUTTONUP)
        {
            lResult = pT->OnTrayIconRButtonUp();
        }
        else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)
        {
            lResult = pT->OnTrayIconLButtonDblClk();
        }
        else
        {
            // 何もしない。。
        }
 
        return lResult;
    }
    LRESULT OnTaskBarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        BOOL br = ::Shell_NotifyIcon(NIM_ADD, &m_notifyIconData);
        if (!br)
        {
            // 無視する。。
        }
 
        return 0;
    }
 
// Command Handlers
public:
 
public:
    // Install a taskbar icon
    // szToolTip : The tooltip to display
    // hIcon : The icon to display
    // nID : The resource ID of the context menu
    HRESULT RegisterIcon(HICON hIcon, LPCTSTR szTip, UINT nID)
    {
        T* pT = static_cast<T*>(this);
 
        // Fill in the data        
        m_notifyIconData.hWnd = pT->m_hWnd;
        m_notifyIconData.uID = nID;
        m_notifyIconData.hIcon = hIcon;
        m_notifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
        m_notifyIconData.uCallbackMessage = WM_TRAYICON;
        _tcscpy_s(m_notifyIconData.szTip, szTip);
 
        BOOL br = ::Shell_NotifyIcon(NIM_ADD, &m_notifyIconData);
        if (!br)
        {
            return E_FAIL;
        }
 
        m_bRegistered = true;
 
        return S_OK;
    }
    // Remove taskbar icon
    HRESULT UnregisterIcon()
    {
        if (!m_bRegistered)
        {
            return E_FAIL;
        }
 
        // Remove
        m_notifyIconData.uFlags = 0;
 
        BOOL br = ::Shell_NotifyIcon(NIM_DELETE, &m_notifyIconData);
        if (!br)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    // Set the icon tooltip text
    HRESULT SetTooltip(LPCTSTR szTip)
    {
        if (szTip == NULL)
        {
            return E_FAIL;
        }
 
        // Fill the structure
        m_notifyIconData.uFlags = NIF_TIP;
        _tcscpy_s(m_notifyIconData.szTip, szTip);
 
        BOOL br = ::Shell_NotifyIcon(NIM_MODIFY, &m_notifyIconData);
        if (!br)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    HRESULT ShowBalloonTip(LPCTSTR szInfo, LPCTSTR szInfoTitle, UINT uTimeout, DWORD dwInfoFlags)
    { 
        m_notifyIconData.uFlags = NIF_INFO;
        m_notifyIconData.uTimeout = uTimeout;
        m_notifyIconData.dwInfoFlags = dwInfoFlags;
        _tcscpy_s(m_notifyIconData.szInfo, szInfo ? szInfo : _T(""));
        _tcscpy_s(m_notifyIconData.szInfoTitle, szInfoTitle ? szInfoTitle : _T(""));
 
        BOOL br = ::Shell_NotifyIcon(NIM_MODIFY, &m_notifyIconData);
        if (!br)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    // Set the default menu item ID
    void SetDefaultID(UINT nID)
    {
        m_nDefaultID = nID;
    }
 
// Overrides
public:
    LRESULT OnTrayIconRButtonUp()
    {
        T* pT = static_cast<T*>(this);
 
        // Display the menu at the current mouse location. There's a "bug"
        // (Microsoft calls it a feature) in Windows 95 that requires calling
        // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
 
        // Load the menu
        CMenu menu;
        if (!menu.LoadMenu(m_notifyIconData.uID))
        {
            return 0;
        }
 
        // Get the sub-menu
        CMenuHandle menuPopup = menu.GetSubMenu(0);
 
        // Prepare
        pT->OnTrayIconPrepareMenu(menuPopup);
 
        // Get the menu position
        CPoint pos;
        ::GetCursorPos(&pos);
 
        // Make app the foreground
        ::SetForegroundWindow(pT->m_hWnd);
 
        // Set the default menu item
        if (m_nDefaultID == 0)
        {
            menuPopup.SetMenuDefaultItem(0, TRUE);
        }
        else
        {
            menuPopup.SetMenuDefaultItem(m_nDefaultID);
        }
 
        // Track
        menuPopup.TrackPopupMenu(TPM_LEFTALIGN, pos.x, pos.y, pT->m_hWnd);
 
        // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly"
        pT->PostMessage(WM_NULL);
 
        // Done
        menu.DestroyMenu();
 
        return 0;
    }
    LRESULT OnTrayIconLButtonDblClk()
    {
        T* pT = static_cast<T*>(this);
 
        // Make app the foreground
        ::SetForegroundWindow(pT->m_hWnd);
 
        // Load the menu
        CMenu menu;
        if (!menu.LoadMenu(m_notifyIconData.uID))
        {
            return 0;
        }
 
        // Get the sub-menu
        CMenuHandle menuPopup = menu.GetSubMenu(0);
 
        // Get the item
        if (m_nDefaultID)
        {
            // Send
            pT->SendMessage(WM_COMMAND, m_nDefaultID, 0);
        }
        else
        {
            UINT nID = menuPopup.GetMenuItemID(0);
 
            // Send
            pT->SendMessage(WM_COMMAND, nID, 0);
        }
 
        // Done
        menu.DestroyMenu();
 
        return 0;
    }
    // Allow the menu items to be enabled/checked/etc.
    void OnTrayIconPrepareMenu(HMENU hMenu)
    {
        // Stub
    }
 
protected:
    UINT WM_TRAYICON;
    UINT WM_TASKBARCREATED;
 
    CNotifyIconData m_notifyIconData;
    bool m_bRegistered;
    UINT m_nDefaultID;
};
一覧に戻る
© 2003 WAC.com All Right Reserved.