Improve startup code further to fix problems showing expecially on Windows
* Avoid overriding argv/argc via `CMD_UTILS_CONVERT_ARGS_TO_UTF8` in Windows-specific code when processing arguments from a 2nd instance * Move the other startup code to main as well as they are not needed when processing arguments from a 2nd instance * Improve debug logging * Use `waitForBytesWritten()` instead of `flush()` when passing args as recommended by the documentation * Avoid use of `bytesAvailable()` as it doesn't work as expected in this situation on Windows (likely it doesn't really work reliably on all platforms); calling `readAll()` works and is simpler anyways * Tested that `--replace` works as well; also the `waitUntilGone && QFile::exists(fullServerName)` block is entered and if the previous instance is taking some time it really waits until it is gone
This commit is contained in:
parent
208391acf7
commit
884ead9760
|
@ -156,9 +156,6 @@ static void shutdownSyncthingTray()
|
|||
static int runApplication(int argc, const char *const *argv)
|
||||
{
|
||||
// setup argument parser
|
||||
SET_APPLICATION_INFO;
|
||||
CMD_UTILS_CONVERT_ARGS_TO_UTF8;
|
||||
CMD_UTILS_HANDLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
auto parser = ArgumentParser();
|
||||
auto qtConfigArgs = QT_CONFIG_ARGUMENTS();
|
||||
auto windowedArg = ConfigValueArgument("windowed", 'w', "opens the tray menu as a regular window");
|
||||
|
@ -301,5 +298,8 @@ static int runApplication(int argc, const char *const *argv)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SET_APPLICATION_INFO;
|
||||
CMD_UTILS_CONVERT_ARGS_TO_UTF8;
|
||||
CMD_UTILS_HANDLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
return runApplication(argc, argv);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace CppUtilities;
|
||||
using namespace CppUtilities::EscapeCodes;
|
||||
|
||||
|
@ -88,9 +87,9 @@ SingleInstance::SingleInstance(int argc, const char *const *argv, bool skipSingl
|
|||
m_server = new QLocalServer(this);
|
||||
connect(m_server, &QLocalServer::newConnection, this, &SingleInstance::handleNewConnection);
|
||||
if (!m_server->listen(appId)) {
|
||||
cerr << Phrases::Error << "Unable to launch as single instance application as " << appId.toStdString() << Phrases::EndFlush;
|
||||
std::cerr << Phrases::Error << "Unable to launch as single instance application as " << appId.toStdString() << Phrases::EndFlush;
|
||||
} else {
|
||||
cerr << Phrases::Info << "Single instance application ID: " << appId.toStdString() << Phrases::EndFlush;
|
||||
std::cerr << Phrases::Info << "Single instance application ID: " << appId.toStdString() << Phrases::EndFlush;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +108,7 @@ const QString &SingleInstance::applicationId()
|
|||
bool SingleInstance::passArgsToRunningInstance(int argc, const char *const *argv, const QString &appId, bool waitUntilGone)
|
||||
{
|
||||
if (argc < 0 || argc > 0xFFFF) {
|
||||
cerr << Phrases::Error << "Unable to pass the specified number of arguments" << Phrases::EndFlush;
|
||||
std::cerr << Phrases::Error << "Unable to pass the specified number of arguments" << Phrases::EndFlush;
|
||||
return false;
|
||||
}
|
||||
auto socket = QLocalSocket();
|
||||
|
@ -118,7 +117,7 @@ bool SingleInstance::passArgsToRunningInstance(int argc, const char *const *argv
|
|||
if (!socket.waitForConnected(1000)) {
|
||||
return false;
|
||||
}
|
||||
cerr << Phrases::Info << "Application already running, sending args to previous instance" << Phrases::EndFlush;
|
||||
std::cerr << Phrases::Info << "Application already running, sending args to previous instance" << Phrases::EndFlush;
|
||||
char buffer[2];
|
||||
BE::getBytes(static_cast<std::uint16_t>(argc), buffer);
|
||||
auto error = socket.write(buffer, 2) < 0;
|
||||
|
@ -126,19 +125,20 @@ bool SingleInstance::passArgsToRunningInstance(int argc, const char *const *argv
|
|||
for (const char *const *end = argv + argc; argv != end && !error; ++argv) {
|
||||
error = socket.write(*argv) < 0 || socket.write(buffer, 1) < 0;
|
||||
}
|
||||
error = error || !socket.flush();
|
||||
error = error || !socket.waitForBytesWritten(1000);
|
||||
socket.disconnectFromServer();
|
||||
if (socket.state() != QLocalSocket::UnconnectedState) {
|
||||
error = !socket.waitForDisconnected(1000) || error;
|
||||
}
|
||||
if (error) {
|
||||
cerr << Phrases::Error << "Unable to pass args to previous instance: " << socket.errorString().toStdString() << Phrases::EndFlush;
|
||||
std::cerr << Phrases::Error << "Unable to pass args to previous instance: " << socket.errorString().toStdString() << Phrases::EndFlush;
|
||||
}
|
||||
if (waitUntilGone) {
|
||||
cerr << Phrases::Info << "Waiting for previous instance to shutdown" << Phrases::EndFlush;
|
||||
while (QFile::exists(fullServerName)) {
|
||||
if (waitUntilGone && QFile::exists(fullServerName)) {
|
||||
const auto fullServerNameStd = fullServerName.toStdString();
|
||||
std::cerr << Phrases::Info << "Waiting for previous instance to shutdown (" << fullServerNameStd << " still exists)" << Phrases::EndFlush;
|
||||
do {
|
||||
QThread::msleep(500);
|
||||
}
|
||||
} while (QFile::exists(fullServerName));
|
||||
}
|
||||
return !error;
|
||||
}
|
||||
|
@ -152,33 +152,30 @@ void SingleInstance::handleNewConnection()
|
|||
void SingleInstance::readArgs()
|
||||
{
|
||||
auto *const socket = static_cast<QLocalSocket *>(sender());
|
||||
|
||||
// check arg data size
|
||||
const auto argDataSize = socket->bytesAvailable();
|
||||
if (argDataSize < 2 && argDataSize > (1024 * 1024)) {
|
||||
cerr << Phrases::Error << "Another application instance sent invalid argument data." << Phrases::EndFlush;
|
||||
const auto argData = socket->readAll();
|
||||
if (argData.size() < 2) {
|
||||
std::cerr << Phrases::Error << "Another application instance sent invalid argument data (payload only " << argData.size() << " bytes)." << Phrases::EndFlush;
|
||||
return;
|
||||
}
|
||||
|
||||
// read arg data
|
||||
auto argData = make_unique<char[]>(static_cast<size_t>(argDataSize));
|
||||
socket->read(argData.get(), argDataSize);
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
|
||||
// reconstruct argc and argv array
|
||||
const auto argc = BE::toUInt16(argData.get());
|
||||
auto args = vector<const char *>();
|
||||
const auto argc = BE::toUInt16(argData.data());
|
||||
auto args = std::vector<const char *>();
|
||||
args.reserve(argc + 1);
|
||||
for (const char *argv = argData.get() + 2, *end = argData.get() + argDataSize, *i = argv; i != end && *argv;) {
|
||||
std::cerr << Phrases::Info << "Evaluating " << argc << " arguments from another instance: " << Phrases::End;
|
||||
for (const char *argv = argData.data() + 2, *end = argData.data() + argData.size(), *i = argv; i != end && *argv;) {
|
||||
if (!*i) {
|
||||
args.push_back(argv);
|
||||
std::cerr << ' ' << argv;
|
||||
argv = ++i;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
args.push_back(nullptr);
|
||||
std::cerr << '\n';
|
||||
|
||||
emit newInstance(static_cast<int>(args.size() - 1), args.data());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue