Revert r66580 and r66579.
[reactos.git] / reactos / base / shell / 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_FALSE)
91 return hr;
92 }
93
94 return S_OK;
95 }
96
97 HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip)
98 {
99 NOTIFYICONDATA nim = { 0 };
100
101 TRACE("NotifyIcon code=%d, uId=%d, hIcon=%p, szTip=%S\n", code, uId, hIcon, szTip);
102
103 nim.cbSize = sizeof(NOTIFYICONDATA);
104 nim.uFlags = NIF_MESSAGE | NIF_ICON | NIF_STATE | NIF_TIP;
105 nim.hIcon = hIcon;
106 nim.uID = uId;
107 nim.uCallbackMessage = uId;
108 nim.dwState = 0;
109 nim.dwStateMask = 0;
110 nim.hWnd = m_hWnd;
111 nim.uVersion = NOTIFYICON_VERSION;
112 if (szTip)
113 StringCchCopy(nim.szTip, _countof(nim.szTip), szTip);
114 else
115 nim.szTip[0] = 0;
116 BOOL ret = Shell_NotifyIcon(code, &nim);
117 return ret ? S_OK : E_FAIL;
118 }
119
120 DWORD WINAPI CSysTray::s_SysTrayThreadProc(PVOID param)
121 {
122 CSysTray * st = (CSysTray*) param;
123 return st->SysTrayThreadProc();
124 }
125
126 HRESULT CSysTray::SysTrayMessageLoop()
127 {
128 BOOL ret;
129 MSG msg;
130
131 while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
132 {
133 if (ret < 0)
134 break;
135
136 TranslateMessage(&msg);
137 DispatchMessage(&msg);
138 }
139
140 return S_OK;
141 }
142
143 HRESULT CSysTray::SysTrayThreadProc()
144 {
145 WCHAR strFileName[MAX_PATH];
146 GetModuleFileNameW(g_hInstance, strFileName, MAX_PATH);
147 HMODULE hLib = LoadLibraryW(strFileName);
148
149 CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
150
151 Create(NULL);
152
153 HRESULT ret = SysTrayMessageLoop();
154
155 CoUninitialize();
156
157 FreeLibraryAndExitThread(hLib, ret);
158 }
159
160 HRESULT CSysTray::CreateSysTrayThread()
161 {
162 TRACE("CSysTray Init TODO: Initialize tray icon handlers.\n");
163
164 HANDLE hThread = CreateThread(NULL, 0, s_SysTrayThreadProc, this, 0, NULL);
165
166 CloseHandle(hThread);
167
168 return S_OK;
169 }
170
171 HRESULT CSysTray::DestroySysTrayWindow()
172 {
173 DestroyWindow();
174 hwndSysTray = NULL;
175 return S_OK;
176 }
177
178 // *** IOleCommandTarget methods ***
179 HRESULT STDMETHODCALLTYPE CSysTray::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
180 {
181 UNIMPLEMENTED;
182 return S_OK;
183 }
184
185 HRESULT STDMETHODCALLTYPE CSysTray::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
186 {
187 if (!IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
188 return E_FAIL;
189
190 switch (nCmdID)
191 {
192 case OLECMDID_NEW: // init
193 return CreateSysTrayThread();
194 case OLECMDID_SAVE: // shutdown
195 return DestroySysTrayWindow();
196 }
197 return S_OK;
198 }
199
200 BOOL CSysTray::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD dwMsgMapID)
201 {
202 HRESULT hr;
203
204 if (hWnd != m_hWnd)
205 return FALSE;
206
207 switch (uMsg)
208 {
209 case WM_CREATE:
210 InitIcons();
211 SetTimer(1, 2000, NULL);
212 return TRUE;
213 case WM_TIMER:
214 UpdateIcons();
215 return TRUE;
216 case WM_DESTROY:
217 KillTimer(1);
218 ShutdownIcons();
219 return TRUE;
220 }
221
222 TRACE("SysTray message received %u (%08p %08p)\n", uMsg, wParam, lParam);
223
224 hr = ProcessIconMessage(uMsg, wParam, lParam);
225 if (FAILED(hr))
226 return FALSE;
227
228 if (hr == S_FALSE)
229 return FALSE;
230
231 return TRUE;
232 }