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>
15 WINE_DEFAULT_DEBUG_CHANNEL(stobject
);
17 const GUID CLSID_SysTray
= { 0x35CEC8A3, 0x2BE6, 0x11D2, { 0x87, 0x73, 0x92, 0xE2, 0x20, 0x52, 0x41, 0x53 } };
19 HINSTANCE g_hInstance
;
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
);
26 struct SysTrayIconHandlers_t
29 PFNSTSHUTDOWN pfnShutdown
;
30 PFNSTUPDATE pfnUpdate
;
31 PFNSTMESSAGE pfnMessage
;
34 SysTrayIconHandlers_t g_IconHandlers
[] = {
35 { Volume_Init
, Volume_Shutdown
, Volume_Update
, Volume_Message
}
37 const int g_NumIcons
= _countof(g_IconHandlers
);
39 HRESULT
CSysTray::InitIcons()
41 for (int i
= 0; i
< g_NumIcons
; i
++)
43 HRESULT hr
= g_IconHandlers
[i
].pfnInit(this);
51 HRESULT
CSysTray::ShutdownIcons()
53 for (int i
= 0; i
< g_NumIcons
; i
++)
55 HRESULT hr
= g_IconHandlers
[i
].pfnShutdown(this);
63 HRESULT
CSysTray::UpdateIcons()
65 for (int i
= 0; i
< g_NumIcons
; i
++)
67 HRESULT hr
= g_IconHandlers
[i
].pfnUpdate(this);
75 HRESULT
CSysTray::ProcessIconMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
77 for (int i
= 0; i
< g_NumIcons
; i
++)
79 HRESULT hr
= g_IconHandlers
[i
].pfnMessage(this, uMsg
, wParam
, lParam
);
90 HRESULT
CSysTray::NotifyIcon(INT code
, UINT uId
, HICON hIcon
, LPCWSTR szTip
)
93 nim
.cbSize
= sizeof(NOTIFYICONDATA
);
94 nim
.uFlags
= NIF_ICON
| NIF_STATE
| NIF_TIP
;
97 nim
.uCallbackMessage
= uId
;
101 nim
.uVersion
= NOTIFYICON_VERSION
;
103 StringCchCopy(nim
.szTip
, _countof(nim
.szTip
), szTip
);
106 BOOL ret
= Shell_NotifyIcon(code
, &nim
);
107 return ret
? S_OK
: E_FAIL
;
110 DWORD WINAPI
CSysTray::s_SysTrayThreadProc(PVOID param
)
112 CSysTray
* st
= (CSysTray
*) param
;
113 return st
->SysTrayThreadProc();
116 HRESULT
CSysTray::SysTrayMessageLoop()
121 while ((ret
= GetMessage(&msg
, NULL
, 0, 0)) != 0)
126 TranslateMessage(&msg
);
127 DispatchMessage(&msg
);
133 HRESULT
CSysTray::SysTrayThreadProc()
135 WCHAR strFileName
[MAX_PATH
];
136 GetModuleFileNameW(g_hInstance
, strFileName
, MAX_PATH
);
137 HMODULE hLib
= LoadLibraryW(strFileName
);
139 CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
| COINIT_APARTMENTTHREADED
);
143 HRESULT ret
= SysTrayMessageLoop();
147 FreeLibraryAndExitThread(hLib
, ret
);
150 HRESULT
CSysTray::CreateSysTrayThread()
152 DbgPrint("CSysTray Init TODO: Initialize tray icon handlers.\n");
154 HANDLE hThread
= CreateThread(NULL
, 0, s_SysTrayThreadProc
, this, 0, NULL
);
156 CloseHandle(hThread
);
161 HRESULT
CSysTray::DestroySysTrayWindow()
168 CSysTray::CSysTray() {}
169 CSysTray::~CSysTray() {}
171 // *** IOleCommandTarget methods ***
172 HRESULT STDMETHODCALLTYPE
CSysTray::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
178 HRESULT STDMETHODCALLTYPE
CSysTray::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
180 if (!IsEqualGUID(*pguidCmdGroup
, CGID_ShellServiceObject
))
185 case OLECMDID_NEW
: // init
186 return CreateSysTrayThread();
187 case OLECMDID_SAVE
: // shutdown
188 return DestroySysTrayWindow();
193 BOOL
CSysTray::ProcessWindowMessage(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
&lResult
, DWORD dwMsgMapID
)
204 SetTimer(1, 2000, NULL
);
214 DbgPrint("SysTray message received %u (%08p %08p)\n", uMsg
, wParam
, lParam
);
216 hr
= ProcessIconMessage(uMsg
, wParam
, lParam
);
226 BEGIN_OBJECT_MAP(ObjectMap
)
227 OBJECT_ENTRY(CLSID_SysTray
, CSysTray
)
230 class CShellTrayModule
: public CComModule
234 CShellTrayModule gModule
;
237 HRESULT
RegisterShellServiceObject(REFGUID guidClass
, LPCWSTR lpName
, BOOL bRegister
)
239 const LPCWSTR strRegistryLocation
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad";
241 OLECHAR strGuid
[128]; // shouldn't need so much!
244 if (StringFromGUID2(guidClass
, strGuid
, 128))
246 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, strRegistryLocation
, 0, KEY_WRITE
, &hKey
))
250 LONG cbGuid
= (lstrlenW(strGuid
) + 1) * 2;
251 ret
= RegSetValueExW(hKey
, lpName
, 0, REG_SZ
, (const BYTE
*) strGuid
, cbGuid
);
255 ret
= RegDeleteValueW(hKey
, lpName
);
261 return /*HRESULT_FROM_NT*/(ret
); // regsvr32 considers anything != S_OK to be an error
265 void *operator new (size_t, void *buf
)
272 DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
274 if (fdwReason
== DLL_PROCESS_ATTACH
)
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
;
282 g_hInstance
= hinstDLL
;
283 DisableThreadLibraryCalls(g_hInstance
);
285 gModule
.Init(ObjectMap
, g_hInstance
, NULL
);
287 else if (fdwReason
== DLL_PROCESS_DETACH
)
297 DllCanUnloadNow(void)
299 return gModule
.DllCanUnloadNow();
303 DllRegisterServer(void)
305 HRESULT hr
= gModule
.DllRegisterServer(FALSE
);
309 return RegisterShellServiceObject(CLSID_SysTray
, L
"SysTray", TRUE
);
313 DllUnregisterServer(void)
315 RegisterShellServiceObject(CLSID_SysTray
, L
"SysTray", FALSE
);
317 return gModule
.DllUnregisterServer(FALSE
);
326 return gModule
.DllGetClassObject(rclsid
, riid
, ppv
);