2 ******************************************************************************
4 * @file consoleprocess_win.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
8 * @see The GNU Public License (GPL) Version 3
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "consoleprocess.h"
32 #include <QtCore/QCoreApplication>
33 #include <QtCore/QDir>
34 #include <QtCore/QTemporaryFile>
35 #include <QtCore/QAbstractEventDispatcher>
36 #include "qwineventnotifier_p.h"
38 #include <QtNetwork/QLocalSocket>
42 using namespace Utils
;
44 ConsoleProcess::ConsoleProcess(QObject
*parent
) :
52 inferiorFinishedNotifier(0),
53 processFinishedNotifier(0)
55 connect(&m_stubServer
, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
58 ConsoleProcess::~ConsoleProcess()
63 bool ConsoleProcess::start(const QString
&program
, const QStringList
&args
)
69 const QString err
= stubServerListen();
71 emit
processError(msgCommChannelFailed(err
));
75 if (!environment().isEmpty()) {
76 m_tempFile
= new QTemporaryFile();
77 if (!m_tempFile
->open()) {
79 emit
processError(msgCannotCreateTempFile(m_tempFile
->errorString()));
84 QTextStream
out(m_tempFile
);
85 out
.setCodec("UTF-16LE");
86 out
.setGenerateByteOrderMark(false);
87 foreach(const QString
&var
, fixWinEnvironment(environment()))
88 out
<< var
<< QChar(0);
93 ZeroMemory(&si
, sizeof(si
));
96 m_pid
= new PROCESS_INFORMATION
;
97 ZeroMemory(m_pid
, sizeof(PROCESS_INFORMATION
));
99 QString workDir
= QDir::toNativeSeparators(workingDirectory());
100 if (!workDir
.isEmpty() && !workDir
.endsWith('\\')) {
101 workDir
.append('\\');
104 QStringList stubArgs
;
105 stubArgs
<< modeOption(m_mode
)
106 << m_stubServer
.fullServerName()
108 << (m_tempFile
? m_tempFile
->fileName() : 0)
109 << createWinCommandline(program
, args
)
110 << msgPromptToClose();
112 const QString cmdLine
= createWinCommandline(
113 QCoreApplication::applicationDirPath() + QLatin1String("/qtcreator_process_stub.exe"), stubArgs
);
115 bool success
= CreateProcessW(0, (WCHAR
*)cmdLine
.utf16(),
116 0, 0, FALSE
, CREATE_NEW_CONSOLE
,
125 stubServerShutdown();
126 emit
processError(tr("The process '%1' could not be started: %2").arg(cmdLine
, winErrorMessage(GetLastError())));
130 processFinishedNotifier
= new QWinEventNotifier(m_pid
->hProcess
, this);
131 connect(processFinishedNotifier
, SIGNAL(activated(HANDLE
)), SLOT(stubExited()));
132 emit
wrapperStarted();
136 void ConsoleProcess::stop()
138 if (m_hInferior
!= NULL
) {
139 TerminateProcess(m_hInferior
, (unsigned)-1);
143 TerminateProcess(m_pid
->hProcess
, (unsigned)-1);
144 WaitForSingleObject(m_pid
->hProcess
, INFINITE
);
149 bool ConsoleProcess::isRunning() const
154 QString
ConsoleProcess::stubServerListen()
156 if (m_stubServer
.listen(QString::fromLatin1("creator-%1-%2")
157 .arg(QCoreApplication::applicationPid())
161 return m_stubServer
.errorString();
164 void ConsoleProcess::stubServerShutdown()
168 if (m_stubServer
.isListening()) {
169 m_stubServer
.close();
173 void ConsoleProcess::stubConnectionAvailable()
175 m_stubSocket
= m_stubServer
.nextPendingConnection();
176 connect(m_stubSocket
, SIGNAL(readyRead()), SLOT(readStubOutput()));
179 void ConsoleProcess::readStubOutput()
181 while (m_stubSocket
->canReadLine()) {
182 QByteArray out
= m_stubSocket
->readLine();
184 if (out
.startsWith("err:chdir ")) {
185 emit
processError(msgCannotChangeToWorkDir(workingDirectory(), winErrorMessage(out
.mid(10).toInt())));
186 } else if (out
.startsWith("err:exec ")) {
187 emit
processError(msgCannotExecute(m_executable
, winErrorMessage(out
.mid(9).toInt())));
188 } else if (out
.startsWith("pid ")) {
189 // Wil not need it any more
193 m_appPid
= out
.mid(4).toInt();
194 m_hInferior
= OpenProcess(
195 SYNCHRONIZE
| PROCESS_QUERY_INFORMATION
| PROCESS_TERMINATE
,
197 if (m_hInferior
== NULL
) {
198 emit
processError(tr("Cannot obtain a handle to the inferior: %1")
199 .arg(winErrorMessage(GetLastError())));
200 // Uhm, and now what?
203 inferiorFinishedNotifier
= new QWinEventNotifier(m_hInferior
, this);
204 connect(inferiorFinishedNotifier
, SIGNAL(activated(HANDLE
)), SLOT(inferiorExited()));
205 emit
processStarted();
207 emit
processError(msgUnexpectedOutput());
208 TerminateProcess(m_pid
->hProcess
, (unsigned)-1);
214 void ConsoleProcess::cleanupInferior()
216 delete inferiorFinishedNotifier
;
217 inferiorFinishedNotifier
= 0;
218 CloseHandle(m_hInferior
);
223 void ConsoleProcess::inferiorExited()
227 if (!GetExitCodeProcess(m_hInferior
, &chldStatus
)) {
228 emit
processError(tr("Cannot obtain exit status from inferior: %1")
229 .arg(winErrorMessage(GetLastError())));
232 m_appStatus
= QProcess::NormalExit
;
233 m_appCode
= chldStatus
;
234 emit
processStopped();
237 void ConsoleProcess::cleanupStub()
239 stubServerShutdown();
240 delete processFinishedNotifier
;
241 processFinishedNotifier
= 0;
242 CloseHandle(m_pid
->hThread
);
243 CloseHandle(m_pid
->hProcess
);
250 void ConsoleProcess::stubExited()
252 // The stub exit might get noticed before we read the pid for the kill.
253 if (m_stubSocket
&& m_stubSocket
->state() == QLocalSocket::ConnectedState
) {
254 m_stubSocket
->waitForDisconnected();
257 if (m_hInferior
!= NULL
) {
258 TerminateProcess(m_hInferior
, (unsigned)-1);
260 m_appStatus
= QProcess::CrashExit
;
262 emit
processStopped();
264 emit
wrapperStopped();