[HIVESFT.INF]
[reactos.git] / dll / win32 / stobject / stobject.cpp
1 /*
2 * PROJECT: ReactOS system libraries
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll\win32\stobject\stobject.cpp
5 * PURPOSE: Systray shell service object
6 * PROGRAMMERS: Robert Naumann
7 David Quintana <gigaherz@gmail.com>
8 */
9
10 #include "precomp.h"
11
12 #include <olectl.h>
13 #include <atlwin.h>
14
15 WINE_DEFAULT_DEBUG_CHANNEL(stobject);
16
17 const GUID CLSID_SysTray = { 0x35CEC8A3, 0x2BE6, 0x11D2, { 0x87, 0x73, 0x92, 0xE2, 0x20, 0x52, 0x41, 0x53 } };
18
19 HINSTANCE g_hInstance;
20
21 typedef HRESULT(STDMETHODCALLTYPE * PFNSTINIT) (_In_ CSysTray * pSysTray);
22 typedef HRESULT(STDMETHODCALLTYPE * PFNSTSHUTDOWN) (_In_ CSysTray * pSysTray);
23 typedef HRESULT(STDMETHODCALLTYPE * PFNSTUPDATE) (_In_ CSysTray * pSysTray);
24 typedef HRESULT(STDMETHODCALLTYPE * PFNSTMESSAGE) (_In_ CSysTray * pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam);
25
26 struct SysTrayIconHandlers_t
27 {
28 PFNSTINIT pfnInit;
29 PFNSTSHUTDOWN pfnShutdown;
30 PFNSTUPDATE pfnUpdate;
31 PFNSTMESSAGE pfnMessage;
32 };
33
34 SysTrayIconHandlers_t g_IconHandlers [] = {
35 { Volume_Init, Volume_Shutdown, Volume_Update, Volume_Message }
36 };
37 const int g_NumIcons = _countof(g_IconHandlers);
38
39 HRESULT CSysTray::InitIcons()
40 {
41 for (int i = 0; i < g_NumIcons; i++)
42 {
43 HRESULT hr = g_IconHandlers[i].pfnInit(this);
44 if (FAILED(hr))
45 return hr;
46 }
47
48 return S_OK;
49 }
50
51 HRESULT CSysTray::ShutdownIcons()
52 {
53 for (int i = 0; i < g_NumIcons; i++)
54 {
55 HRESULT hr = g_IconHandlers[i].pfnShutdown(this);
56 if (FAILED(hr))
57 return hr;
58 }
59
60 return S_OK;
61 }
62
63 HRESULT CSysTray::UpdateIcons()
64 {
65 for (int i = 0; i < g_NumIcons; i++)
66 {
67 HRESULT hr = g_IconHandlers[i].pfnUpdate(this);
68 if (FAILED(hr))
69 return hr;
70 }
71
72 return S_OK;
73 }
74
75 HRESULT CSysTray::ProcessIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
76 {
77 for (int i = 0; i < g_NumIcons; i++)
78 {
79 HRESULT hr = g_IconHandlers[i].pfnMessage(this, uMsg, wParam, lParam);
80 if (FAILED(hr))
81 return hr;
82
83 if (hr != S_FALSE)
84 return hr;
85 }
86
87 return S_OK;
88 }
89
90 HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip)
91 {
92 NOTIFYICONDATA nim;
93 nim.cbSize = sizeof(NOTIFYICONDATA);
94 nim.uFlags = NIF_ICON | NIF_STATE | NIF_TIP;
95 nim.hIcon = hIcon;
96 nim.uID = uId;
97 nim.uCallbackMessage = uId;
98 nim.dwState = 0;
99 nim.dwStateMask = 0;
100 nim.hWnd = m_hWnd;
101 nim.uVersion = NOTIFYICON_VERSION;
102 if (szTip)
103 StringCchCopy(nim.szTip, _countof(nim.szTip), szTip);
104 else
105 nim.szTip[0] = 0;
106 BOOL ret = Shell_NotifyIcon(code, &nim);
107 return ret ? S_OK : E_FAIL;
108 }
109
110 DWORD WINAPI CSysTray::s_SysTrayThreadProc(PVOID param)
111 {
112 CSysTray * st = (CSysTray*) param;
113 return st->SysTrayThreadProc();
114 }
115
116 HRESULT CSysTray::SysTrayMessageLoop()
117 {
118 BOOL ret;
119 MSG msg;
120
121 while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
122 {
123 if (ret < 0)
124 break;
125
126 TranslateMessage(&msg);
127 DispatchMessage(&msg);
128 }
129
130 return S_OK;
131 }
132
133 HRESULT CSysTray::SysTrayThreadProc()
134 {
135 WCHAR strFileName[MAX_PATH];
136 GetModuleFileNameW(g_hInstance, strFileName, MAX_PATH);
137 HMODULE hLib = LoadLibraryW(strFileName);
138
139 CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
140
141 Create(NULL);
142
143 HRESULT ret = SysTrayMessageLoop();
144
145 CoUninitialize();
146
147 FreeLibraryAndExitThread(hLib, ret);
148 }
149
150 HRESULT CSysTray::CreateSysTrayThread()
151 {
152 DbgPrint("CSysTray Init TODO: Initialize tray icon handlers.\n");
153
154 HANDLE hThread = CreateThread(NULL, 0, s_SysTrayThreadProc, this, 0, NULL);
155
156 CloseHandle(hThread);
157
158 return S_OK;
159 }
160
161 HRESULT CSysTray::DestroySysTrayWindow()
162 {
163 DestroyWindow();
164 hwndSysTray = NULL;
165 return S_OK;
166 }
167
168 CSysTray::CSysTray() {}
169 CSysTray::~CSysTray() {}
170
171 // *** IOleCommandTarget methods ***
172 HRESULT STDMETHODCALLTYPE CSysTray::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
173 {
174 UNIMPLEMENTED;
175 return S_OK;
176 }
177
178 HRESULT STDMETHODCALLTYPE CSysTray::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
179 {
180 if (!IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
181 return E_FAIL;
182
183 switch (nCmdID)
184 {
185 case OLECMDID_NEW: // init
186 return CreateSysTrayThread();
187 case OLECMDID_SAVE: // shutdown
188 return DestroySysTrayWindow();
189 }
190 return S_OK;
191 }
192
193 BOOL CSysTray::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD dwMsgMapID)
194 {
195 HRESULT hr;
196
197 if (hWnd != m_hWnd)
198 return FALSE;
199
200 switch (uMsg)
201 {
202 case WM_CREATE:
203 InitIcons();
204 SetTimer(1, 2000, NULL);
205 return TRUE;
206 case WM_TIMER:
207 UpdateIcons();
208 return TRUE;
209 case WM_DESTROY:
210 ShutdownIcons();
211 return TRUE;
212 }
213
214 DbgPrint("SysTray message received %u (%08p %08p)\n", uMsg, wParam, lParam);
215
216 hr = ProcessIconMessage(uMsg, wParam, lParam);
217 if (FAILED(hr))
218 return FALSE;
219
220 if (hr == S_FALSE)
221 return FALSE;
222
223 return TRUE;
224 }
225
226 BEGIN_OBJECT_MAP(ObjectMap)
227 OBJECT_ENTRY(CLSID_SysTray, CSysTray)
228 END_OBJECT_MAP()
229
230 class CShellTrayModule : public CComModule
231 {
232 };
233
234 CShellTrayModule gModule;
235
236
237 HRESULT RegisterShellServiceObject(REFGUID guidClass, LPCWSTR lpName, BOOL bRegister)
238 {
239 const LPCWSTR strRegistryLocation = L"Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad";
240
241 OLECHAR strGuid[128]; // shouldn't need so much!
242 LSTATUS ret = 0;
243 HKEY hKey = 0;
244 if (StringFromGUID2(guidClass, strGuid, 128))
245 {
246 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, strRegistryLocation, 0, KEY_WRITE, &hKey))
247 {
248 if (bRegister)
249 {
250 LONG cbGuid = (lstrlenW(strGuid) + 1) * 2;
251 ret = RegSetValueExW(hKey, lpName, 0, REG_SZ, (const BYTE *) strGuid, cbGuid);
252 }
253 else
254 {
255 ret = RegDeleteValueW(hKey, lpName);
256 }
257 }
258 }
259 if (hKey)
260 RegCloseKey(hKey);
261 return /*HRESULT_FROM_NT*/(ret); // regsvr32 considers anything != S_OK to be an error
262
263 }
264
265 void *operator new (size_t, void *buf)
266 {
267 return buf;
268 }
269
270 BOOL
271 WINAPI
272 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
273 {
274 if (fdwReason == DLL_PROCESS_ATTACH)
275 {
276 /* HACK - the global constructors don't run, so I placement new them here */
277 new (&gModule) CShellTrayModule;
278 new (&_AtlWinModule) CAtlWinModule;
279 new (&_AtlBaseModule) CAtlBaseModule;
280 new (&_AtlComModule) CAtlComModule;
281
282 g_hInstance = hinstDLL;
283 DisableThreadLibraryCalls(g_hInstance);
284
285 gModule.Init(ObjectMap, g_hInstance, NULL);
286 }
287 else if (fdwReason == DLL_PROCESS_DETACH)
288 {
289 g_hInstance = NULL;
290 gModule.Term();
291 }
292 return TRUE;
293 }
294
295 HRESULT
296 WINAPI
297 DllCanUnloadNow(void)
298 {
299 return gModule.DllCanUnloadNow();
300 }
301
302 STDAPI
303 DllRegisterServer(void)
304 {
305 HRESULT hr = gModule.DllRegisterServer(FALSE);
306 if (FAILED(hr))
307 return hr;
308
309 return RegisterShellServiceObject(CLSID_SysTray, L"SysTray", TRUE);
310 }
311
312 STDAPI
313 DllUnregisterServer(void)
314 {
315 RegisterShellServiceObject(CLSID_SysTray, L"SysTray", FALSE);
316
317 return gModule.DllUnregisterServer(FALSE);
318 }
319
320 STDAPI
321 DllGetClassObject(
322 REFCLSID rclsid,
323 REFIID riid,
324 LPVOID *ppv)
325 {
326 return gModule.DllGetClassObject(rclsid, riid, ppv);
327 }