[STOBJECT] Revert b7c3398 because it was not the cause of the original problem I...
[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 * 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(NOTIFYICONDATA);
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 UpdateIcons();
245 return TRUE;
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 }