运行 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;
}
我想在 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;
}