xref: /reactos/dll/cpl/hotplug/eject.c (revision 4514e91d)
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