diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 94121ec7..d3a57fe6 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -162,6 +162,10 @@ HWND MainDlg = NULL; wchar_t *lpszTitle = NULL; BOOL Silent = FALSE; +/* Set by Mount.c only while it carries out a dismount requested on the command line + with /q. UnmountVolumeBase and DismountAll then send the drive removal notification + again with SHCNF_FLUSH, as they do when Silent is set. */ +BOOL FlushDriveRemovalNotifications = FALSE; BOOL bPreserveTimestamp = TRUE; BOOL bShowDisconnectedNetworkDrives = FALSE; BOOL bHideWaitingDialog = FALSE; @@ -9826,13 +9830,13 @@ retry: BroadcastDeviceChange (DBT_DEVICEREMOVECOMPLETE, nDosDriveNo, 0); - /* GH #337, GH #1426: When running in silent/CLI mode, the process may - exit immediately after unmount. BroadcastDeviceChange sends - SHChangeNotify asynchronously, so Explorer may not process the drive - removal before the process exits, leaving a ghost drive letter. - Re-send the notification with SHCNF_FLUSH to force synchronous - processing by Explorer before we return. */ - if (Silent && !DeviceChangeBroadcastDisabled) + /* GH #337, GH #1426: ghost drive letters were reported after dismounts + requested on the command line; their cause hasn't been established. + When Silent or FlushDriveRemovalNotifications is set, the notification + is sent again with SHCNF_FLUSH. According to the documentation, + SHChangeNotify then returns only once it has been delivered, which + doesn't mean that Explorer has finished updating its display. */ + if ((Silent || FlushDriveRemovalNotifications) && !DeviceChangeBroadcastDisabled) { wchar_t root[] = { (wchar_t) (nDosDriveNo + L'A'), L':', L'\\', 0 }; SHChangeNotify (SHCNE_DRIVEREMOVED, SHCNF_PATH | SHCNF_FLUSH, root, NULL); diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 6ebb6c53..47271e8c 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -133,6 +133,7 @@ extern int ScreenDPI; extern double DlgAspectRatio; extern HWND MainDlg; extern BOOL Silent; +extern BOOL FlushDriveRemovalNotifications; extern BOOL bHistory; extern BOOL bPreserveTimestamp; extern BOOL bShowDisconnectedNetworkDrives; diff --git a/src/Mount/Mount.c b/src/Mount/Mount.c index d99d9306..511415b5 100644 --- a/src/Mount/Mount.c +++ b/src/Mount/Mount.c @@ -6351,10 +6351,9 @@ retry: if (removedDrives) BroadcastDeviceChange (DBT_DEVICEREMOVECOMPLETE, 0, removedDrives); - /* GH #337, GH #1426: Flush shell notifications synchronously in - silent/CLI mode to prevent ghost drive letters when the process - exits immediately after dismount. */ - if (Silent && !DeviceChangeBroadcastDisabled) + /* GH #337, GH #1426: as in UnmountVolumeBase, send the notifications again + with SHCNF_FLUSH when Silent or FlushDriveRemovalNotifications is set. */ + if ((Silent || FlushDriveRemovalNotifications) && !DeviceChangeBroadcastDisabled) { for (i = 0; i < 26; i++) { @@ -8446,6 +8445,10 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa } // Dismount + /* With /q, flush the drive removal notifications of this dismount even + without /s (see UnmountVolumeBase). Only for this request: a process + that goes on as the background task doesn't flush later dismounts. */ + FlushDriveRemovalNotifications = Quit; if (cmdUnmountDrive >= 0) { MOUNT_LIST_STRUCT mountList; @@ -8467,6 +8470,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (!DismountAll (hwndDlg, bForceUnmount, !Silent, UNMOUNT_MAX_AUTO_RETRIES, UNMOUNT_AUTO_RETRY_DELAY)) exitCode = 1; } + FlushDriveRemovalNotifications = FALSE; // TaskBar icon if (bEnableBkgTask)