运行 Qt 中的可执行文件在 windows cmd 中成功时失败

Run executable in Qt failed while successful in windows cmd

我想在 Qt 应用程序中弹出可移动 USB 磁盘,并且使用了 Microsoft 的一个名为 Sync(download) 的工具,用法是 sync.exe -e [E:]

所以我运行使用下面的代码从 Qt 中安装了这个工具:

QString ejectToolPath = QString("%1/sync.exe").arg(qApp->applicationDirPath());
QStringList params;
params << "-e" << driveLetter;
QProcess::startDetached(ejectToolPath, params);

在运行执行此代码后,可移动U盘没有弹出,如果我使用托盘图标弹出磁盘,它会警告磁盘正在使用中。

但是如果我在 cmd 或 powershell 中使用 windows 资源管理器托盘图标或 运行 sync.exe,它能够弹出那个 device.Am 我遗漏了一些东西,或者 运行 shell 和 Qt 中的 exe 之间存在差异。

这个问题困扰了我好几天了,希望有大神帮忙。

提前致谢!

[2022-03-03更新]

经过测试,我缩小了问题的范围。 我的应用场景是这样的,首先点击QPushButton弹出可移动设备列表,然后select要弹出的设备,点击菜单项,调用real eject函数。 顺便说一下,设备列表小部件设置了 Qt::Popup 属性。

setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::Popup);

我发现如果我直接调用弹出设备功能,它执行正常,但如果单击具有相同代码的弹出菜单项时失败。有什么区别?

成功:

void HMStatusBarWidget::onPluginButtonClick() {
ejectDevice("D:"); // **success**
/*QHash<QString, QString> deviceList;
if (deviceListWidget_ == nullptr) {
    deviceListWidget_ = new PopupListWidget(this);
    connect(deviceListWidget_, &PopupListWidget::textItemClicked, [=]() {
        ejectDevice("D:"); // **fail**
        });
}*/
....

失败:

void HMStatusBarWidget::onPluginButtonClick() {
//ejectDevice("D:"); // **success**
QHash<QString, QString> deviceList;
if (deviceListWidget_ == nullptr) {
    deviceListWidget_ = new PopupListWidget(this);
    connect(deviceListWidget_, &PopupListWidget::textItemClicked, [=]() {
        ejectDevice("D:"); // **fail**
        });
}
....

我认为情况并非如此,但构建可执行文件路径的更好方法是

QString ejectToolPath = QDir(qApp->applicationDirPath()).filePath("sync.exe")

如果 shadowbuild 被禁用,Qt 在 debug/release/ 文件夹中构建应用程序,如果启用,则在 build-xxxx 文件夹中构建应用程序,您是否 100% 确定 sync.exe 在应用程序文件夹中?再检查一下也不会有什么坏处。

qDebug() << QFile(ejectToolPath).exists()

如果存在 startDetached 只有当 sync.exe 依赖的库之一不在 %PATH% 中时才会启动失败。

同步需要路径还是盘符? E: 可能被认为是有效路径,正确的版本是 E:\ - 带有强制性的尾部斜杠。

这是我的问题。当我枚举可移动 USB 磁盘时,我忘记关闭设备句柄。这导致设备在使用中,与Qt无关。 谢谢你的帮助! @mugiseyebrows

STORAGE_HOTPLUG_INFO HMStatusBarWidget::getDeviceType(char driveLetter)

{ STORAGE_HOTPLUG_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;

}