我有Qt控制檯服務器應用程序。我希望有人按Ctrl + C正確退出我的服務器(調用析構函數等)。我讀過this,但是我希望它可以在Linux和Windows上運行。怎麼做?如何使用Qt在Windows和Linux上執行Ctrl + C
9
A
回答
19
我使用這個類來捕獲C++控制檯應用程序中的信號。但是,這並不是Qt特有的。它在Windows平臺上使用SetConsoleCtrlHandler(),並在其他平臺上使用<signal.h>提供的函數。棘手的一點是「信號」不是一個跨平臺術語 - Windows和POSIX對它們有不同的定義。無論如何,這個班級試圖將他們映射到一個共同的詞彙。 Ctrl^C是在兩個平臺上很好的映射。
我希望這可以適應您的具體情況。請注意,錯誤檢查很少,應該可以改進。
用法(main.cpp中)
#include "SignalHandler.h"
class Application : public SignalHandler
{
public:
Application() : SignalHandler(SignalHandler::SIG_INT), myThread(NULL) {}
int Application::main(int argc, char *argv[])
{
// Main program instructions here (e.g. start a thread)
myThread = new Thread(...);
myThread->start();
myThread->join();
delete myThread;
return 0;
}
bool handleSignal(int signal)
{
std::cout << "Handling signal " << signal << std::endl;
if (_myThread && _myThread->isRunning())
{
_myThread->stop();
// The thread is going to stop soon, so don't propagate this signal further
return true;
}
// Let the signal propagate as though we had not been there
return false;
}
private:
Thread* myThread;
};
int main(int argc, char* argv[])
{
Application app;
return app.main(argc, argv);
}
SignalHandler.h
class SignalHandler
{
public:
SignalHandler(int mask = DEFAULT_SIGNALS);
virtual ~SignalHandler();
enum SIGNALS
{
SIG_UNHANDLED = 0, // Physical signal not supported by this class
SIG_NOOP = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway)
SIG_INT = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit)
SIG_TERM = 4, // Control+Break (should terminate now without regarding the consquences)
SIG_CLOSE = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM]
SIG_RELOAD = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP]
DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
};
static const int numSignals = 6;
virtual bool handleSignal(int signal) = 0;
private:
int _mask;
};
SignalHandler.cpp
#include "SignalHandler.h"
#include <assert.h>
#ifndef _WIN32
#include <signal.h>
#else
#include <windows.h>
#endif //!_WIN32
// There can be only ONE SignalHandler per process
SignalHandler* g_handler(NULL);
#ifdef _WIN32
BOOL WINAPI WIN32_handleFunc(DWORD);
int WIN32_physicalToLogical(DWORD);
DWORD WIN32_logicalToPhysical(int);
std::set<int> g_registry;
#else //_WIN32
void POSIX_handleFunc(int);
int POSIX_physicalToLogical(int);
int POSIX_logicalToPhysical(int);
#endif //_WIN32
SignalHandler::SignalHandler(int mask) : _mask(mask)
{
assert(g_handler == NULL);
g_handler = this;
#ifdef _WIN32
SetConsoleCtrlHandler(WIN32_handleFunc, TRUE);
#endif //_WIN32
for (int i=0;i<numSignals;i++)
{
int logical = 0x1 << i;
if (_mask & logical)
{
#ifdef _WIN32
g_registry.insert(logical);
#else
int sig = POSIX_logicalToPhysical(logical);
bool failed = signal(sig, POSIX_handleFunc) == SIG_ERR;
assert(!failed);
(void)failed; // Silence the warning in non _DEBUG; TODO: something better
#endif //_WIN32
}
}
}
SignalHandler::~SignalHandler()
{
#ifdef _WIN32
SetConsoleCtrlHandler(WIN32_handleFunc, FALSE);
#else
for (int i=0;i<numSignals;i++)
{
int logical = 0x1 << i;
if (_mask & logical)
{
signal(POSIX_logicalToPhysical(logical), SIG_DFL);
}
}
#endif //_WIN32
}
#ifdef _WIN32
DWORD WIN32_logicalToPhysical(int signal)
{
switch (signal)
{
case SignalHandler::SIG_INT: return CTRL_C_EVENT;
case SignalHandler::SIG_TERM: return CTRL_BREAK_EVENT;
case SignalHandler::SIG_CLOSE: return CTRL_CLOSE_EVENT;
default:
return ~(unsigned int)0; // SIG_ERR = -1
}
}
#else
int POSIX_logicalToPhysical(int signal)
{
switch (signal)
{
case SignalHandler::SIG_INT: return SIGINT;
case SignalHandler::SIG_TERM: return SIGTERM;
// In case the client asks for a SIG_CLOSE handler, accept and
// bind it to a SIGTERM. Anyway the signal will never be raised
case SignalHandler::SIG_CLOSE: return SIGTERM;
case SignalHandler::SIG_RELOAD: return SIGHUP;
default:
return -1; // SIG_ERR = -1
}
}
#endif //_WIN32
#ifdef _WIN32
int WIN32_physicalToLogical(DWORD signal)
{
switch (signal)
{
case CTRL_C_EVENT: return SignalHandler::SIG_INT;
case CTRL_BREAK_EVENT: return SignalHandler::SIG_TERM;
case CTRL_CLOSE_EVENT: return SignalHandler::SIG_CLOSE;
default:
return SignalHandler::SIG_UNHANDLED;
}
}
#else
int POSIX_physicalToLogical(int signal)
{
switch (signal)
{
case SIGINT: return SignalHandler::SIG_INT;
case SIGTERM: return SignalHandler::SIG_TERM;
case SIGHUP: return SignalHandler::SIG_RELOAD;
default:
return SignalHandler::SIG_UNHANDLED;
}
}
#endif //_WIN32
#ifdef _WIN32
BOOL WINAPI WIN32_handleFunc(DWORD signal)
{
if (g_handler)
{
int signo = WIN32_physicalToLogical(signal);
// The std::set is thread-safe in const reading access and we never
// write to it after the program has started so we don't need to
// protect this search by a mutex
std::set<int>::const_iterator found = g_registry.find(signo);
if (signo != -1 && found != g_registry.end())
{
return g_handler->handleSignal(signo) ? TRUE : FALSE;
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
#else
void POSIX_handleFunc(int signal)
{
if (g_handler)
{
int signo = POSIX_physicalToLogical(signal);
g_handler->handleSignal(signo);
}
}
#endif //_WIN32
-2
在Windows上該代碼的工作,我想他可能在Linux上運行。
ui->setupUi(this);
QAction *ctrlp =new QAction("plus",this), *ctrlm = new QAction("minus",this);
ctrlp->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
ctrlm->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus));
connect(ctrlp, SIGNAL(triggered()), this, SLOT(on_pushButton_4_clicked()));
connect(ctrlm, SIGNAL(triggered()), this, SLOT(on_pushButton_5_clicked()));
connect(ui->pushButton_2,SIGNAL(clicked()),SLOT(close()));
ui->textEdit->addAction(ctrlp);
ui->textEdit->addAction(ctrlm);
相關問題
- 1. 如何在Linux上使用C/C++執行DNS查找?
- 2. 如何在Linux上使用C執行切換用戶
- 3. 在Windows和Linux上運行C++程序
- 4. MySQL的QT在Linux和Windows
- 5. 如何在Windows上編譯Botan和Qt?
- 6. 在linux上分配可執行的RAM在c上使用
- 7. 如何編譯C++在Linux上進行,以使Windows二進制
- 8. SQL查詢執行 - 在Windows和Linux
- 9. 如何使用regexp在C/C++中執行glob(Linux)
- 10. 如何在nattable中使用Ctrl + c和ctrl + v?
- 11. 在C#中使用SendMessage在給定的句柄上執行CTRL-C操作
- 12. 如何在Windows上爲Linux生成可執行文件?
- 13. 如何在linux上運行windows擴展名爲.exe的windows可執行文件
- 14. 在Windows上使用python執行程序
- 15. Windows C#執行linux dd命令
- 16. 在Centos(Linux)上執行C#代碼?
- 17. 如何在linux ssh上執行腳本...?
- 18. 如何在windows Qt中使用linux字體?
- 19. 在Windows上混合使用Qt和Objective-C
- 20. 如何使用QT,OpenGL,C++和Linux更改屏幕分辨率?
- 21. linux組合鍵[Ctrl +,]和[Ctrl +。]被禁用?
- 22. 如何使用Eclipse和CDT在Windows上進行C++開發?
- 23. 如何從使用Ctrl-C
- 24. 如何測量'用戶'在Linux和Windows中的函數執行時間
- 25. 如何在Windows XP上使用Perl運行可執行文件?
- 26. 使現有的C#Windows應用程序在Linux上運行
- 27. 如何在Ctrl'C'之前釋放Ctrl時用Qt捕捉Ctrl + C鍵事件?
- 28. 如何在Unix/Linux上使用perl執行批量DNS查詢?
- 29. 使用C++在Linux和Windows機器上的調度任務
- 30. 如何在Qt 5.7中使用Windows SDK?
感謝您發表了這個問題的答案! Stack Overflow不鼓勵使用代碼解答,因爲沒有上下文的代碼轉儲並不能解釋解決方案如何或爲什麼會起作用,這使原始海報(或任何未來的讀者)很難理解其背後的邏輯。請編輯你的問題,幷包括你的代碼的解釋,以便其他人可以從你的答案中受益。謝謝! –
這個答案適用於Qt GUI應用程序,而OP明確要求Qt控制檯應用程序。 OP想要捕獲終止信號並對其進行處理,而不是爲GUI應用程序設置快捷方式處理程序。請參閱[Unix信號](https://en.wikipedia.org/wiki/Unix_signal)瞭解它如何在Linux上運行。 –