From 1c977ea5a518edf57dbb01a3ca511638d66785a0 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 19 Apr 2011 11:14:57 +0200 Subject: [PATCH] Win: Get debug output from several GUI apps at once Get debug output for all GUI applications at once. This should stop the "Cannot retrieve debugging output". Task-number: QTCREATORBUG-4569 --- .../projectexplorer/projectexplorer.cpp | 3 + .../projectexplorer/projectexplorer.pro | 2 + .../projectexplorer/windebuginterface.cpp | 87 ++++++++++++++ .../projectexplorer/windebuginterface.h | 63 ++++++++++ src/plugins/projectexplorer/winguiprocess.cpp | 112 +++++------------- src/plugins/projectexplorer/winguiprocess.h | 7 +- 6 files changed, 192 insertions(+), 82 deletions(-) create mode 100644 src/plugins/projectexplorer/windebuginterface.cpp create mode 100644 src/plugins/projectexplorer/windebuginterface.h diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 97697fb7bdf..3be417350d5 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -85,6 +85,7 @@ #include "publishing/publishingwizardselectiondialog.h" #ifdef Q_OS_WIN +# include "windebuginterface.h" # include "msvctoolchain.h" #endif @@ -305,6 +306,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // Add ToolChainFactories: #ifdef Q_OS_WIN + addAutoReleasedObject(new WinDebugInterface); + addAutoReleasedObject(new Internal::MingwToolChainFactory); addAutoReleasedObject(new Internal::MsvcToolChainFactory); #else diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 7b77b27f8f0..81c4973a3b7 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -212,10 +212,12 @@ equals(TEST, 1) { win32 { SOURCES += applicationlauncher_win.cpp \ + windebuginterface.cpp \ winguiprocess.cpp \ msvcparser.cpp \ msvctoolchain.cpp HEADERS += winguiprocess.h \ + windebuginterface.h \ msvcparser.h \ msvctoolchain.h } else { diff --git a/src/plugins/projectexplorer/windebuginterface.cpp b/src/plugins/projectexplorer/windebuginterface.cpp new file mode 100644 index 00000000000..01c704ce958 --- /dev/null +++ b/src/plugins/projectexplorer/windebuginterface.cpp @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "windebuginterface.h" + +namespace ProjectExplorer { +namespace Internal { + +WinDebugInterface *WinDebugInterface::m_instance = 0; + +WinDebugInterface *WinDebugInterface::instance() +{ + return m_instance; +} + + +WinDebugInterface::WinDebugInterface(QObject *parent) : + QThread(parent) +{ + m_instance = this; + start(); +} + +void WinDebugInterface::run() +{ + HANDLE bufferReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_BUFFER_READY"); + if (!bufferReadyEvent) + return; + HANDLE dataReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_DATA_READY"); + if (!dataReadyEvent) + return; + HANDLE sharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, L"DBWIN_BUFFER"); + if (!sharedFile) + return; + LPVOID sharedMem = MapViewOfFile(sharedFile, FILE_MAP_READ, 0, 0, 512); + if (!sharedMem) + return; + + LPSTR message; + LPDWORD processId; + + message = reinterpret_cast(sharedMem) + sizeof(DWORD); + processId = reinterpret_cast(sharedMem); + + SetEvent(bufferReadyEvent); + + while (true) { + DWORD ret = WaitForSingleObject(dataReadyEvent, INFINITE); + + if (ret == WAIT_OBJECT_0) { + emit debugOutput(*processId, QString::fromLocal8Bit(message)); + SetEvent(bufferReadyEvent); + } + } +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/windebuginterface.h b/src/plugins/projectexplorer/windebuginterface.h new file mode 100644 index 00000000000..f652b2e9526 --- /dev/null +++ b/src/plugins/projectexplorer/windebuginterface.h @@ -0,0 +1,63 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef WINDEBUGINTERFACE_H +#define WINDEBUGINTERFACE_H + +#include + +#include + +namespace ProjectExplorer { +namespace Internal { + +class WinDebugInterface : public QThread +{ + Q_OBJECT + +public: + explicit WinDebugInterface(QObject *parent = 0); + static WinDebugInterface *instance(); + +signals: + void debugOutput(qint64 pid, const QString &message); + +private: + void run(); + + static WinDebugInterface *m_instance; +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // WINDEBUGINTERFACE_H diff --git a/src/plugins/projectexplorer/winguiprocess.cpp b/src/plugins/projectexplorer/winguiprocess.cpp index 62db7ee5e97..fb410dd0249 100644 --- a/src/plugins/projectexplorer/winguiprocess.cpp +++ b/src/plugins/projectexplorer/winguiprocess.cpp @@ -31,6 +31,7 @@ **************************************************************************/ #include "winguiprocess.h" +#include "windebuginterface.h" #include "consoleprocess.h" #include @@ -48,11 +49,12 @@ using namespace ProjectExplorer::Internal; visible. Uses the debug interface and emits via a signal. */ -WinGuiProcess::WinGuiProcess(QObject *parent) - : QThread(parent) +WinGuiProcess::WinGuiProcess(QObject *parent) : + QThread(parent), + m_pid(0), + m_exitCode(0) { - m_pid = 0; - m_exitCode = 0; + connect(this, SIGNAL(processFinished(int)), this, SLOT(done())); } WinGuiProcess::~WinGuiProcess() @@ -60,16 +62,24 @@ WinGuiProcess::~WinGuiProcess() stop(); } +bool WinGuiProcess::isRunning() const +{ + return QThread::isRunning(); +} + bool WinGuiProcess::start(const QString &program, const QString &args) { + if (isRunning()) + return false; + + connect(WinDebugInterface::instance(), SIGNAL(debugOutput(qint64,QString)), + this, SLOT(checkDebugOutput(qint64,QString))); + m_program = program; m_args = args; - if (!isRunning()) { - QThread::start(QThread::NormalPriority); - return true; - } - return false; + QThread::start(); + return true; } void WinGuiProcess::stop() @@ -79,29 +89,6 @@ void WinGuiProcess::stop() wait(); } -bool WinGuiProcess::isRunning() const -{ - return QThread::isRunning(); -} - -bool WinGuiProcess::setupDebugInterface(HANDLE &bufferReadyEvent, HANDLE &dataReadyEvent, HANDLE &sharedFile, LPVOID &sharedMem) -{ - - bufferReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_BUFFER_READY"); - if (!bufferReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS) - return false; - dataReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_DATA_READY"); - if (!dataReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS) - return false; - sharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, L"DBWIN_BUFFER"); - if (!sharedFile || GetLastError() == ERROR_ALREADY_EXISTS) - return false; - sharedMem = MapViewOfFile(sharedFile, FILE_MAP_READ, 0, 0, 512); - if (!sharedMem) - return false; - return true; -} - void WinGuiProcess::run() { if (m_pid) @@ -117,15 +104,7 @@ void WinGuiProcess::run() m_exitCode = 0; bool started = false; - HANDLE bufferReadyEvent = NULL; - HANDLE dataReadyEvent = NULL; - HANDLE sharedFile = NULL; - LPVOID sharedMem = 0; - do { - - const bool dbgInterface = setupDebugInterface(bufferReadyEvent, dataReadyEvent, sharedFile, sharedMem); - QString pcmd, pargs; QtcProcess::prepareCommand(m_program, m_args, &pcmd, &pargs, &m_environment, &m_workingDir); const QString cmdLine = createWinCommandline(pcmd, pargs); @@ -145,38 +124,7 @@ void WinGuiProcess::run() break; } - if (!dbgInterface) { - // Text is filtered in qmlengine.cpp - emit receivedDebugOutput(Utils::AbstractProcess::msgWinCannotRetrieveDebuggingOutput(), true); - WaitForSingleObject(m_pid->hProcess, INFINITE); - } else { - LPSTR message; - LPDWORD processId; - HANDLE toWaitFor[2]; - - message = reinterpret_cast(sharedMem) + sizeof(DWORD); - processId = reinterpret_cast(sharedMem); - - SetEvent(bufferReadyEvent); - - toWaitFor[0] = dataReadyEvent; - toWaitFor[1] = m_pid->hProcess; - - for (bool stop = false; !stop;) { - DWORD ret = WaitForMultipleObjects(2, toWaitFor, FALSE, INFINITE); - - switch (ret) { - case WAIT_OBJECT_0 + 0: - if (*processId == m_pid->dwProcessId) - emit receivedDebugOutput(QString::fromLocal8Bit(message), false); - SetEvent(bufferReadyEvent); - break; - case WAIT_OBJECT_0 + 1: - stop = true; - break; - } - } - } + WaitForSingleObject(m_pid->hProcess, INFINITE); } while (false); if (started) { @@ -184,14 +132,6 @@ void WinGuiProcess::run() emit processFinished(static_cast(m_exitCode)); } - if (sharedMem) - UnmapViewOfFile(sharedMem); - if (sharedFile != NULL) - CloseHandle(sharedFile); - if (bufferReadyEvent != NULL) - CloseHandle(bufferReadyEvent); - if (dataReadyEvent != NULL) - CloseHandle(dataReadyEvent); if (m_pid->hProcess != NULL) CloseHandle(m_pid->hProcess); if (m_pid->hThread != NULL) @@ -200,6 +140,18 @@ void WinGuiProcess::run() m_pid = 0; } +void WinGuiProcess::checkDebugOutput(qint64 pid, const QString &message) +{ + if (applicationPID() == pid) + emit receivedDebugOutput(message, false); +} + +void WinGuiProcess::done() +{ + disconnect(WinDebugInterface::instance(), SIGNAL(debugOutput(qint64,QString)), + this, SLOT(checkDebugOutput(qint64,QString))); +} + qint64 WinGuiProcess::applicationPID() const { if (m_pid) diff --git a/src/plugins/projectexplorer/winguiprocess.h b/src/plugins/projectexplorer/winguiprocess.h index c7efe398457..8a6c995ba1a 100644 --- a/src/plugins/projectexplorer/winguiprocess.h +++ b/src/plugins/projectexplorer/winguiprocess.h @@ -54,10 +54,10 @@ public: explicit WinGuiProcess(QObject *parent = 0); virtual ~WinGuiProcess(); + bool isRunning() const; bool start(const QString &program, const QString &args); void stop(); - bool isRunning() const; qint64 applicationPID() const; int exitCode() const; @@ -66,8 +66,11 @@ signals: void receivedDebugOutput(const QString &output, bool isError); void processFinished(int exitCode); +private slots: + void checkDebugOutput(qint64, const QString &); + void done(); + private: - bool setupDebugInterface(HANDLE &bufferReadyEvent, HANDLE &dataReadyEvent, HANDLE &sharedFile, LPVOID &sharedMem); void run(); PROCESS_INFORMATION *m_pid;