I want to eject removable USB disk in Qt application, and was using a tool from Microsoft called Sync(download) , the usage is sync.exe -e [E:]
So I was running this tool from Qt with code below:
QString ejectToolPath = QString("%1/sync.exe").arg(qApp->applicationDirPath());
QStringList params;
params << "-e" << driveLetter;
QProcess::startDetached(ejectToolPath, params);
after running this code, the removable Usb disk was not ejected, and if I use the tray icon to eject the disk, it warns the disk is in use.
But if I use the windows explorer tray icon or run the sync.exe in cmd or powershell, it was able to eject that device.Am I missing something or there is difference between run the exe in shell and in Qt.
This problem has tormented me for days, hope someone can help.
Thanks in advance!
[2022-03-03 update]
After testing, I narrowed down the scope of the problem. My application scenario is like this, First click the QPushButton to popup the removable device list, then select the device to eject, on click of the menu item, call the real eject function. By the way, the device list widget is set the Qt::Popup attribute.
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::Popup);
I found if I directly call eject device function, it performs OK, but if fail on click the popup menu item with the same code. what was the difference?
SUCEESS:
void HMStatusBarWidget::onPluginButtonClick() {
ejectDevice("D:"); // **success**
/*QHash<QString, QString> deviceList;
if (deviceListWidget_ == nullptr) {
deviceListWidget_ = new PopupListWidget(this);
connect(deviceListWidget_, &PopupListWidget::textItemClicked, [=]() {
ejectDevice("D:"); // **fail**
});
}*/
....
FAILURE:
void HMStatusBarWidget::onPluginButtonClick() {
//ejectDevice("D:"); // **success**
QHash<QString, QString> deviceList;
if (deviceListWidget_ == nullptr) {
deviceListWidget_ = new PopupListWidget(this);
connect(deviceListWidget_, &PopupListWidget::textItemClicked, [=]() {
ejectDevice("D:"); // **fail**
});
}
....
CodePudding user response:
I dont think it's the case but better way to build path to executable is
QString ejectToolPath = QDir(qApp->applicationDirPath()).filePath("sync.exe")
Qt builds application in debug/
or release/
folder if shadowbuild is disabled and in build-xxxx
folder if enabled, are you 100% sure sync.exe
is in application folder? It wont hurt to check again.
qDebug() << QFile(ejectToolPath).exists()
If it's there startDetached
can only fail to start if one of libraries that sync.exe
depends on is not in %PATH%.
Does sync expect path or drive letter? E:
may be considered as ivalid path, the correct version is E:\
- with mandatory trailing slash.
CodePudding user response:
It's my problem. When I was enumerating removable usb disks, I forget to close the device handle. This cause the device in use, It has nothing to do with Qt. Thanks for your help! @mugiseyebrows
STORAGE_HOTPLUG_INFO HMStatusBarWidget::getDeviceType(char driveLetter)
{ STORAGE_HOTPLUG_INFO Info = { 0 };
HANDLE hDevice = getDeviceHandle(driveLetter);
if (hDevice == INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
return Info;
}
DWORD bytesReturned = 0;
DeviceIoControl(hDevice, IOCTL_STORAGE_GET_HOTPLUG_INFO, 0, 0, &Info, sizeof(Info), &bytesReturned, NULL);
CloseHandle(hDevice);
return Info;
}