2012-06-10 16:50:54 +00:00
|
|
|
/*
|
2024-09-17 19:00:25 +00:00
|
|
|
* Deskflow -- mouse and keyboard sharing utility
|
2025-02-24 13:17:22 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2012 - 2016, 2025 Symless Ltd.
|
2025-01-24 00:11:17 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
2012-06-10 16:50:54 +00:00
|
|
|
*/
|
|
|
|
|
|
2025-02-06 18:13:54 +00:00
|
|
|
#include "arch/Arch.h"
|
2025-03-05 18:09:25 +00:00
|
|
|
#include "base/EventQueue.h"
|
2025-02-06 18:13:54 +00:00
|
|
|
#include "base/Log.h"
|
2025-02-07 12:50:25 +00:00
|
|
|
#include "common/constants.h"
|
2024-09-17 19:00:25 +00:00
|
|
|
#include "deskflow/DaemonApp.h"
|
2025-02-07 17:03:26 +00:00
|
|
|
#include "deskflow/ipc/DaemonIpcServer.h"
|
2014-02-28 12:36:45 +00:00
|
|
|
|
2025-02-28 12:46:12 +00:00
|
|
|
#if SYSAPI_WIN32
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2025-02-06 12:03:51 +00:00
|
|
|
#include "arch/win32/ArchMiscWindows.h"
|
2012-06-10 16:50:54 +00:00
|
|
|
|
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
|
2025-02-06 12:03:51 +00:00
|
|
|
#endif
|
|
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
#include <QCommandLineParser>
|
2025-02-06 18:13:54 +00:00
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QThread>
|
|
|
|
|
|
2025-02-10 12:58:23 +00:00
|
|
|
using namespace deskflow::core;
|
|
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
void handleError(const char *message = "Unrecognized error.");
|
2025-02-24 13:17:22 +00:00
|
|
|
|
2025-02-06 12:03:51 +00:00
|
|
|
int main(int argc, char **argv)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-02-28 12:46:12 +00:00
|
|
|
#if SYSAPI_WIN32
|
2025-03-06 12:36:14 +00:00
|
|
|
ArchMiscWindows::guardRuntimeVersion();
|
|
|
|
|
|
2025-02-06 18:13:54 +00:00
|
|
|
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
2025-02-28 12:46:12 +00:00
|
|
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Arch arch;
|
|
|
|
|
arch.init();
|
|
|
|
|
|
|
|
|
|
Log log;
|
|
|
|
|
EventQueue events;
|
|
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
// Daemon deliberately does not have a parent, as it will be moved to a new thread.
|
|
|
|
|
DaemonApp daemon(events);
|
|
|
|
|
|
|
|
|
|
QCoreApplication app(argc, argv);
|
|
|
|
|
QCoreApplication::setApplicationName(QStringLiteral("%1 Daemon").arg(kAppName));
|
|
|
|
|
|
|
|
|
|
QCommandLineParser parser;
|
|
|
|
|
parser.addHelpOption();
|
|
|
|
|
parser.addVersionOption();
|
|
|
|
|
|
|
|
|
|
const auto foregroundOption = QCommandLineOption({"f", "foreground"}, "Run in the foreground (show console)");
|
|
|
|
|
parser.addOption(foregroundOption);
|
|
|
|
|
|
|
|
|
|
const auto installOption = QCommandLineOption({"i", "install"}, "Install as a Windows service");
|
|
|
|
|
parser.addOption(installOption);
|
|
|
|
|
|
|
|
|
|
const auto uninstallOption = QCommandLineOption({"u", "uninstall"}, "Uninstall the Windows service");
|
|
|
|
|
parser.addOption(uninstallOption);
|
|
|
|
|
|
|
|
|
|
parser.process(app);
|
|
|
|
|
|
|
|
|
|
if (parser.isSet(foregroundOption)) {
|
|
|
|
|
daemon.setForeground();
|
2025-02-24 13:17:22 +00:00
|
|
|
}
|
2025-02-07 17:03:26 +00:00
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
// Depends on whether foreground option was set.
|
|
|
|
|
daemon.initLogging();
|
|
|
|
|
|
|
|
|
|
// Important: Log the app name and version number to the log file daemon app has initialized
|
|
|
|
|
// logging as it creates the file logger. Logging before would only log to stdout which is not
|
|
|
|
|
// useful for troubleshooting Windows services.
|
2025-03-04 10:40:31 +00:00
|
|
|
// It's important to write the version number to the log file so we can be certain the old daemon
|
|
|
|
|
// was uninstalled, since sometimes Windows services can get stuck and fail to be removed.
|
2025-03-05 15:40:23 +00:00
|
|
|
LOG_PRINT("%s v%s", QCoreApplication::applicationName().toStdString().c_str(), kDisplayVersion);
|
2025-03-04 10:40:31 +00:00
|
|
|
|
2025-03-04 13:32:07 +00:00
|
|
|
// Default log level to system setting (found in Registry).
|
|
|
|
|
if (std::string logLevel = ARCH->setting("LogLevel"); logLevel != "") {
|
|
|
|
|
CLOG->setFilter(logLevel.c_str());
|
|
|
|
|
LOG_DEBUG("log level: %s", logLevel.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
try {
|
|
|
|
|
|
2025-03-04 14:41:46 +00:00
|
|
|
#if SYSAPI_WIN32
|
2025-03-05 15:40:23 +00:00
|
|
|
// Show warning if not running as admin as daemon will behave differently.
|
|
|
|
|
if (!ArchMiscWindows::isProcessElevated()) {
|
|
|
|
|
LOG_WARN("not running as admin, some features may not work");
|
|
|
|
|
}
|
2025-03-04 14:41:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
if (parser.isSet(installOption)) {
|
|
|
|
|
daemon.install();
|
|
|
|
|
return kExitSuccess;
|
|
|
|
|
} else if (parser.isSet(uninstallOption)) {
|
|
|
|
|
daemon.uninstall();
|
|
|
|
|
return kExitSuccess;
|
|
|
|
|
}
|
2025-02-07 17:03:26 +00:00
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
const auto ipcServer = new ipc::DaemonIpcServer(&app, DaemonApp::logFilename().c_str()); // NOSONAR - Qt managed
|
|
|
|
|
ipcServer->listen();
|
|
|
|
|
daemon.connectIpcServer(ipcServer);
|
2025-02-07 17:03:26 +00:00
|
|
|
|
2025-02-10 17:59:43 +00:00
|
|
|
QThread daemonThread;
|
|
|
|
|
QObject::connect(&daemonThread, &QThread::finished, &app, &QCoreApplication::quit);
|
2025-03-05 15:40:23 +00:00
|
|
|
daemon.run(daemonThread);
|
2025-02-07 17:03:26 +00:00
|
|
|
|
2025-02-10 17:59:43 +00:00
|
|
|
const auto exitCode = QCoreApplication::exec();
|
|
|
|
|
daemonThread.wait();
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("daemon exited, code: %d", exitCode);
|
|
|
|
|
return exitCode;
|
2025-02-07 17:03:26 +00:00
|
|
|
|
2025-03-05 15:40:23 +00:00
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
handleError(e.what());
|
|
|
|
|
return kExitFailed;
|
|
|
|
|
} catch (...) {
|
|
|
|
|
handleError();
|
2025-02-07 17:03:26 +00:00
|
|
|
return kExitFailed;
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-06 12:03:51 +00:00
|
|
|
#if SYSAPI_WIN32
|
|
|
|
|
|
2025-02-07 17:03:26 +00:00
|
|
|
// Win32 subsystem entry point (simply forwards to main).
|
|
|
|
|
// We need this because using regular main under the Win32 subsystem results in empty args.
|
2025-02-06 12:03:51 +00:00
|
|
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|
|
|
|
{
|
|
|
|
|
return main(__argc, __argv);
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
2025-02-24 13:17:22 +00:00
|
|
|
|
|
|
|
|
void handleError(const char *message)
|
|
|
|
|
{
|
|
|
|
|
// Always print error to stdout in case run as CLI program.
|
|
|
|
|
LOG_ERR("%s", message);
|
|
|
|
|
|
|
|
|
|
#if SYSAPI_WIN32
|
|
|
|
|
// Show a message box for when run from MSI in Win32 subsystem.
|
|
|
|
|
MessageBoxA(nullptr, message, "Deskflow daemon error", MB_OK | MB_ICONERROR);
|
|
|
|
|
#endif
|
|
|
|
|
}
|