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
GetDeviceInstForRemoval(_In_ PHOTPLUG_DATA pHotplugData)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
FillConfirmDeviceList(_In_ HWND hwndCfmDeviceList,_In_ PHOTPLUG_DATA pHotplugData)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
SafeRemoveDevice(_In_ DEVINST DevInst,_In_opt_ HWND hwndDlg)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
ConfirmRemovalDlgProc(_In_ HWND hwndDlg,_In_ UINT uMsg,_In_ WPARAM wParam,_In_ LPARAM lParam)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