Sync with trunk r64222.
[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\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 const GUID CLSID_SysTray = { 0x35CEC8A3, 0x2BE6, 0x11D2, { 0x87, 0x73, 0x92, 0xE2, 0x20, 0x52, 0x41, 0x53 } };
19
20 CSysTray::CSysTray() {}
21 CSysTray::~CSysTray() {}
22
23 HRESULT CSysTray::InitIcons()
24 {
25 for (int i = 0; i < g_NumIcons; i++)
26 {
27 HRESULT hr = g_IconHandlers[i].pfnInit(this);
28 if (FAILED(hr))
29 return hr;
30 }
31
32 return S_OK;
33 }
34
35 HRESULT CSysTray::ShutdownIcons()
36 {
37 for (int i = 0; i < g_NumIcons; i++)
38 {
39 HRESULT hr = g_IconHandlers[i].pfnShutdown(this);
40 if (FAILED(hr))
41 return hr;
42 }
43
44 return S_OK;
45 }
46
47 HRESULT CSysTray::UpdateIcons()
48 {
49 for (int i = 0; i < g_NumIcons; i++)
50 {
51 HRESULT hr = g_IconHandlers[i].pfnUpdate(this);
52 if (FAILED(hr))
53 return hr;
54 }
55
56 return S_OK;
57 }
58
59 HRESULT CSysTray::ProcessIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
60 {
61 for (int i = 0; i < g_NumIcons; i++)
62 {
63 HRESULT hr = g_IconHandlers[i].pfnMessage(this, uMsg, wParam, lParam);
64 if (FAILED(hr))
65 return hr;
66
67 if (hr != S_FALSE)
68 return hr;
69 }
70
71 return S_OK;
72 }
73
74 HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip)
75 {
76 NOTIFYICONDATA nim;
77 nim.cbSize = sizeof(NOTIFYICONDATA);
78 nim.uFlags = NIF_ICON | NIF_STATE | NIF_TIP;
79 nim.hIcon = hIcon;
80 nim.uID = uId;
81 nim.uCallbackMessage = uId;
82 nim.dwState = 0;
83 nim.dwStateMask = 0;
84 nim.hWnd = m_hWnd;
85 nim.uVersion = NOTIFYICON_VERSION;
86 if (szTip)
87 StringCchCopy(nim.szTip, _countof(nim.szTip), szTip);
88 else
89 nim.szTip[0] = 0;
90 BOOL ret = Shell_NotifyIcon(code, &nim);
91 return ret ? S_OK : E_FAIL;
92 }
93
94 DWORD WINAPI CSysTray::s_SysTrayThreadProc(PVOID param)
95 {
96 CSysTray * st = (CSysTray*) param;
97 return st->SysTrayThreadProc();
98 }
99
100 HRESULT CSysTray::SysTrayMessageLoop()
101 {
102 BOOL ret;
103 MSG msg;
104
105 while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
106 {
107 if (ret < 0)
108 break;
109
110 TranslateMessage(&msg);
111 DispatchMessage(&msg);
112 }
113
114 return S_OK;
115 }
116
117 HRESULT CSysTray::SysTrayThreadProc()
118 {
119 WCHAR strFileName[MAX_PATH];
120 GetModuleFileNameW(g_hInstance, strFileName, MAX_PATH);
121 HMODULE hLib = LoadLibraryW(strFileName);
122
123 CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
124
125 Create(NULL);
126
127 HRESULT ret = SysTrayMessageLoop();
128
129 CoUninitialize();
130
131 FreeLibraryAndExitThread(hLib, ret);
132 }
133
134 HRESULT CSysTray::CreateSysTrayThread()
135 {
136 TRACE("CSysTray Init TODO: Initialize tray icon handlers.\n");
137
138 HANDLE hThread = CreateThread(NULL, 0, s_SysTrayThreadProc, this, 0, NULL);
139
140 CloseHandle(hThread);
141
142 return S_OK;
143 }
144
145 HRESULT CSysTray::DestroySysTrayWindow()
146 {
147 DestroyWindow();
148 hwndSysTray = NULL;
149 return S_OK;
150 }
151
152 // *** IOleCommandTarget methods ***
153 HRESULT STDMETHODCALLTYPE CSysTray::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
154 {
155 UNIMPLEMENTED;
156 return S_OK;
157 }
158
159 HRESULT STDMETHODCALLTYPE CSysTray::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
160 {
161 if (!IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
162 return E_FAIL;
163
164 switch (nCmdID)
165 {
166 case OLECMDID_NEW: // init
167 return CreateSysTrayThread();
168 case OLECMDID_SAVE: // shutdown
169 return DestroySysTrayWindow();
170 }
171 return S_OK;
172 }
173
174 BOOL CSysTray::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD dwMsgMapID)
175 {
176 HRESULT hr;
177
178 if (hWnd != m_hWnd)
179 return FALSE;
180
181 switch (uMsg)
182 {
183 case WM_CREATE:
184 InitIcons();
185 SetTimer(1, 2000, NULL);
186 return TRUE;
187 case WM_TIMER:
188 UpdateIcons();
189 return TRUE;
190 case WM_DESTROY:
191 ShutdownIcons();
192 return TRUE;
193 }
194
195 TRACE("SysTray message received %u (%08p %08p)\n", uMsg, wParam, lParam);
196
197 hr = ProcessIconMessage(uMsg, wParam, lParam);
198 if (FAILED(hr))
199 return FALSE;
200
201 if (hr == S_FALSE)
202 return FALSE;
203
204 return TRUE;
205 }