ReactOS 0.4.16-dev-1097-g530d26a
hotplug.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS system libraries
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/shellext/stobject/hotplug.cpp
5 * PURPOSE: Removable devices notification icon handler
6 * PROGRAMMERS: Shriraj Sawant a.k.a SR13 <sr.official@hotmail.com>
7 */
8
9#include "precomp.h"
10
11#include <atlsimpcoll.h>
12#include <dbt.h>
13#include <cfgmgr32.h>
14#include <shlwapi.h>
15
16#define DISPLAY_NAME_LEN 40
17
23
24/*++
25* @name EnumHotpluggedDevices
26*
27* Enumerates the connected safely removable devices.
28*
29* @param devList
30* List of device instances, representing the currently attached devices.
31*
32* @return The error code.
33*
34*--*/
36{
37 devList.RemoveAll(); // Clear current devList
40 return E_HANDLE;
41 SP_DEVINFO_DATA did = { 0 };
42 did.cbSize = sizeof(did);
43
44 // Enumerate all the attached devices.
45 for (int idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++)
46 {
47 DWORD dwCapabilities = 0, dwSize = sizeof(dwCapabilities);
48 ULONG ulStatus = 0, ulProblem = 0;
49 CONFIGRET cr = CM_Get_DevNode_Status(&ulStatus, &ulProblem, did.DevInst, 0);
50 if (cr != CR_SUCCESS)
51 continue;
52
54 if (cr != CR_SUCCESS)
55 continue;
56
57 // Filter and make list of only the appropriate safely removable devices.
58 if ( (dwCapabilities & CM_DEVCAP_REMOVABLE) &&
59 !(dwCapabilities & CM_DEVCAP_DOCKDEVICE) &&
60 !(dwCapabilities & CM_DEVCAP_SURPRISEREMOVALOK) &&
61 ((dwCapabilities & CM_DEVCAP_EJECTSUPPORTED) || (ulStatus & DN_DISABLEABLE)) &&
62 !ulProblem)
63 {
64 devList.Add(did.DevInst);
65 }
66 }
68
70 {
71 return E_UNEXPECTED;
72 }
73
74 return S_OK;
75}
76
77/*++
78* @name NotifyBalloon
79*
80* Pops the balloon notification of the given notification icon.
81*
82* @param pSysTray
83* Provides interface for acquiring CSysTray information as required.
84* @param szTitle
85* Title for the balloon notification.
86* @param szInfo
87* Main content for the balloon notification.
88* @param uId
89* Represents the particular notification icon.
90*
91* @return The error code.
92*
93*--*/
95{
96 NOTIFYICONDATA nim = { 0 };
97
98 nim.cbSize = sizeof(nim);
99 nim.uID = uId;
100 nim.hWnd = pSysTray->GetHWnd();
101
102 nim.uFlags = NIF_INFO;
103 nim.uTimeout = 10;
104 nim.dwInfoFlags = NIIF_INFO;
105
107 StringCchCopy(nim.szInfo, _countof(nim.szInfo), szInfo);
109
110 Sleep(10000); /* As per windows, the balloon notification remains visible for atleast 10 sec.
111 This timer maintains the same condition.
112 Also it is required so that the icon doesn't hide instantly after last device is removed,
113 as that will prevent popping of notification.
114 */
116 StringCchCopy(nim.szInfo, _countof(nim.szInfo), L"");
118 g_IsRemoving = FALSE; /* This flag is used to prevent instant icon hiding after last device is removed.
119 The above timer maintains the required state for the same.
120 */
121 return ret ? S_OK : E_FAIL;
122}
123
125{
126 TRACE("Hotplug_Init\n");
127
130
132
133 if (g_devList.GetSize() > 0)
134 return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, g_strHotplugTooltip);
135 else
136 return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, g_strHotplugTooltip, NIS_HIDDEN);
137}
138
140{
141 TRACE("Hotplug_Update\n");
142 return S_OK;
143}
144
146{
147 TRACE("Hotplug_Shutdown\n");
148
151
152 return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_HOTPLUG, NULL, NULL);
153}
154
155static void _RunHotplug(CSysTray * pSysTray)
156{
157 pSysTray->RunDll("hotplug.dll", "");
158}
159
160static void _ShowContextMenu(CSysTray * pSysTray)
161{
162 HMENU hPopup = CreatePopupMenu();
163 ULONG ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
164
165 for (INT index = 0; index < g_devList.GetSize(); index++)
166 {
167 WCHAR dispName[DISPLAY_NAME_LEN];
168 CString menuName;
170 if (cr != CR_SUCCESS)
171 StrCpyW(dispName, L"Unknown Device");
172
173 menuName.Format(IDS_HOTPLUG_REMOVE_3, dispName);
174 AppendMenuW(hPopup, MF_STRING, index+1, menuName);
175 }
176
177 SetForegroundWindow(pSysTray->GetHWnd());
179 POINT pt;
181
182 DWORD id = TrackPopupMenuEx(hPopup, flags,
183 pt.x, pt.y,
184 pSysTray->GetHWnd(), NULL);
185
186 if (id > 0)
187 {
188 id--; // since array indices starts from zero.
190 if (cr != CR_SUCCESS)
191 StrCpyW(g_strMenuSel, L"Unknown Device");
192
193 cr = CM_Request_Device_Eject_Ex(g_devList[id], 0, 0, 0, 0, 0);
194 if (cr != CR_SUCCESS)
195 {
196 WCHAR strInfo[128];
197 swprintf(strInfo, L"Problem Ejecting %wS", g_strMenuSel);
198 MessageBox(0, L"The device cannot be stopped right now! Try stopping it again later!", strInfo, MB_OK | MB_ICONEXCLAMATION);
199 }
200 else
201 {
202 //MessageBox(0, L"Device ejected successfully!! You can safely remove the device now!", L"Safely Remove Hardware", MB_OK | MB_ICONINFORMATION);
204 g_devList.RemoveAt(id); /* thing is.. even after removing id at this point, the devnode_change occurs after some seconds of sucessful removal
205 and since pendrive is still plugged in it gets enumerated, if problem number is not filtered.
206 */
207 }
208 }
209
210 DestroyMenu(hPopup);
211}
212
213static void _ShowContextMenuR(CSysTray * pSysTray)
214{
216 HMENU hPopup = CreatePopupMenu();
217 AppendMenuW(hPopup, MF_STRING, IDS_HOTPLUG_REMOVE_2, strMenu);
219
220 SetForegroundWindow(pSysTray->GetHWnd());
222 POINT pt;
224
225 DWORD id = TrackPopupMenuEx(hPopup, flags,
226 pt.x, pt.y,
227 pSysTray->GetHWnd(), NULL);
228
229 if (id == IDS_HOTPLUG_REMOVE_2)
230 {
231 _RunHotplug(pSysTray);
232 }
233
234 DestroyMenu(hPopup);
235}
236
237
238VOID
240 _In_ CSysTray *pSysTray)
241{
242 TRACE("HotplugDeviceTimer()\n");
243
245
246 if (g_devList.GetSize() > 0)
248 else
249 pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, g_hIconHotplug, g_strHotplugTooltip, NIS_HIDDEN);
250}
251
252
254{
255 TRACE("Hotplug_Message uMsg=%d, wParam=%x, lParam=%x\n", uMsg, wParam, lParam);
256
257 switch (uMsg)
258 {
259 case WM_USER + 220:
260 TRACE("Hotplug_Message: WM_USER+220\n");
262 {
263 if (lParam)
264 {
265 pSysTray->EnableService(HOTPLUG_SERVICE_FLAG, TRUE);
266 return Hotplug_Init(pSysTray);
267 }
268 else
269 {
270 pSysTray->EnableService(HOTPLUG_SERVICE_FLAG, FALSE);
271 return Hotplug_Shutdown(pSysTray);
272 }
273 }
274 return S_FALSE;
275
276 case WM_USER + 221:
277 TRACE("Hotplug_Message: WM_USER+221\n");
279 {
280 lResult = (LRESULT)pSysTray->IsServiceEnabled(HOTPLUG_SERVICE_FLAG);
281 return S_OK;
282 }
283 return S_FALSE;
284
285 case WM_TIMER:
287 {
288 KillTimer(pSysTray->GetHWnd(), HOTPLUG_TIMER_ID);
289 _ShowContextMenu(pSysTray);
290 }
292 {
293 KillTimer(pSysTray->GetHWnd(), HOTPLUG_DEVICE_TIMER_ID);
294 HotplugDeviceTimer(pSysTray);
295 }
296 break;
297
298 case ID_ICON_HOTPLUG:
299 switch (lParam)
300 {
301 case WM_LBUTTONDOWN:
302 SetTimer(pSysTray->GetHWnd(), HOTPLUG_TIMER_ID, GetDoubleClickTime(), NULL);
303 break;
304
305 case WM_LBUTTONUP:
306 break;
307
308 case WM_LBUTTONDBLCLK:
309 KillTimer(pSysTray->GetHWnd(), HOTPLUG_TIMER_ID);
310 _RunHotplug(pSysTray);
311 break;
312
313 case WM_RBUTTONDOWN:
314 break;
315
316 case WM_RBUTTONUP:
317 _ShowContextMenuR(pSysTray);
318 break;
319
320 case WM_RBUTTONDBLCLK:
321 break;
322
323 case WM_MOUSEMOVE:
324 break;
325 }
326 return S_OK;
327
328 case WM_DEVICECHANGE:
329 switch (wParam)
330 {
332 TRACE("WM_DEVICECHANGE : DBT_DEVNODES_CHANGED\n");
333 SetTimer(pSysTray->GetHWnd(), HOTPLUG_DEVICE_TIMER_ID, 100, NULL);
334 lResult = true;
335 break;
336
338 break;
340 break;
342 break;
344 WCHAR strInfo[128];
345 swprintf(strInfo, L"The %wS can now be safely removed from the system.", g_strMenuSel);
346 NotifyBalloon(pSysTray, L"Safe to Remove Hardware", strInfo);
347
348 lResult = true;
349 break;
351 break;
352 }
353 return S_OK;
354
355 default:
356 TRACE("Hotplug_Message received for unknown ID %d, ignoring.\n");
357 return S_FALSE;
358 }
359
360 return S_FALSE;
361}
HINSTANCE g_hInstance
Definition: MainWindow.cpp:18
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
#define DN_DISABLEABLE
Definition: cfg.h:131
#define CM_DEVCAP_EJECTSUPPORTED
Definition: cfgmgr32.h:736
#define CM_DRP_CAPABILITIES
Definition: cfgmgr32.h:691
#define CM_DRP_DEVICEDESC
Definition: cfgmgr32.h:676
#define CM_Get_DevNode_Registry_Property
Definition: cfgmgr32.h:1733
#define CM_Request_Device_Eject_Ex
Definition: cfgmgr32.h:2878
#define CM_DEVCAP_SURPRISEREMOVALOK
Definition: cfgmgr32.h:742
#define CM_DEVCAP_DOCKDEVICE
Definition: cfgmgr32.h:738
#define CM_DEVCAP_REMOVABLE
Definition: cfgmgr32.h:737
RETURN_TYPE CONFIGRET
Definition: cfgmgr32.h:74
#define CR_SUCCESS
Definition: cfgmgr32.h:842
CONFIGRET WINAPI CM_Get_DevNode_Status(_Out_ PULONG pulStatus, _Out_ PULONG pulProblemNumber, _In_ DEVINST dnDevInst, _In_ ULONG ulFlags)
Definition: cfgmgr.c:3665
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:818
HWND GetHWnd()
Definition: csystray.h:54
static void RunDll(PCSTR Dll, PCSTR Parameters)
Definition: csystray.cpp:413
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define DBT_DEVICEREMOVEPENDING
Definition: dbt.h:15
#define DBT_DEVNODES_CHANGED
Definition: dbt.h:28
#define DBT_DEVICEQUERYREMOVE
Definition: dbt.h:13
#define DBT_DEVICEARRIVAL
Definition: dbt.h:12
#define DBT_DEVICEREMOVECOMPLETE
Definition: dbt.h:16
#define DBT_DEVICEQUERYREMOVEFAILED
Definition: dbt.h:14
#define NO_ERROR
Definition: dderror.h:5
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define HOTPLUG_TIMER_ID
Definition: precomp.h:94
#define HOTPLUG_SERVICE_FLAG
Definition: precomp.h:39
#define ID_ICON_HOTPLUG
Definition: precomp.h:34
#define HOTPLUG_DEVICE_TIMER_ID
Definition: precomp.h:95
#define IDS_HOTPLUG_REMOVE_1
Definition: resource.h:19
#define IDI_HOTPLUG_OK
Definition: resource.h:58
#define IDS_HOTPLUG_REMOVE_2
Definition: resource.h:20
#define IDS_HOTPLUG_REMOVE_3
Definition: resource.h:21
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
BOOL WINAPI SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, PSP_DEVINFO_DATA info)
Definition: devinst.c:1787
BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
Definition: devinst.c:2893
LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
Definition: string.c:514
#define swprintf
Definition: precomp.h:40
#define pt(x, y)
Definition: drawing.c:79
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint index
Definition: glext.h:6031
GLbitfield flags
Definition: glext.h:7161
HRESULT NotifyBalloon(CSysTray *pSysTray, LPCWSTR szTitle=NULL, LPCWSTR szInfo=NULL, UINT uId=ID_ICON_HOTPLUG)
Definition: hotplug.cpp:94
HRESULT STDMETHODCALLTYPE Hotplug_Init(_In_ CSysTray *pSysTray)
Definition: hotplug.cpp:124
HRESULT EnumHotpluggedDevices(CSimpleArray< DEVINST > &devList)
Definition: hotplug.cpp:35
HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray *pSysTray)
Definition: hotplug.cpp:145
#define DISPLAY_NAME_LEN
Definition: hotplug.cpp:16
HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray *pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
Definition: hotplug.cpp:253
static BOOL g_IsRemoving
Definition: hotplug.cpp:22
VOID HotplugDeviceTimer(_In_ CSysTray *pSysTray)
Definition: hotplug.cpp:239
static WCHAR g_strMenuSel[DISPLAY_NAME_LEN]
Definition: hotplug.cpp:21
static HICON g_hIconHotplug
Definition: hotplug.cpp:20
HRESULT STDMETHODCALLTYPE Hotplug_Update(_In_ CSysTray *pSysTray)
Definition: hotplug.cpp:139
static void _ShowContextMenuR(CSysTray *pSysTray)
Definition: hotplug.cpp:213
CSimpleArray< DEVINST > g_devList
Definition: hotplug.cpp:18
CString g_strHotplugTooltip
Definition: hotplug.cpp:19
static void _RunHotplug(CSysTray *pSysTray)
Definition: hotplug.cpp:155
static void _ShowContextMenu(CSysTray *pSysTray)
Definition: hotplug.cpp:160
#define S_OK
Definition: intsafe.h:52
TCHAR szTitle[MAX_LOADSTRING]
Definition: magnifier.c:35
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static HICON
Definition: imagelist.c:80
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
unsigned int UINT
Definition: ndis.h:50
#define _In_
Definition: no_sal2.h:158
#define L(x)
Definition: ntvdm.h:50
#define MAKEINTRESOURCE(i)
Definition: ntverrsrc.c:25
#define LRESULT
Definition: ole.h:14
#define DIGCF_ALLCLASSES
Definition: setupapi.h:173
#define SetupDiGetClassDevs
Definition: setupapi.h:2594
#define DIGCF_PRESENT
Definition: setupapi.h:172
#define NIM_DELETE
Definition: shellapi.h:97
#define NIM_MODIFY
Definition: shellapi.h:96
#define NIM_ADD
Definition: shellapi.h:95
#define Shell_NotifyIcon
Definition: shellapi.h:731
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
#define StringCchCopy
Definition: strsafe.h:139
CHAR szInfoTitle[64]
Definition: shellapi.h:246
CHAR szInfo[256]
Definition: shellapi.h:241
DWORD dwInfoFlags
Definition: shellapi.h:247
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
int ret
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ HDEV hdev
Definition: winddi.h:3449
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define S_FALSE
Definition: winerror.h:2357
#define E_HANDLE
Definition: winerror.h:2850
#define E_UNEXPECTED
Definition: winerror.h:2456
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
BOOL WINAPI SetMenuDefaultItem(_In_ HMENU, _In_ UINT, _In_ UINT)
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1789
#define TPM_BOTTOMALIGN
Definition: winuser.h:2396
#define MF_STRING
Definition: winuser.h:138
BOOL WINAPI SetForegroundWindow(_In_ HWND)
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:3032
#define WM_RBUTTONUP
Definition: winuser.h:1791
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1792
#define WM_MOUSEMOVE
Definition: winuser.h:1786
#define TPM_RIGHTALIGN
Definition: winuser.h:2389
#define TPM_NONOTIFY
Definition: winuser.h:2397
#define WM_LBUTTONDOWN
Definition: winuser.h:1787
#define WM_DEVICECHANGE
Definition: winuser.h:1822
BOOL WINAPI TrackPopupMenuEx(_In_ HMENU, _In_ UINT, _In_ int, _In_ int, _In_ HWND, _In_opt_ LPTPMPARAMS)
UINT WINAPI GetDoubleClickTime(void)
Definition: ntwrapper.h:314
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_RBUTTONDOWN
Definition: winuser.h:1790
#define WM_TIMER
Definition: winuser.h:1753
#define LoadIcon
Definition: winuser.h:5833
#define MB_ICONEXCLAMATION
Definition: winuser.h:796
#define MB_OK
Definition: winuser.h:801
#define WM_LBUTTONUP
Definition: winuser.h:1788
BOOL WINAPI DestroyMenu(_In_ HMENU)
#define MessageBox
Definition: winuser.h:5842
#define WM_USER
Definition: winuser.h:1906
#define TPM_RETURNCMD
Definition: winuser.h:2398
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
BOOL WINAPI AppendMenuW(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
BOOL WINAPI DestroyIcon(_In_ HICON)
Definition: cursoricon.c:2390
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185