1 /* 2 * PROJECT: Safely Remove Hardware Applet 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Device removal support 5 * COPYRIGHT: Copyright 2023 Thamatip Chitpong <thamatip.chitpong@reactos.org> 6 */ 7 8 #include "hotplug.h" 9 10 #include <strsafe.h> 11 12 DEVINST 13 GetDeviceInstForRemoval( 14 _In_ PHOTPLUG_DATA pHotplugData) 15 { 16 HTREEITEM hItem, hParentItem; 17 TVITEMW tvItem; 18 19 hItem = TreeView_GetSelection(pHotplugData->hwndDeviceTree); 20 if (!hItem) 21 return 0; 22 23 /* Find root item */ 24 hParentItem = TreeView_GetParent(pHotplugData->hwndDeviceTree, hItem); 25 while (hParentItem) 26 { 27 hItem = hParentItem; 28 hParentItem = TreeView_GetParent(pHotplugData->hwndDeviceTree, hItem); 29 } 30 31 ZeroMemory(&tvItem, sizeof(tvItem)); 32 tvItem.mask = TVIF_PARAM; 33 tvItem.hItem = hItem; 34 35 TreeView_GetItem(pHotplugData->hwndDeviceTree, &tvItem); 36 37 return tvItem.lParam; 38 } 39 40 static 41 VOID 42 FillConfirmDeviceList( 43 _In_ HWND hwndCfmDeviceList, 44 _In_ PHOTPLUG_DATA pHotplugData) 45 { 46 LVCOLUMNW lvColumn; 47 48 ZeroMemory(&lvColumn, sizeof(lvColumn)); 49 lvColumn.mask = LVCF_FMT; 50 lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE; 51 ListView_InsertColumn(hwndCfmDeviceList, 0, &lvColumn); 52 53 CfmListEnumDevices(hwndCfmDeviceList, pHotplugData); 54 55 ListView_SetColumnWidth(hwndCfmDeviceList, 0, LVSCW_AUTOSIZE_USEHEADER); 56 } 57 58 static 59 VOID 60 SafeRemoveDevice( 61 _In_ DEVINST DevInst, 62 _In_opt_ HWND hwndDlg) 63 { 64 PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; 65 CONFIGRET cr; 66 67 cr = CM_Request_Device_EjectW(DevInst, &VetoType, NULL, 0, 0); 68 if (cr != CR_SUCCESS && VetoType == PNP_VetoTypeUnknown) 69 { 70 LPCWSTR pszFormat = L""; 71 WCHAR szError[64]; 72 73 /* NOTES: IDS_EJECT_ERROR_FORMAT resource has to be explicitly NULL-terminated 74 * so we can use the string directly without having to make a copy of it. */ 75 LoadStringW(hApplet, IDS_EJECT_ERROR_FORMAT, (LPWSTR)&pszFormat, 0); 76 StringCbPrintfW(szError, sizeof(szError), pszFormat, cr); 77 78 MessageBoxW(hwndDlg, szError, NULL, MB_ICONEXCLAMATION | MB_OK); 79 } 80 } 81 82 INT_PTR 83 CALLBACK 84 ConfirmRemovalDlgProc( 85 _In_ HWND hwndDlg, 86 _In_ UINT uMsg, 87 _In_ WPARAM wParam, 88 _In_ LPARAM lParam) 89 { 90 PHOTPLUG_DATA pHotplugData; 91 92 pHotplugData = (PHOTPLUG_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER); 93 94 switch (uMsg) 95 { 96 case WM_INITDIALOG: 97 { 98 HWND hwndDevList; 99 100 pHotplugData = (PHOTPLUG_DATA)lParam; 101 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pHotplugData); 102 103 hwndDevList = GetDlgItem(hwndDlg, IDC_CONFIRM_STOP_DEVICE_LIST); 104 105 ListView_SetImageList(hwndDevList, 106 pHotplugData->ImageListData.ImageList, 107 LVSIL_SMALL); 108 109 FillConfirmDeviceList(hwndDevList, pHotplugData); 110 111 return TRUE; 112 } 113 114 case WM_COMMAND: 115 { 116 switch (LOWORD(wParam)) 117 { 118 case IDOK: 119 SafeRemoveDevice(GetDeviceInstForRemoval(pHotplugData), hwndDlg); 120 EndDialog(hwndDlg, LOWORD(wParam)); 121 break; 122 123 case IDCANCEL: 124 EndDialog(hwndDlg, LOWORD(wParam)); 125 break; 126 } 127 128 break; 129 } 130 131 case WM_DESTROY: 132 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)NULL); 133 break; 134 } 135 136 return FALSE; 137 } 138