1 /* 2 * PROJECT: ReactOS system libraries 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/shellext/stobject/csystray.cpp 5 * PURPOSE: Systray shell service object implementation 6 * PROGRAMMERS: David Quintana <gigaherz@gmail.com> 7 * Shriraj Sawant a.k.a SR13 <sr.official@hotmail.com> 8 */ 9 10 #include "precomp.h" 11 12 #include <undocshell.h> 13 #include <shellutils.h> 14 15 SysTrayIconHandlers_t g_IconHandlers [] = { 16 { Volume_Init, Volume_Shutdown, Volume_Update, Volume_Message }, 17 { Hotplug_Init, Hotplug_Shutdown, Hotplug_Update, Hotplug_Message }, 18 { Power_Init, Power_Shutdown, Power_Update, Power_Message } 19 }; 20 const int g_NumIcons = _countof(g_IconHandlers); 21 22 CSysTray::CSysTray() {} 23 CSysTray::~CSysTray() {} 24 25 HRESULT CSysTray::InitNetShell() 26 { 27 HRESULT hr = CoCreateInstance(CLSID_ConnectionTray, 0, 1u, IID_PPV_ARG(IOleCommandTarget, &pctNetShell)); 28 if (FAILED(hr)) 29 return hr; 30 31 return pctNetShell->Exec(&CGID_ShellServiceObject, 32 OLECMDID_NEW, 33 OLECMDEXECOPT_DODEFAULT, NULL, NULL); 34 } 35 36 HRESULT CSysTray::ShutdownNetShell() 37 { 38 if (!pctNetShell) 39 return S_FALSE; 40 HRESULT hr = pctNetShell->Exec(&CGID_ShellServiceObject, 41 OLECMDID_SAVE, 42 OLECMDEXECOPT_DODEFAULT, NULL, NULL); 43 pctNetShell.Release(); 44 return hr; 45 } 46 47 HRESULT CSysTray::InitIcons() 48 { 49 TRACE("Initializing Notification icons...\n"); 50 for (int i = 0; i < g_NumIcons; i++) 51 { 52 HRESULT hr = g_IconHandlers[i].pfnInit(this); 53 if (FAILED(hr)) 54 return hr; 55 } 56 57 return InitNetShell(); 58 } 59 60 HRESULT CSysTray::ShutdownIcons() 61 { 62 TRACE("Shutting down Notification icons...\n"); 63 for (int i = 0; i < g_NumIcons; i++) 64 { 65 HRESULT hr = g_IconHandlers[i].pfnShutdown(this); 66 if (FAILED(hr)) 67 return hr; 68 } 69 70 return ShutdownNetShell(); 71 } 72 73 HRESULT CSysTray::UpdateIcons() 74 { 75 TRACE("Updating Notification icons...\n"); 76 for (int i = 0; i < g_NumIcons; i++) 77 { 78 HRESULT hr = g_IconHandlers[i].pfnUpdate(this); 79 if (FAILED(hr)) 80 return hr; 81 } 82 83 return S_OK; 84 } 85 86 HRESULT CSysTray::ProcessIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult) 87 { 88 for (int i = 0; i < g_NumIcons; i++) 89 { 90 HRESULT hr = g_IconHandlers[i].pfnMessage(this, uMsg, wParam, lParam, lResult); 91 if (FAILED(hr)) 92 return hr; 93 94 if (hr == S_OK) 95 return hr; 96 } 97 98 // Not handled by anyone, so return accordingly. 99 return S_FALSE; 100 } 101 102 /*++ 103 * @name NotifyIcon 104 * 105 * Basically a Shell_NotifyIcon wrapper. 106 * Based on the parameters provided, it changes the current state of the notification icon. 107 * 108 * @param code 109 * Determines whether to add, delete or modify the notification icon (represented by uId). 110 * @param uId 111 * Represents the particular notification icon. 112 * @param hIcon 113 * A handle to an icon for the notification object. 114 * @param szTip 115 * A string for the tooltip of the notification. 116 * @param dwstate 117 * Determines whether to show or hide the notification icon. 118 * 119 * @return The error code. 120 * 121 *--*/ 122 HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, DWORD dwstate) 123 { 124 NOTIFYICONDATA nim = { 0 }; 125 126 TRACE("NotifyIcon code=%d, uId=%d, hIcon=%p, szTip=%S\n", code, uId, hIcon, szTip); 127 128 nim.cbSize = sizeof(nim); 129 nim.uFlags = NIF_MESSAGE | NIF_ICON | NIF_STATE | NIF_TIP; 130 nim.hIcon = hIcon; 131 nim.uID = uId; 132 nim.uCallbackMessage = uId; 133 nim.dwState = dwstate; 134 nim.dwStateMask = NIS_HIDDEN; 135 nim.hWnd = m_hWnd; 136 nim.uVersion = NOTIFYICON_VERSION; 137 if (szTip) 138 StringCchCopy(nim.szTip, _countof(nim.szTip), szTip); 139 else 140 nim.szTip[0] = 0; 141 BOOL ret = Shell_NotifyIcon(code, &nim); 142 return ret ? S_OK : E_FAIL; 143 } 144 145 DWORD WINAPI CSysTray::s_SysTrayThreadProc(PVOID param) 146 { 147 CSysTray * st = (CSysTray*) param; 148 return st->SysTrayThreadProc(); 149 } 150 151 HRESULT CSysTray::SysTrayMessageLoop() 152 { 153 BOOL ret; 154 MSG msg; 155 156 while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) 157 { 158 if (ret < 0) 159 break; 160 161 TranslateMessage(&msg); 162 DispatchMessage(&msg); 163 } 164 165 return S_OK; 166 } 167 168 HRESULT CSysTray::SysTrayThreadProc() 169 { 170 WCHAR strFileName[MAX_PATH]; 171 GetModuleFileNameW(g_hInstance, strFileName, MAX_PATH); 172 HMODULE hLib = LoadLibraryW(strFileName); 173 174 CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED); 175 176 Create(NULL); 177 178 HRESULT ret = SysTrayMessageLoop(); 179 180 CoUninitialize(); 181 182 FreeLibraryAndExitThread(hLib, ret); 183 } 184 185 HRESULT CSysTray::CreateSysTrayThread() 186 { 187 TRACE("CSysTray Init TODO: Initialize tray icon handlers.\n"); 188 189 HANDLE hThread = CreateThread(NULL, 0, s_SysTrayThreadProc, this, 0, NULL); 190 191 CloseHandle(hThread); 192 193 return S_OK; 194 } 195 196 HRESULT CSysTray::DestroySysTrayWindow() 197 { 198 DestroyWindow(); 199 hwndSysTray = NULL; 200 return S_OK; 201 } 202 203 // *** IOleCommandTarget methods *** 204 HRESULT STDMETHODCALLTYPE CSysTray::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText) 205 { 206 UNIMPLEMENTED; 207 return S_OK; 208 } 209 210 HRESULT STDMETHODCALLTYPE CSysTray::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 211 { 212 if (!IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject)) 213 return E_FAIL; 214 215 switch (nCmdID) 216 { 217 case OLECMDID_NEW: // init 218 return CreateSysTrayThread(); 219 case OLECMDID_SAVE: // shutdown 220 return DestroySysTrayWindow(); 221 } 222 return S_OK; 223 } 224 225 BOOL CSysTray::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD dwMsgMapID) 226 { 227 HRESULT hr; 228 229 if (hWnd != m_hWnd) 230 return FALSE; 231 232 switch (uMsg) 233 { 234 case WM_NCCREATE: 235 case WM_NCDESTROY: 236 return FALSE; 237 238 case WM_CREATE: 239 InitIcons(); 240 SetTimer(1, 2000, NULL); 241 return TRUE; 242 243 case WM_TIMER: 244 if (wParam == 1) 245 UpdateIcons(); 246 else 247 ProcessIconMessage(uMsg, wParam, lParam, lResult); 248 return TRUE; 249 250 case WM_DESTROY: 251 KillTimer(1); 252 ShutdownIcons(); 253 return TRUE; 254 } 255 256 TRACE("SysTray message received %u (%08p %08p)\n", uMsg, wParam, lParam); 257 258 hr = ProcessIconMessage(uMsg, wParam, lParam, lResult); 259 if (FAILED(hr)) 260 return FALSE; 261 262 return (hr == S_OK); 263 } 264