diff --git a/reactos/dll/shellext/stobject/csystray.cpp b/reactos/dll/shellext/stobject/csystray.cpp index 41ddbb5f8cc..31a7f183230 100644 --- a/reactos/dll/shellext/stobject/csystray.cpp +++ b/reactos/dll/shellext/stobject/csystray.cpp @@ -4,6 +4,7 @@ * FILE: dll/shellext/stobject/csystray.cpp * PURPOSE: Systray shell service object implementation * PROGRAMMERS: David Quintana +* Shriraj Sawant a.k.a SR13 */ #include "precomp.h" @@ -97,7 +98,7 @@ HRESULT CSysTray::ProcessIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, LR return S_FALSE; } -HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip) +HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, DWORD dwstate) { NOTIFYICONDATA nim = { 0 }; @@ -108,8 +109,8 @@ HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip) nim.hIcon = hIcon; nim.uID = uId; nim.uCallbackMessage = uId; - nim.dwState = 0; - nim.dwStateMask = 0; + nim.dwState = dwstate; + nim.dwStateMask = NIS_HIDDEN; nim.hWnd = m_hWnd; nim.uVersion = NOTIFYICON_VERSION; if (szTip) diff --git a/reactos/dll/shellext/stobject/csystray.h b/reactos/dll/shellext/stobject/csystray.h index 04f7c1e2920..b95cd65577f 100644 --- a/reactos/dll/shellext/stobject/csystray.h +++ b/reactos/dll/shellext/stobject/csystray.h @@ -5,6 +5,7 @@ * PURPOSE: Systray shell service object * PROGRAMMERS: Robert Naumann * David Quintana + * Shriraj Sawant a.k.a SR13 */ #pragma once @@ -43,7 +44,7 @@ class CSysTray : HRESULT ShutdownNetShell(); public: - HRESULT NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip); + HRESULT NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, DWORD dwstate = 0); HWND GetHWnd() { return m_hWnd; } diff --git a/reactos/dll/shellext/stobject/hotplug.cpp b/reactos/dll/shellext/stobject/hotplug.cpp index 230940b6caf..9ef5bdcc459 100644 --- a/reactos/dll/shellext/stobject/hotplug.cpp +++ b/reactos/dll/shellext/stobject/hotplug.cpp @@ -5,33 +5,87 @@ * PURPOSE: Removable devices notification icon handler * PROGRAMMERS: Shriraj Sawant a.k.a SR13 */ - +#include #include "precomp.h" #include #include #include +#include +#include +#include +#include WINE_DEFAULT_DEBUG_CHANNEL(stobject); +#define DISPLAY_NAME_LEN 40 +//BOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); + +CSimpleArray g_devList; +static HDEVNOTIFY g_hDevNotify = NULL; static HICON g_hIconHotplug = NULL; static LPWSTR g_strTooltip = L"Safely Remove Hardware and Eject Media"; static BOOL g_IsRunning = FALSE; +static BOOL g_IsRemoved = FALSE; + +// Enumerate the connected removable devices +// TODO: Require proper enumeration and filters. +HRESULT EnumHotpluggedDevices(CSimpleArray &devList) +{ + devList.RemoveAll(); // Clear current devList + HDEVINFO hdev = SetupDiGetClassDevs(NULL, NULL, 0, DIGCF_ALLCLASSES | DIGCF_PRESENT); + if (INVALID_HANDLE_VALUE == hdev) + return E_HANDLE; + SP_DEVINFO_DATA did = { 0 }; + did.cbSize = sizeof(did); + + for (int idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++) + { + DWORD dwCapabilities = 0, dwSize = sizeof(dwCapabilities); + WCHAR dispName[DISPLAY_NAME_LEN]; + ULONG ulStatus = 0, ulPnum = 0, ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR); + CONFIGRET cr = CM_Get_DevNode_Status(&ulStatus, &ulPnum, did.DevInst, 0); + if (cr != CR_SUCCESS) + continue; + cr = CM_Get_DevNode_Registry_Property(did.DevInst, CM_DRP_DEVICEDESC, NULL, dispName, &ulLength, 0); + if (cr != CR_SUCCESS) + continue; + cr = CM_Get_DevNode_Registry_Property(did.DevInst, CM_DRP_CAPABILITIES, NULL, &dwCapabilities, &dwSize, 0); + if (cr != CR_SUCCESS) + continue; + + if ((dwCapabilities & CM_DEVCAP_REMOVABLE) && (dwCapabilities & CM_DEVCAP_UNIQUEID)) + { + devList.Add(did.DevInst); + } + } + SetupDiDestroyDeviceInfoList(hdev); + + if (NO_ERROR != GetLastError() && ERROR_NO_MORE_ITEMS != GetLastError()) + { + return E_UNEXPECTED; + } + + return S_OK; +} HRESULT STDMETHODCALLTYPE Hotplug_Init(_In_ CSysTray * pSysTray) { TRACE("Hotplug_Init\n"); - g_hIconHotplug = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EXTRACT)); + g_hIconHotplug = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_HOTPLUG_OK)); g_IsRunning = TRUE; + EnumHotpluggedDevices(g_devList); - return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, g_strTooltip); + return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, g_strTooltip, NIS_HIDDEN); } HRESULT STDMETHODCALLTYPE Hotplug_Update(_In_ CSysTray * pSysTray) { TRACE("Hotplug_Update\n"); - //g_hIconHotplug = DynamicLoadIcon(g_hInstance); - - return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, g_hIconHotplug, g_strTooltip); + + if(g_devList.GetSize()) + return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, g_hIconHotplug, g_strTooltip); + else + return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, g_hIconHotplug, g_strTooltip, NIS_HIDDEN); } HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray * pSysTray) @@ -42,16 +96,26 @@ HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray * pSysTray) return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_HOTPLUG, NULL, NULL); } -static void _RunHotplug() +static void _RunHotplug(CSysTray * pSysTray) { - ShellExecuteW(NULL, NULL, L"hotplug.cpl", NULL, NULL, SW_SHOWNORMAL); + ShellExecuteW(pSysTray->GetHWnd(), L"open", L"rundll32.exe shell32.dll,Control_RunDLL hotplug.dll", NULL, NULL, SW_SHOWNORMAL); } static void _ShowContextMenu(CSysTray * pSysTray) -{ - CString strOpen((LPCSTR)IDS_HOTPLUG_REMOVE_2); - HMENU hPopup = CreatePopupMenu(); - AppendMenuW(hPopup, MF_STRING, IDS_HOTPLUG_REMOVE_2, strOpen); +{ + HMENU hPopup = CreatePopupMenu(); + + for (UINT index = 0; index < g_devList.GetSize(); index++) + { + WCHAR dispName[DISPLAY_NAME_LEN], menuName[DISPLAY_NAME_LEN + 10]; + ULONG ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR); + CONFIGRET cr = CM_Get_DevNode_Registry_Property(g_devList[index], CM_DRP_DEVICEDESC, NULL, dispName, &ulLength, 0); + if (cr != CR_SUCCESS) + StrCpyW(dispName, L"Unknown Device"); + + swprintf(menuName, L"Eject %wS", dispName); + AppendMenuW(hPopup, MF_STRING, index+1, menuName); + } SetForegroundWindow(pSysTray->GetHWnd()); DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | TPM_BOTTOMALIGN; @@ -60,23 +124,69 @@ static void _ShowContextMenu(CSysTray * pSysTray) DWORD id = TrackPopupMenuEx(hPopup, flags, pt.x, pt.y, - pSysTray->GetHWnd(), NULL); - - switch (id) + pSysTray->GetHWnd(), NULL); + + if (id > 0) { - case IDS_HOTPLUG_REMOVE_2: - _RunHotplug(); - break; + id--; // since array indices starts from zero. + CONFIGRET cr = CM_Request_Device_Eject_Ex(g_devList[id], 0, 0, 0, 0, 0); + if (cr != CR_SUCCESS) + MessageBox(0, L"Device ejection failed!! Please try again after closing any open programs on device!", L"Safely Remove Hardware", MB_OKCANCEL | MB_ICONEXCLAMATION); + else + { + MessageBox(0, L"Device ejected successfully!! You can safely remove the device now!", L"Safely Remove Hardware", MB_OKCANCEL | MB_ICONINFORMATION); + g_devList.RemoveAt(id); + } } + + DestroyMenu(hPopup); +} + +static void _ShowContextMenuR(CSysTray * pSysTray) +{ + CString strMenu((LPWSTR)IDS_HOTPLUG_REMOVE_2); + HMENU hPopup = CreatePopupMenu(); + AppendMenuW(hPopup, MF_STRING, IDS_HOTPLUG_REMOVE_2, strMenu); + + SetForegroundWindow(pSysTray->GetHWnd()); + DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | TPM_BOTTOMALIGN; + POINT pt; + GetCursorPos(&pt); + + DWORD id = TrackPopupMenuEx(hPopup, flags, + pt.x, pt.y, + pSysTray->GetHWnd(), NULL); + + if (id == IDS_HOTPLUG_REMOVE_2) + { + _RunHotplug(pSysTray); + } + DestroyMenu(hPopup); } HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray * pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult) { - TRACE("Hotplug_Message uMsg=%d, wParam=%x, lParam=%x\n", uMsg, wParam, lParam); + TRACE("Hotplug_Message uMsg=%d, wParam=%x, lParam=%x\n", uMsg, wParam, lParam); switch (uMsg) { + /*case WM_CREATE: + TRACE("Hotplug_Message: WM_CREATE\n"); + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; + + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + + g_hDevNotify = RegisterDeviceNotification(pSysTray->GetHWnd(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); + if (g_hDevNotify != NULL) + { + lResult = true; + return S_OK; + } + return S_FALSE;*/ + case WM_USER + 220: TRACE("Hotplug_Message: WM_USER+220\n"); if (wParam == 1) @@ -106,18 +216,18 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray * pSysTray, UINT uMsg, W break; case WM_LBUTTONUP: - MessageBox(0, L"Safely Remove Hardware", L"Test", MB_OKCANCEL | MB_ICONINFORMATION); + _ShowContextMenu(pSysTray); break; case WM_LBUTTONDBLCLK: - _RunHotplug(); + _RunHotplug(pSysTray); break; case WM_RBUTTONDOWN: break; case WM_RBUTTONUP: - _ShowContextMenu(pSysTray); + _ShowContextMenuR(pSysTray); break; case WM_RBUTTONDBLCLK: @@ -128,6 +238,25 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray * pSysTray, UINT uMsg, W } return S_OK; + case WM_DEVICECHANGE: + switch (wParam) + { + case DBT_DEVNODES_CHANGED: + HRESULT hr = EnumHotpluggedDevices(g_devList); + if (FAILED(hr)) + return hr; + } + + lResult = true; + return S_OK; + + /*case WM_CLOSE: + if (!UnregisterDeviceNotification(hDeviceNotify)) + { + return S_FALSE; + } + return S_OK;*/ + default: TRACE("Hotplug_Message received for unknown ID %d, ignoring.\n"); return S_FALSE; diff --git a/reactos/dll/shellext/stobject/resource.h b/reactos/dll/shellext/stobject/resource.h index 11ad4147dd9..a7466f77d31 100644 --- a/reactos/dll/shellext/stobject/resource.h +++ b/reactos/dll/shellext/stobject/resource.h @@ -39,17 +39,20 @@ #define IDS_KEYS_MOUSE 331 #define IDS_KEYS_FILTER 332 -#define IDI_BATTCAP0 400 -#define IDI_BATTCAP1 401 -#define IDI_BATTCAP2 402 -#define IDI_BATTCAP3 403 -#define IDI_BATTCAP4 404 -#define IDI_BATTCAP5 405 -#define IDI_BATTCHA0 406 -#define IDI_BATTCHA1 407 -#define IDI_BATTCHA2 408 -#define IDI_BATTCHA3 409 -#define IDI_BATTCHA4 410 -#define IDI_BATTCAP_ERR 412 +#define IDI_BATTCAP0 400 +#define IDI_BATTCAP1 401 +#define IDI_BATTCAP2 402 +#define IDI_BATTCAP3 403 +#define IDI_BATTCAP4 404 +#define IDI_BATTCAP5 405 +#define IDI_BATTCHA0 406 +#define IDI_BATTCHA1 407 +#define IDI_BATTCHA2 408 +#define IDI_BATTCHA3 409 +#define IDI_BATTCHA4 410 +#define IDI_BATTCAP_ERR 412 + +#define IDI_HOTPLUG_ERR 420 +#define IDI_HOTPLUG_OK 421 #define IDR_SYSTRAY 11001 diff --git a/reactos/dll/shellext/stobject/resources/battery/0.ico b/reactos/dll/shellext/stobject/resources/battery/0.ico index b69af8b2553..1610499aa35 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/0.ico and b/reactos/dll/shellext/stobject/resources/battery/0.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/1.ico b/reactos/dll/shellext/stobject/resources/battery/1.ico index e29ec5e5a36..9c2f526f9e1 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/1.ico and b/reactos/dll/shellext/stobject/resources/battery/1.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/2.ico b/reactos/dll/shellext/stobject/resources/battery/2.ico index d7734031c0f..f1dc98aa7fc 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/2.ico and b/reactos/dll/shellext/stobject/resources/battery/2.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/3.ico b/reactos/dll/shellext/stobject/resources/battery/3.ico index e91d2879134..59fabc2ef39 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/3.ico and b/reactos/dll/shellext/stobject/resources/battery/3.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/4.ico b/reactos/dll/shellext/stobject/resources/battery/4.ico index 5172d8a1694..edc24a071e9 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/4.ico and b/reactos/dll/shellext/stobject/resources/battery/4.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/5.ico b/reactos/dll/shellext/stobject/resources/battery/5.ico index c5ef87e0587..cd4e3b8ee79 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/5.ico and b/reactos/dll/shellext/stobject/resources/battery/5.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/charging0.ico b/reactos/dll/shellext/stobject/resources/battery/charging0.ico index 5dc27f88b6d..75041624234 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/charging0.ico and b/reactos/dll/shellext/stobject/resources/battery/charging0.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/charging1.ico b/reactos/dll/shellext/stobject/resources/battery/charging1.ico index 93bf995a749..3a6210c19a1 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/charging1.ico and b/reactos/dll/shellext/stobject/resources/battery/charging1.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/charging2.ico b/reactos/dll/shellext/stobject/resources/battery/charging2.ico index a414df79d87..7c1c919a352 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/charging2.ico and b/reactos/dll/shellext/stobject/resources/battery/charging2.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/charging3.ico b/reactos/dll/shellext/stobject/resources/battery/charging3.ico index e0fc35a439d..fb92ab62130 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/charging3.ico and b/reactos/dll/shellext/stobject/resources/battery/charging3.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/charging4.ico b/reactos/dll/shellext/stobject/resources/battery/charging4.ico index c768457ccd9..bd1f495c9aa 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/charging4.ico and b/reactos/dll/shellext/stobject/resources/battery/charging4.ico differ diff --git a/reactos/dll/shellext/stobject/resources/battery/error.ico b/reactos/dll/shellext/stobject/resources/battery/error.ico index c3c2041626d..6afba7759db 100644 Binary files a/reactos/dll/shellext/stobject/resources/battery/error.ico and b/reactos/dll/shellext/stobject/resources/battery/error.ico differ diff --git a/reactos/dll/shellext/stobject/resources/hotplug/0.ico b/reactos/dll/shellext/stobject/resources/hotplug/0.ico new file mode 100644 index 00000000000..83025a942d1 Binary files /dev/null and b/reactos/dll/shellext/stobject/resources/hotplug/0.ico differ diff --git a/reactos/dll/shellext/stobject/resources/hotplug/1.ico b/reactos/dll/shellext/stobject/resources/hotplug/1.ico new file mode 100644 index 00000000000..f615f0ebd3c Binary files /dev/null and b/reactos/dll/shellext/stobject/resources/hotplug/1.ico differ diff --git a/reactos/dll/shellext/stobject/stobject.rc b/reactos/dll/shellext/stobject/stobject.rc index 6f99fefab9b..b9dc1c35bf1 100644 --- a/reactos/dll/shellext/stobject/stobject.rc +++ b/reactos/dll/shellext/stobject/stobject.rc @@ -26,6 +26,10 @@ IDI_BATTCHA4 ICON "resources/battery/charging4.ico" IDI_BATTCAP_ERR ICON "resources/battery/error.ico" +IDI_HOTPLUG_ERR ICON "resources/hotplug/0.ico" +IDI_HOTPLUG_OK ICON "resources/hotplug/1.ico" + + IDR_SYSTRAY REGISTRY "resources/rgs/systray.rgs" #include