https://git.reactos.org/?p=reactos.git;a=commitdiff;h=119057800efd0d2bb86204ebf1f99558302edc51

commit 119057800efd0d2bb86204ebf1f99558302edc51
Author:     Thamatip Chitpong <thamatip.chitp...@reactos.org>
AuthorDate: Sat Nov 4 19:31:26 2023 +0700
Commit:     GitHub <nore...@github.com>
CommitDate: Sat Nov 4 13:31:26 2023 +0100

    [HOTPLUG] Add device removal support (#5836)
---
 dll/cpl/hotplug/CMakeLists.txt |   1 +
 dll/cpl/hotplug/eject.c        | 137 ++++++++++++++++++++
 dll/cpl/hotplug/enum.c         | 285 ++++++++++++++++++++++++++++++++++++++++-
 dll/cpl/hotplug/hotplug.c      | 267 +++++---------------------------------
 dll/cpl/hotplug/hotplug.h      |  31 +++++
 dll/cpl/hotplug/lang/de-DE.rc  |  14 ++
 dll/cpl/hotplug/lang/en-US.rc  |  14 ++
 dll/cpl/hotplug/lang/es-ES.rc  |  14 ++
 dll/cpl/hotplug/lang/fr-FR.rc  |  14 ++
 dll/cpl/hotplug/lang/id-ID.rc  |  14 ++
 dll/cpl/hotplug/lang/ja-JP.rc  |  14 ++
 dll/cpl/hotplug/lang/pl-PL.rc  |  14 ++
 dll/cpl/hotplug/lang/pt-PT.rc  |  14 ++
 dll/cpl/hotplug/lang/ro-RO.rc  |  14 ++
 dll/cpl/hotplug/lang/ru-RU.rc  |  14 ++
 dll/cpl/hotplug/lang/tr-TR.rc  |  14 ++
 dll/cpl/hotplug/lang/zh-CN.rc  |  14 ++
 dll/cpl/hotplug/lang/zh-HK.rc  |  14 ++
 dll/cpl/hotplug/lang/zh-TW.rc  |  14 ++
 dll/cpl/hotplug/resource.h     |   8 +-
 20 files changed, 686 insertions(+), 239 deletions(-)

diff --git a/dll/cpl/hotplug/CMakeLists.txt b/dll/cpl/hotplug/CMakeLists.txt
index ec6588697c5..c5e636d8938 100644
--- a/dll/cpl/hotplug/CMakeLists.txt
+++ b/dll/cpl/hotplug/CMakeLists.txt
@@ -3,6 +3,7 @@ spec2def(hotplug.dll hotplug.spec)
 
 list(APPEND SOURCE
     hotplug.c
+    eject.c
     enum.c)
 
 file(GLOB hotplug_rc_deps resources/*.*)
diff --git a/dll/cpl/hotplug/eject.c b/dll/cpl/hotplug/eject.c
new file mode 100644
index 00000000000..8f310ce5d0c
--- /dev/null
+++ b/dll/cpl/hotplug/eject.c
@@ -0,0 +1,137 @@
+/*
+ * PROJECT:     Safely Remove Hardware Applet
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Device removal support
+ * COPYRIGHT:   Copyright 2023 Thamatip Chitpong 
<thamatip.chitp...@reactos.org>
+ */
+
+#include "hotplug.h"
+
+#include <strsafe.h>
+
+DEVINST
+GetDeviceInstForRemoval(
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    HTREEITEM hItem, hParentItem;
+    TVITEMW tvItem;
+
+    hItem = TreeView_GetSelection(pHotplugData->hwndDeviceTree);
+    if (!hItem)
+        return 0;
+
+    /* Find root item */
+    hParentItem = TreeView_GetParent(pHotplugData->hwndDeviceTree, hItem);
+    while (hParentItem)
+    {
+        hItem = hParentItem;
+        hParentItem = TreeView_GetParent(pHotplugData->hwndDeviceTree, hItem);
+    }
+
+    ZeroMemory(&tvItem, sizeof(tvItem));
+    tvItem.mask = TVIF_PARAM;
+    tvItem.hItem = hItem;
+
+    TreeView_GetItem(pHotplugData->hwndDeviceTree, &tvItem);
+
+    return tvItem.lParam;
+}
+
+static
+VOID
+FillConfirmDeviceList(
+    _In_ HWND hwndCfmDeviceList,
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    LVCOLUMNW lvColumn;
+
+    ZeroMemory(&lvColumn, sizeof(lvColumn));
+    lvColumn.mask = LVCF_FMT;
+    lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
+    ListView_InsertColumn(hwndCfmDeviceList, 0, &lvColumn);
+
+    CfmListEnumDevices(hwndCfmDeviceList, pHotplugData);
+
+    ListView_SetColumnWidth(hwndCfmDeviceList, 0, LVSCW_AUTOSIZE_USEHEADER);
+}
+
+static
+VOID
+SafeRemoveDevice(
+    _In_ DEVINST DevInst,
+    _In_opt_ HWND hwndDlg)
+{
+    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)
+    {
+        LPCWSTR pszFormat = L"";
+        WCHAR szError[64];
+
+        /* NOTES: IDS_EJECT_ERROR_FORMAT resource has to be explicitly 
NULL-terminated
+         * so we can use the string directly without having to make a copy of 
it. */
+        LoadStringW(hApplet, IDS_EJECT_ERROR_FORMAT, (LPWSTR)&pszFormat, 0);
+        StringCbPrintfW(szError, sizeof(szError), pszFormat, cr);
+
+        MessageBoxW(hwndDlg, szError, NULL, MB_ICONEXCLAMATION | MB_OK);
+    }
+}
+
+INT_PTR
+CALLBACK
+ConfirmRemovalDlgProc(
+    _In_ HWND hwndDlg,
+    _In_ UINT uMsg,
+    _In_ WPARAM wParam,
+    _In_ LPARAM lParam)
+{
+    PHOTPLUG_DATA pHotplugData;
+
+    pHotplugData = (PHOTPLUG_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER);
+
+    switch (uMsg)
+    {
+        case WM_INITDIALOG:
+        {
+            HWND hwndDevList;
+
+            pHotplugData = (PHOTPLUG_DATA)lParam;
+            SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pHotplugData);
+
+            hwndDevList = GetDlgItem(hwndDlg, IDC_CONFIRM_STOP_DEVICE_LIST);
+
+            ListView_SetImageList(hwndDevList,
+                                  pHotplugData->ImageListData.ImageList,
+                                  LVSIL_SMALL);
+
+            FillConfirmDeviceList(hwndDevList, pHotplugData);
+
+            return TRUE;
+        }
+
+        case WM_COMMAND:
+        {
+            switch (LOWORD(wParam))
+            {
+                case IDOK:
+                    SafeRemoveDevice(GetDeviceInstForRemoval(pHotplugData), 
hwndDlg);
+                    EndDialog(hwndDlg, LOWORD(wParam));
+                    break;
+
+                case IDCANCEL:
+                    EndDialog(hwndDlg, LOWORD(wParam));
+                    break;
+            }
+
+            break;
+        }
+
+        case WM_DESTROY:
+            SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
+            break;
+    }
+
+    return FALSE;
+}
diff --git a/dll/cpl/hotplug/enum.c b/dll/cpl/hotplug/enum.c
index 26e25e660b8..698e94b0cb3 100644
--- a/dll/cpl/hotplug/enum.c
+++ b/dll/cpl/hotplug/enum.c
@@ -1,7 +1,284 @@
 /*
  * PROJECT:     Safely Remove Hardware Applet
- * LICENSE:     GPL - See COPYING in the top level directory
- * FILE:        dll/cpl/hotplug/enum.c
- * PURPOSE:     device enumeration
- * PROGRAMMERS: Johannes Anderwald (johannes.anderw...@reactos.org)
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Device enumeration
+ * COPYRIGHT:   Copyright 2013 Johannes Anderwald 
<johannes.anderw...@reactos.org>
+ *              Copyright 2023 Thamatip Chitpong 
<thamatip.chitp...@reactos.org>
  */
+
+#include "hotplug.h"
+
+#include <initguid.h>
+#include <devguid.h>
+
+#define MAX_DEVICE_DISPLAYNAME_LEN 256
+
+static
+VOID
+GetDeviceDisplayInfo(
+    _In_ DEVINST DevInst,
+    _In_ PHOTPLUG_DATA pHotplugData,
+    _Out_writes_z_(cchDesc) LPWSTR pszDesc,
+    _In_ ULONG cchDesc,
+    _Out_ PINT pImageIndex)
+{
+    WCHAR szGuidString[MAX_GUID_STRING_LEN];
+    GUID ClassGuid;
+    ULONG ulSize;
+    CONFIGRET cr;
+
+    /* Get the device description */
+    ulSize = cchDesc * sizeof(WCHAR);
+    cr = CM_Get_DevNode_Registry_PropertyW(DevInst,
+                                           CM_DRP_FRIENDLYNAME,
+                                           NULL,
+                                           pszDesc,
+                                           &ulSize,
+                                           0);
+    if (cr != CR_SUCCESS)
+    {
+        ulSize = cchDesc * sizeof(WCHAR);
+        cr = CM_Get_DevNode_Registry_PropertyW(DevInst,
+                                               CM_DRP_DEVICEDESC,
+                                               NULL,
+                                               pszDesc,
+                                               &ulSize,
+                                               0);
+        if (cr != CR_SUCCESS)
+            LoadStringW(hApplet, IDS_UNKNOWN_DEVICE, pszDesc, cchDesc);
+    }
+
+    /* Get the class GUID */
+    ulSize = sizeof(szGuidString);
+    cr = CM_Get_DevNode_Registry_PropertyW(DevInst,
+                                           CM_DRP_CLASSGUID,
+                                           NULL,
+                                           szGuidString,
+                                           &ulSize,
+                                           0);
+    if (cr == CR_SUCCESS)
+    {
+        pSetupGuidFromString(szGuidString, &ClassGuid);
+    }
+    else
+    {
+        ClassGuid = GUID_DEVCLASS_UNKNOWN;
+    }
+
+    /* Get the image for the class this device is in */
+    SetupDiGetClassImageIndex(&pHotplugData->ImageListData,
+                              &ClassGuid,
+                              pImageIndex);
+}
+
+static
+HTREEITEM
+InsertDeviceTreeItem(
+    _In_ HTREEITEM hParent,
+    _In_ DEVINST DevInst,
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    WCHAR szDisplayName[MAX_DEVICE_DISPLAYNAME_LEN];
+    INT nClassImage;
+    TVINSERTSTRUCTW tvItem;
+
+    GetDeviceDisplayInfo(DevInst,
+                         pHotplugData,
+                         szDisplayName,
+                         ARRAYSIZE(szDisplayName),
+                         &nClassImage);
+
+    ZeroMemory(&tvItem, sizeof(tvItem));
+    tvItem.hParent = hParent;
+    tvItem.hInsertAfter = TVI_LAST;
+
+    tvItem.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | 
TVIF_SELECTEDIMAGE;
+    tvItem.item.state = TVIS_EXPANDED;
+    tvItem.item.stateMask = TVIS_EXPANDED;
+    tvItem.item.pszText = szDisplayName;
+    tvItem.item.iImage = nClassImage;
+    tvItem.item.iSelectedImage = nClassImage;
+    tvItem.item.lParam = (LPARAM)DevInst;
+
+    return TreeView_InsertItem(pHotplugData->hwndDeviceTree, &tvItem);
+}
+
+static
+VOID
+DevTreeRecursiveInsertSubDevices(
+    _In_ HTREEITEM hParentItem,
+    _In_ DEVINST ParentDevInst,
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    HTREEITEM hTreeItem;
+    DEVINST ChildDevInst;
+    CONFIGRET cr;
+
+    cr = CM_Get_Child(&ChildDevInst, ParentDevInst, 0);
+    if (cr != CR_SUCCESS)
+        return;
+
+    hTreeItem = InsertDeviceTreeItem(hParentItem,
+                                     ChildDevInst,
+                                     pHotplugData);
+    if (hTreeItem != NULL)
+    {
+        DevTreeRecursiveInsertSubDevices(hTreeItem,
+                                         ChildDevInst,
+                                         pHotplugData);
+    }
+
+    for (;;)
+    {
+        cr = CM_Get_Sibling(&ChildDevInst, ChildDevInst, 0);
+        if (cr != CR_SUCCESS)
+            return;
+
+        hTreeItem = InsertDeviceTreeItem(hParentItem,
+                                         ChildDevInst,
+                                         pHotplugData);
+        if (hTreeItem != NULL)
+        {
+            DevTreeRecursiveInsertSubDevices(hTreeItem,
+                                             ChildDevInst,
+                                             pHotplugData);
+        }
+    }
+}
+
+VOID
+EnumHotpluggedDevices(
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    SP_DEVINFO_DATA did = { 0 };
+    HDEVINFO hdev;
+    int idev;
+    DWORD dwCapabilities, dwSize;
+    ULONG ulStatus, ulProblem;
+    HTREEITEM hTreeItem;
+    CONFIGRET cr;
+
+    TreeView_DeleteAllItems(pHotplugData->hwndDeviceTree);
+
+    hdev = SetupDiGetClassDevs(NULL, NULL, 0, DIGCF_ALLCLASSES | 
DIGCF_PRESENT);
+    if (hdev == INVALID_HANDLE_VALUE)
+        return;
+
+    did.cbSize = sizeof(did);
+
+    /* Enumerate all the attached devices */
+    for (idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++)
+    {
+        ulStatus = 0;
+        ulProblem = 0;
+
+        cr = CM_Get_DevNode_Status(&ulStatus,
+                                   &ulProblem,
+                                   did.DevInst,
+                                   0);
+        if (cr != CR_SUCCESS)
+            continue;
+
+        dwCapabilities = 0,
+        dwSize = sizeof(dwCapabilities);
+        cr = CM_Get_DevNode_Registry_Property(did.DevInst,
+                                              CM_DRP_CAPABILITIES,
+                                              NULL,
+                                              &dwCapabilities,
+                                              &dwSize,
+                                              0);
+        if (cr != CR_SUCCESS)
+            continue;
+
+        /* Add devices that require safe removal to the device tree */
+        if ( (dwCapabilities & CM_DEVCAP_REMOVABLE) &&
+            !(dwCapabilities & CM_DEVCAP_DOCKDEVICE) &&
+            !(dwCapabilities & CM_DEVCAP_SURPRISEREMOVALOK) &&
+            ((dwCapabilities & CM_DEVCAP_EJECTSUPPORTED) || (ulStatus & 
DN_DISABLEABLE)) &&
+            ulProblem == 0)
+        {
+            hTreeItem = InsertDeviceTreeItem(TVI_ROOT,
+                                             did.DevInst,
+                                             pHotplugData);
+
+            if ((hTreeItem != NULL) && (pHotplugData->dwFlags & 
HOTPLUG_DISPLAY_DEVICE_COMPONENTS))
+            {
+                DevTreeRecursiveInsertSubDevices(hTreeItem,
+                                                 did.DevInst,
+                                                 pHotplugData);
+            }
+        }
+    }
+
+    SetupDiDestroyDeviceInfoList(hdev);
+}
+
+static
+VOID
+InsertConfirmDeviceListItem(
+    _In_ HWND hwndCfmDeviceList,
+    _In_ DEVINST DevInst,
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    WCHAR szDisplayName[MAX_DEVICE_DISPLAYNAME_LEN];
+    INT nClassImage;
+    LVITEMW lvItem;
+
+    GetDeviceDisplayInfo(DevInst,
+                         pHotplugData,
+                         szDisplayName,
+                         ARRAYSIZE(szDisplayName),
+                         &nClassImage);
+
+    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);
+    }
+}
+
+VOID
+CfmListEnumDevices(
+    _In_ HWND hwndCfmDeviceList,
+    _In_ PHOTPLUG_DATA pHotplugData)
+{
+    DEVINST DevInst;
+
+    DevInst = GetDeviceInstForRemoval(pHotplugData);
+    if (DevInst != 0)
+    {
+        InsertConfirmDeviceListItem(hwndCfmDeviceList, DevInst, pHotplugData);
+        CfmListRecursiveInsertSubDevices(hwndCfmDeviceList, DevInst, 
pHotplugData);
+    }
+}
diff --git a/dll/cpl/hotplug/hotplug.c b/dll/cpl/hotplug/hotplug.c
index 15dea9c7583..1c50fc62fb1 100644
--- a/dll/cpl/hotplug/hotplug.c
+++ b/dll/cpl/hotplug/hotplug.c
@@ -8,23 +8,9 @@
 
 #include "hotplug.h"
 
-#include <initguid.h>
-#include <devguid.h>
-
 #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;
 
@@ -102,215 +88,22 @@ done:
     return dwError;
 }
 
-
-static
-HTREEITEM
-InsertDeviceTreeItem(
-    _In_ HWND hwndDeviceTree,
-    _In_ HTREEITEM hParent,
-    _In_ DWORD DevInst,
-    _In_ PHOTPLUG_DATA pHotplugData)
-{
-    WCHAR szDisplayName[40];
-    WCHAR szGuidString[MAX_GUID_STRING_LEN];
-    TVINSERTSTRUCTW tvItem;
-    GUID ClassGuid;
-    INT nClassImage;
-    DWORD dwSize;
-    CONFIGRET cr;
-
-    /* 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 device tree */
-    ZeroMemory(&tvItem, sizeof(tvItem));
-    tvItem.hParent = hParent;
-    tvItem.hInsertAfter = TVI_LAST;
-
-    tvItem.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | 
TVIF_SELECTEDIMAGE;
-    tvItem.item.state = TVIS_EXPANDED;
-    tvItem.item.stateMask = TVIS_EXPANDED;
-    tvItem.item.pszText = szDisplayName;
-    tvItem.item.iImage = nClassImage;
-    tvItem.item.iSelectedImage = nClassImage;
-    tvItem.item.lParam = (LPARAM)DevInst;
-
-    return TreeView_InsertItem(hwndDeviceTree, &tvItem);
-}
-
-
 static
 VOID
-RecursiveInsertSubDevices(
-    _In_ HWND hwndDeviceTree,
-    _In_ HTREEITEM hParentItem,
-    _In_ DWORD ParentDevInst,
-    _In_ PHOTPLUG_DATA pHotplugData)
+UpdateDialog(
+    _In_ HWND hwndDlg)
 {
-    HTREEITEM hTreeItem;
-    DEVINST ChildDevInst;
-    CONFIGRET cr;
-
-    DPRINT("RecursiveInsertSubDevices()\n");
+    HWND hwndDeviceTree;
+    BOOL bHasItem;
 
-    cr = CM_Get_Child(&ChildDevInst, ParentDevInst, 0);
-    if (cr != CR_SUCCESS)
-    {
-        DPRINT("No child! %lu\n", cr);
-        return;
-    }
+    hwndDeviceTree = GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_DEVICE_TREE);
 
-    hTreeItem = InsertDeviceTreeItem(hwndDeviceTree,
-                                     hParentItem,
-                                     ChildDevInst,
-                                     pHotplugData);
-    if (hTreeItem != NULL)
-    {
-        RecursiveInsertSubDevices(hwndDeviceTree,
-                                  hTreeItem,
-                                  ChildDevInst,
-                                  pHotplugData);
-    }
+    bHasItem = (TreeView_GetCount(hwndDeviceTree) != 0);
+    if (bHasItem)
+        TreeView_SelectItem(hwndDeviceTree, 
TreeView_GetFirstVisible(hwndDeviceTree));
 
-    for (;;)
-    {
-        cr = CM_Get_Sibling(&ChildDevInst, ChildDevInst, 0);
-        if (cr != CR_SUCCESS)
-        {
-            DPRINT("No sibling! %lu\n", cr);
-            return;
-        }
-
-        hTreeItem = InsertDeviceTreeItem(hwndDeviceTree,
-                                         hParentItem,
-                                         ChildDevInst,
-                                         pHotplugData);
-        if (hTreeItem != NULL)
-        {
-            RecursiveInsertSubDevices(hwndDeviceTree,
-                                      hTreeItem,
-                                      ChildDevInst,
-                                      pHotplugData);
-        }
-    }
-}
-
-
-static
-VOID
-EnumHotpluggedDevices(
-    HWND hwndDeviceTree,
-    PHOTPLUG_DATA pHotplugData)
-{
-    SP_DEVINFO_DATA did = { 0 };
-    HDEVINFO hdev;
-    int idev;
-    DWORD dwCapabilities, dwSize;
-    ULONG ulStatus, ulProblem;
-    HTREEITEM hTreeItem;
-    CONFIGRET cr;
-
-    DPRINT1("EnumHotpluggedDevices()\n");
-
-    TreeView_DeleteAllItems(hwndDeviceTree);
-
-    hdev = SetupDiGetClassDevs(NULL, NULL, 0, DIGCF_ALLCLASSES | 
DIGCF_PRESENT);
-    if (hdev == INVALID_HANDLE_VALUE)
-        return;
-
-    did.cbSize = sizeof(did);
-
-    /* Enumerate all the attached devices */
-    for (idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++)
-    {
-        ulStatus = 0;
-        ulProblem = 0;
-
-        cr = CM_Get_DevNode_Status(&ulStatus,
-                                   &ulProblem,
-                                   did.DevInst,
-                                   0);
-        if (cr != CR_SUCCESS)
-            continue;
-
-        dwCapabilities = 0,
-        dwSize = sizeof(dwCapabilities);
-        cr = CM_Get_DevNode_Registry_Property(did.DevInst,
-                                              CM_DRP_CAPABILITIES,
-                                              NULL,
-                                              &dwCapabilities,
-                                              &dwSize,
-                                              0);
-        if (cr != CR_SUCCESS)
-            continue;
-
-        /* Add devices that require safe removal to the device tree */
-        if ( (dwCapabilities & CM_DEVCAP_REMOVABLE) &&
-            !(dwCapabilities & CM_DEVCAP_DOCKDEVICE) &&
-            !(dwCapabilities & CM_DEVCAP_SURPRISEREMOVALOK) &&
-            ((dwCapabilities & CM_DEVCAP_EJECTSUPPORTED) || (ulStatus & 
DN_DISABLEABLE)) &&
-            ulProblem == 0)
-        {
-            hTreeItem = InsertDeviceTreeItem(hwndDeviceTree,
-                                             TVI_ROOT,
-                                             did.DevInst,
-                                             pHotplugData);
-
-            if ((hTreeItem != NULL) && (pHotplugData->dwFlags & 
HOTPLUG_DISPLAY_DEVICE_COMPONENTS))
-            {
-                RecursiveInsertSubDevices(hwndDeviceTree,
-                                          hTreeItem,
-                                          did.DevInst,
-                                          pHotplugData);
-            }
-        }
-    }
-
-    SetupDiDestroyDeviceInfoList(hdev);
-}
-
-
-static
-VOID
-UpdateButtons(
-    HWND hwndDlg)
-{
-    BOOL bEnabled;
-
-    bEnabled = (TreeView_GetCount(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE)) != 0);
-
-    EnableWindow(GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_PROPERTIES), bEnabled);
-    EnableWindow(GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_STOP), bEnabled);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_PROPERTIES), bHasItem);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_SAFE_REMOVE_STOP), bHasItem);
 }
 
 
@@ -347,12 +140,12 @@ ShowContextMenu(
 static
 DEVINST
 GetSelectedDeviceInst(
-    _In_ HWND hwndDeviceTree)
+    _In_ PHOTPLUG_DATA pHotplugData)
 {
     HTREEITEM hTreeItem;
     TVITEMW item;
 
-    hTreeItem = TreeView_GetSelection(hwndDeviceTree);
+    hTreeItem = TreeView_GetSelection(pHotplugData->hwndDeviceTree);
     if (hTreeItem == NULL)
         return 0;
 
@@ -360,7 +153,7 @@ GetSelectedDeviceInst(
     item.mask = TVIF_PARAM;
     item.hItem = hTreeItem;
 
-    TreeView_GetItem(hwndDeviceTree, &item);
+    TreeView_GetItem(pHotplugData->hwndDeviceTree, &item);
 
     return item.lParam;
 }
@@ -456,19 +249,18 @@ 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)
                     Button_SetCheck(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DISPLAY_COMPONENTS), BST_CHECKED);
 
-                TreeView_SetImageList(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE),
+                TreeView_SetImageList(pHotplugData->hwndDeviceTree,
                                       pHotplugData->ImageListData.ImageList,
                                       TVSIL_NORMAL);
 
-                EnumHotpluggedDevices(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE),
-                                      pHotplugData);
-                UpdateButtons(hwndDlg);
+                EnumHotpluggedDevices(pHotplugData);
+                UpdateDialog(hwndDlg);
             }
             return TRUE;
 
@@ -492,17 +284,29 @@ SafeRemovalDlgProc(
 
                             SetHotPlugFlags(pHotplugData->dwFlags);
 
-                            EnumHotpluggedDevices(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE),
-                                                  pHotplugData);
+                            EnumHotpluggedDevices(pHotplugData);
+                            UpdateDialog(hwndDlg);
                         }
                     }
                     break;
 
                 case IDC_SAFE_REMOVE_PROPERTIES:
                 case IDM_PROPERTIES:
+                    ShowDeviceProperties(hwndDlg, 
GetSelectedDeviceInst(pHotplugData));
+                    break;
+
+                case IDC_SAFE_REMOVE_STOP:
+                case IDM_STOP:
                 {
-                    HWND hwndDevTree = GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE);
-                    ShowDeviceProperties(hwndDlg, 
GetSelectedDeviceInst(hwndDevTree));
+                    if (pHotplugData != NULL)
+                    {
+                        DialogBoxParamW(hApplet,
+                                        
MAKEINTRESOURCEW(IDD_CONFIRM_STOP_HARDWARE_DIALOG),
+                                        hwndDlg,
+                                        ConfirmRemovalDlgProc,
+                                        (LPARAM)pHotplugData);
+                    }
+
                     break;
                 }
             }
@@ -524,9 +328,8 @@ SafeRemovalDlgProc(
 
                 if (pHotplugData != NULL)
                 {
-                    EnumHotpluggedDevices(GetDlgItem(hwndDlg, 
IDC_SAFE_REMOVE_DEVICE_TREE),
-                                          pHotplugData);
-                    UpdateButtons(hwndDlg);
+                    EnumHotpluggedDevices(pHotplugData);
+                    UpdateDialog(hwndDlg);
                 }
             }
             break;
diff --git a/dll/cpl/hotplug/hotplug.h b/dll/cpl/hotplug/hotplug.h
index 8e11875c613..1f61a2fb894 100644
--- a/dll/cpl/hotplug/hotplug.h
+++ b/dll/cpl/hotplug/hotplug.h
@@ -38,7 +38,38 @@ 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
+DEVINST
+GetDeviceInstForRemoval(
+    _In_ PHOTPLUG_DATA pHotplugData);
+
+INT_PTR
+CALLBACK
+ConfirmRemovalDlgProc(
+    _In_ HWND hwndDlg,
+    _In_ UINT uMsg,
+    _In_ WPARAM wParam,
+    _In_ LPARAM lParam);
+
+// enum.c
+VOID
+EnumHotpluggedDevices(
+    _In_ PHOTPLUG_DATA pHotplugData);
 
+VOID
+CfmListEnumDevices(
+    _In_ HWND hwndCfmDeviceList,
+    _In_ PHOTPLUG_DATA pHotplugData);
 
 // hotplug.c
 LONG
diff --git a/dll/cpl/hotplug/lang/de-DE.rc b/dll/cpl/hotplug/lang/de-DE.rc
index 32ae783b3d4..bc70584c158 100644
--- a/dll/cpl/hotplug/lang/de-DE.rc
+++ b/dll/cpl/hotplug/lang/de-DE.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "&Schließen", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Hardware sicher entfernen"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/en-US.rc b/dll/cpl/hotplug/lang/en-US.rc
index f0728860bba..20acd4ecb5c 100644
--- a/dll/cpl/hotplug/lang/en-US.rc
+++ b/dll/cpl/hotplug/lang/en-US.rc
@@ -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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Safely Remove Hardware"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/es-ES.rc b/dll/cpl/hotplug/lang/es-ES.rc
index 47165e847b7..512a0ae4850 100644
--- a/dll/cpl/hotplug/lang/es-ES.rc
+++ b/dll/cpl/hotplug/lang/es-ES.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "&Cerrar", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Retirar hardware con seguridad"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/fr-FR.rc b/dll/cpl/hotplug/lang/fr-FR.rc
index 36577034316..c7f9e2ab7c7 100644
--- a/dll/cpl/hotplug/lang/fr-FR.rc
+++ b/dll/cpl/hotplug/lang/fr-FR.rc
@@ -24,6 +24,18 @@ BEGIN
     PUSHBUTTON "&Fermer", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -43,4 +55,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Retirer un périphérique en toute sécurité"
     IDS_CPLDESCRIPTION "Déconnecter ou éjecter un périphérique de votre 
ordinateur en sécurité."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/id-ID.rc b/dll/cpl/hotplug/lang/id-ID.rc
index 29f9c5994fe..45c2963177c 100644
--- a/dll/cpl/hotplug/lang/id-ID.rc
+++ b/dll/cpl/hotplug/lang/id-ID.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "&Tutup", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Hapus perangkat keras dengan aman"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/ja-JP.rc b/dll/cpl/hotplug/lang/ja-JP.rc
index c2a9c356d50..0940057bd35 100644
--- a/dll/cpl/hotplug/lang/ja-JP.rc
+++ b/dll/cpl/hotplug/lang/ja-JP.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "閉じる(&C)", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "安全なハードウェアの取り外し"
     IDS_CPLDESCRIPTION "コンピュータからデバイスを安全に取り外しできます。"
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/pl-PL.rc b/dll/cpl/hotplug/lang/pl-PL.rc
index 2c13620fd6f..cf7af16f8ea 100644
--- a/dll/cpl/hotplug/lang/pl-PL.rc
+++ b/dll/cpl/hotplug/lang/pl-PL.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "Za&mknij", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Bezpieczne usuwanie sprzętu"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/pt-PT.rc b/dll/cpl/hotplug/lang/pt-PT.rc
index ae7db1f835e..8e1ed9d4a18 100644
--- a/dll/cpl/hotplug/lang/pt-PT.rc
+++ b/dll/cpl/hotplug/lang/pt-PT.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "&Fechar", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Remover Hardware com segurança"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/ro-RO.rc b/dll/cpl/hotplug/lang/ro-RO.rc
index 5c0df0fbdf3..d0e9dd9c5c2 100644
--- a/dll/cpl/hotplug/lang/ro-RO.rc
+++ b/dll/cpl/hotplug/lang/ro-RO.rc
@@ -24,6 +24,18 @@ BEGIN
     PUSHBUTTON "Î&nchidere", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -43,4 +55,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Eliminare în siguranță a dispozitivul fizic"
     IDS_CPLDESCRIPTION "Deconectare sau scoatere în siguranță a dispozitivelor 
din calculator."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/ru-RU.rc b/dll/cpl/hotplug/lang/ru-RU.rc
index 953fb4230d4..688ee84c6f6 100644
--- a/dll/cpl/hotplug/lang/ru-RU.rc
+++ b/dll/cpl/hotplug/lang/ru-RU.rc
@@ -17,6 +17,18 @@ BEGIN
     PUSHBUTTON "&Закрыть", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -36,4 +48,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Безопасное извлечение устройств"
     IDS_CPLDESCRIPTION "Безопасно отключайте или извлекайте устройства из 
вашего компьютера."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/tr-TR.rc b/dll/cpl/hotplug/lang/tr-TR.rc
index a77aa3d16c2..7ffed72f7e0 100644
--- a/dll/cpl/hotplug/lang/tr-TR.rc
+++ b/dll/cpl/hotplug/lang/tr-TR.rc
@@ -19,6 +19,18 @@ BEGIN
     PUSHBUTTON "&Kapat", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -38,4 +50,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "Donanımı Güvenli Kaldır"
     IDS_CPLDESCRIPTION "Aygıtları bilgisayarınızdan güvenle çıkarın veya 
çıkarın."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/zh-CN.rc b/dll/cpl/hotplug/lang/zh-CN.rc
index 53c3eacb3bc..9ca1e3e351e 100644
--- a/dll/cpl/hotplug/lang/zh-CN.rc
+++ b/dll/cpl/hotplug/lang/zh-CN.rc
@@ -24,6 +24,18 @@ BEGIN
     PUSHBUTTON "关闭(&C)", 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 | WS_POPUP | WS_VISIBLE | 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
+
 IDM_POPUP_DEVICE_TREE MENU
 BEGIN
     POPUP ""
@@ -37,4 +49,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "安全地移除硬件"
     IDS_CPLDESCRIPTION "从您的计算机安全地拔出或弹出设备。"
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/zh-HK.rc b/dll/cpl/hotplug/lang/zh-HK.rc
index f004ed02c18..75399afc4ab 100644
--- a/dll/cpl/hotplug/lang/zh-HK.rc
+++ b/dll/cpl/hotplug/lang/zh-HK.rc
@@ -24,6 +24,18 @@ BEGIN
     PUSHBUTTON "關閉(&C)", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -43,4 +55,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "安全地移除硬件"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/lang/zh-TW.rc b/dll/cpl/hotplug/lang/zh-TW.rc
index afbdbf4b4d6..dd49a385693 100644
--- a/dll/cpl/hotplug/lang/zh-TW.rc
+++ b/dll/cpl/hotplug/lang/zh-TW.rc
@@ -24,6 +24,18 @@ BEGIN
     PUSHBUTTON "關閉(&C)", 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 | WS_POPUP | WS_VISIBLE | 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 */
 
@@ -43,4 +55,6 @@ STRINGTABLE
 BEGIN
     IDS_CPLNAME "安全地移除硬體"
     IDS_CPLDESCRIPTION "Safely unplug or eject devices from your computer."
+    IDS_UNKNOWN_DEVICE "Unknown Device"
+    IDS_EJECT_ERROR_FORMAT "Failed to remove device (0x%x)\0"
 END
diff --git a/dll/cpl/hotplug/resource.h b/dll/cpl/hotplug/resource.h
index af8d359670d..7206d24bab5 100644
--- a/dll/cpl/hotplug/resource.h
+++ b/dll/cpl/hotplug/resource.h
@@ -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
@@ -22,6 +23,7 @@
 #define IDM_PROPERTIES                     502
 
 /* Resource strings IDs */
-#define IDS_CPLNAME        1000
-#define IDS_CPLDESCRIPTION 1001
-
+#define IDS_CPLNAME            1000
+#define IDS_CPLDESCRIPTION     1001
+#define IDS_UNKNOWN_DEVICE     1002
+#define IDS_EJECT_ERROR_FORMAT 1003

Reply via email to