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