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