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