Skip to content

Commit

Permalink
[HOTPLUG] Implement confirm removal dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
TAN-Gaming committed Oct 29, 2023
1 parent ea4424c commit 637939b
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 31 deletions.
1 change: 1 addition & 0 deletions dll/cpl/hotplug/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ spec2def(hotplug.dll hotplug.spec)

list(APPEND SOURCE
hotplug.c
eject.c
enum.c)

file(GLOB hotplug_rc_deps resources/*.*)
Expand Down
220 changes: 220 additions & 0 deletions dll/cpl/hotplug/eject.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* PROJECT: ReactOS Safely Remove Hardware Applet
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Confirm Removal Dialog
* COPYRIGHT: Copyright 2023 Thamatip Chitpong <[email protected]>
*/

#include "hotplug.h"

#include <initguid.h>
#include <devguid.h>

static
DEVINST
GetDeviceInstForRemoval(
_In_ PHOTPLUG_DATA pHotplugData)
{
HTREEITEM hTreeItem;
TVITEMW tvItem;

hTreeItem = TreeView_GetSelection(pHotplugData->hwndDeviceTree);
if (!hTreeItem)
return 0;

/* Find top-level parent item */
while (TreeView_GetParent(pHotplugData->hwndDeviceTree, hTreeItem))
{
hTreeItem = TreeView_GetParent(pHotplugData->hwndDeviceTree, hTreeItem);
}

ZeroMemory(&tvItem, sizeof(tvItem));
tvItem.mask = TVIF_PARAM;
tvItem.hItem = hTreeItem;

TreeView_GetItem(pHotplugData->hwndDeviceTree, &tvItem);

return tvItem.lParam;
}

static
VOID
InsertConfirmDeviceListItem(
_In_ HWND hwndCfmDeviceList,
_In_ DEVINST DevInst,
_In_ PHOTPLUG_DATA pHotplugData)
{
WCHAR szDisplayName[40];
WCHAR szGuidString[MAX_GUID_STRING_LEN];
DWORD dwSize;
GUID ClassGuid;
INT nClassImage;
CONFIGRET cr;
LVITEMW lvItem;

/* Get the device description */
dwSize = sizeof(szDisplayName);
cr = CM_Get_DevNode_Registry_Property(DevInst,
CM_DRP_DEVICEDESC,
NULL,
szDisplayName,
&dwSize,
0);
if (cr != CR_SUCCESS)
wcscpy(szDisplayName, L"Unknown Device");

/* Get the class GUID */
dwSize = sizeof(szGuidString);
cr = CM_Get_DevNode_Registry_Property(DevInst,
CM_DRP_CLASSGUID,
NULL,
szGuidString,
&dwSize,
0);
if (cr == CR_SUCCESS)
{
pSetupGuidFromString(szGuidString, &ClassGuid);
}
else
{
memcpy(&ClassGuid, &GUID_DEVCLASS_UNKNOWN, sizeof(GUID));
}

/* Get the image for the class this device is in */
SetupDiGetClassImageIndex(&pHotplugData->ImageListData,
&ClassGuid,
&nClassImage);

/* Add it to the confirm device list */
ZeroMemory(&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvItem.iItem = ListView_GetItemCount(hwndCfmDeviceList);
lvItem.pszText = szDisplayName;
lvItem.iImage = nClassImage;
lvItem.lParam = (LPARAM)DevInst;

ListView_InsertItem(hwndCfmDeviceList, &lvItem);
}

static
VOID
CfmListRecursiveInsertSubDevices(
_In_ HWND hwndCfmDeviceList,
_In_ DEVINST ParentDevInst,
_In_ PHOTPLUG_DATA pHotplugData)
{
DEVINST ChildDevInst;
CONFIGRET cr;

cr = CM_Get_Child(&ChildDevInst, ParentDevInst, 0);
if (cr != CR_SUCCESS)
return;

InsertConfirmDeviceListItem(hwndCfmDeviceList, ChildDevInst, pHotplugData);
CfmListRecursiveInsertSubDevices(hwndCfmDeviceList, ChildDevInst, pHotplugData);

for (;;)
{
cr = CM_Get_Sibling(&ChildDevInst, ChildDevInst, 0);
if (cr != CR_SUCCESS)
return;

InsertConfirmDeviceListItem(hwndCfmDeviceList, ChildDevInst, pHotplugData);
CfmListRecursiveInsertSubDevices(hwndCfmDeviceList, ChildDevInst, pHotplugData);
}
}

static
VOID
FillConfirmDeviceList(
_In_ HWND hwndCfmDeviceList,
_In_ PHOTPLUG_DATA pHotplugData)
{
DEVINST DevInst;
LVCOLUMNW lvColumn;

DevInst = GetDeviceInstForRemoval(pHotplugData);
if (DevInst == 0)
return;

ZeroMemory(&lvColumn, sizeof(lvColumn));
lvColumn.mask = LVCF_FMT;
lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
ListView_InsertColumn(hwndCfmDeviceList, 0, &lvColumn);

InsertConfirmDeviceListItem(hwndCfmDeviceList, DevInst, pHotplugData);
CfmListRecursiveInsertSubDevices(hwndCfmDeviceList, DevInst, pHotplugData);

ListView_SetColumnWidth(hwndCfmDeviceList, 0, LVSCW_AUTOSIZE_USEHEADER);
}

static
VOID
SafeRemoveDevice(
_In_ DEVINST DevInst)
{
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
CONFIGRET cr;

cr = CM_Request_Device_EjectW(DevInst, &VetoType, NULL, 0, 0);
if (cr != CR_SUCCESS && VetoType == PNP_VetoTypeUnknown)
{
WCHAR szError[64];
swprintf(szError, L"Failed to remove device (0x%x)", cr);
MessageBoxW(NULL, szError, NULL, MB_ICONEXCLAMATION | MB_OK);
}
}

INT_PTR
CALLBACK
ConfirmRemovalDlgProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
PHOTPLUG_DATA pHotplugData;

pHotplugData = (PHOTPLUG_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER);

switch (uMsg)
{
case WM_INITDIALOG:
{
pHotplugData = (PHOTPLUG_DATA)lParam;
SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pHotplugData);

ListView_SetImageList(GetDlgItem(hwndDlg, IDC_CONFIRM_STOP_DEVICE_LIST),
pHotplugData->ImageListData.ImageList,
LVSIL_SMALL);

FillConfirmDeviceList(GetDlgItem(hwndDlg, IDC_CONFIRM_STOP_DEVICE_LIST),
pHotplugData);

return TRUE;
}

case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDOK:
SafeRemoveDevice(GetDeviceInstForRemoval(pHotplugData));
EndDialog(hwndDlg, TRUE);
break;

case IDCANCEL:
EndDialog(hwndDlg, TRUE);
break;
}

break;
}

case WM_DESTROY:
SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
break;
}

return FALSE;
}
41 changes: 10 additions & 31 deletions dll/cpl/hotplug/hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@
#define NDEBUG
#include <debug.h>


typedef struct _HOTPLUG_DATA
{
HICON hIcon;
HICON hIconSm;
SP_CLASSIMAGELIST_DATA ImageListData;
HMENU hPopupMenu;
DWORD dwFlags;
} HOTPLUG_DATA, *PHOTPLUG_DATA;


// globals
HINSTANCE hApplet = 0;

Expand Down Expand Up @@ -407,23 +396,6 @@ ShowDeviceProperties(
HeapFree(GetProcessHeap(), 0, pszDevId);
}

static
VOID
SafeRemoveDevice(
_In_ DEVINST DevInst)
{
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
CONFIGRET cr;

cr = CM_Request_Device_EjectW(DevInst, &VetoType, NULL, 0, 0);
if (cr != CR_SUCCESS && VetoType == PNP_VetoTypeUnknown)
{
WCHAR szError[64];
swprintf(szError, L"Failed to remove device (0x%x)", cr);
MessageBoxW(NULL, szError, NULL, MB_ICONEXCLAMATION | MB_OK);
}
}

INT_PTR
CALLBACK
SafeRemovalDlgProc(
Expand Down Expand Up @@ -473,7 +445,7 @@ SafeRemovalDlgProc(
SetupDiGetClassImageList(&pHotplugData->ImageListData);

pHotplugData->hPopupMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDM_POPUP_DEVICE_TREE));

pHotplugData->hwndDeviceTree = GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_DEVICE_TREE);
pHotplugData->dwFlags = GetHotPlugFlags();

if (pHotplugData->dwFlags & HOTPLUG_DISPLAY_DEVICE_COMPONENTS)
Expand Down Expand Up @@ -526,8 +498,15 @@ SafeRemovalDlgProc(
case IDC_SAFE_REMOVE_STOP:
case IDM_STOP:
{
HWND hwndDevTree = GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_DEVICE_TREE);
SafeRemoveDevice(GetSelectedDeviceInst(hwndDevTree));
if (pHotplugData != NULL)
{
DialogBoxParamW(hApplet,
MAKEINTRESOURCEW(IDD_CONFIRM_STOP_HARDWARE_DIALOG),
hwndDlg,
ConfirmRemovalDlgProc,
(LPARAM)pHotplugData);
}

break;
}
}
Expand Down
17 changes: 17 additions & 0 deletions dll/cpl/hotplug/hotplug.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,24 @@ typedef struct
APPLET_PROC AppletProc;
}APPLET, *PAPPLET;

typedef struct _HOTPLUG_DATA
{
HICON hIcon;
HICON hIconSm;
SP_CLASSIMAGELIST_DATA ImageListData;
HMENU hPopupMenu;
HWND hwndDeviceTree;
DWORD dwFlags;
} HOTPLUG_DATA, *PHOTPLUG_DATA;

// eject.c
INT_PTR
CALLBACK
ConfirmRemovalDlgProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);

// hotplug.c
LONG
Expand Down
12 changes: 12 additions & 0 deletions dll/cpl/hotplug/lang/en-US.rc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ BEGIN
PUSHBUTTON "&Close", IDCLOSE, 216, 224, 55, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
END

IDD_CONFIRM_STOP_HARDWARE_DIALOG DIALOGEX 32, 10, 256, 148
CAPTION "Stop a Hardware Device"
STYLE DS_SHELLFONT | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Shell Dlg"
BEGIN
LTEXT "Confirm devices to be stopped, choose OK to continue.", IDC_STATIC, 7, 8, 241, 14, WS_CHILD | WS_VISIBLE | WS_GROUP
LTEXT "ReactOS will attempt to stop the following devices. After the devices are stopped they may be removed safely.", IDC_STATIC, 7, 22, 240, 18, WS_CHILD | WS_VISIBLE | WS_GROUP
CONTROL "", IDC_CONFIRM_STOP_DEVICE_LIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_GROUP | WS_TABSTOP, 8, 45, 240, 78
DEFPUSHBUTTON "OK", IDOK, 144, 127, 50, 14
PUSHBUTTON "Cancel", IDCANCEL, 198, 127, 50, 14
END


/* Menus */

Expand Down
1 change: 1 addition & 0 deletions dll/cpl/hotplug/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define IDC_SAFE_REMOVE_DISPLAY_COMPONENTS 306

#define IDD_CONFIRM_STOP_HARDWARE_DIALOG 310
#define IDC_CONFIRM_STOP_DEVICE_LIST 311

/* Menu IDs */
#define IDM_POPUP_DEVICE_TREE 500
Expand Down

0 comments on commit 637939b

Please sign in to comment.