1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "winrtrunnerhelper.h"
27
28 #include "winrtconstants.h"
29 #include "winrtrunconfiguration.h"
30
31 #include <coreplugin/idocument.h>
32
33 #include <projectexplorer/buildtargetinfo.h>
34 #include <projectexplorer/devicesupport/idevice.h>
35 #include <projectexplorer/buildconfiguration.h>
36 #include <projectexplorer/project.h>
37 #include <projectexplorer/runcontrol.h>
38 #include <projectexplorer/target.h>
39
40 #include <qtsupport/baseqtversion.h>
41 #include <qtsupport/qtkitinformation.h>
42 #include <utils/qtcprocess.h>
43
44 #include <QDir>
45
46 using namespace ProjectExplorer;
47
48 using namespace WinRt;
49 using namespace WinRt::Internal;
50
WinRtRunnerHelper(ProjectExplorer::RunWorker * runWorker,QString * errorMessage)51 WinRtRunnerHelper::WinRtRunnerHelper(ProjectExplorer::RunWorker *runWorker, QString *errorMessage)
52 : QObject(runWorker)
53 , m_worker(runWorker)
54 {
55 auto runControl = runWorker->runControl();
56
57 m_device = runWorker->device().dynamicCast<const WinRtDevice>();
58
59 const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(runControl->kit());
60 if (!qt) {
61 *errorMessage = tr("The current kit has no Qt version.");
62 return;
63 }
64
65 m_runnerFilePath = qt->hostBinPath().toString() + QStringLiteral("/winrtrunner.exe");
66 if (!QFile::exists(m_runnerFilePath)) {
67 *errorMessage = tr("Cannot find winrtrunner.exe in \"%1\".").arg(
68 QDir::toNativeSeparators(qt->hostBinPath().toString()));
69 return;
70 }
71
72 m_executableFilePath = runControl->targetFilePath().toString();
73
74 if (m_executableFilePath.isEmpty()) {
75 *errorMessage = tr("Cannot determine the executable file path for \"%1\".")
76 .arg(runControl->projectFilePath().toUserOutput());
77 return;
78 }
79
80 // ### we should not need to append ".exe" here.
81 if (!m_executableFilePath.endsWith(QLatin1String(".exe")))
82 m_executableFilePath += QStringLiteral(".exe");
83
84
85 bool loopbackExemptClient = false;
86 bool loopbackExemptServer = false;
87 if (auto aspect = runControl->aspect<ArgumentsAspect>())
88 m_arguments = aspect->arguments(runControl->macroExpander());
89 if (auto aspect = runControl->aspect<UninstallAfterStopAspect>())
90 m_uninstallAfterStop = aspect->value();
91 if (auto aspect = runControl->aspect<LoopbackExemptClientAspect>())
92 loopbackExemptClient = aspect->value();
93 if (auto aspect = runControl->aspect<LoopbackExemptServerAspect>())
94 loopbackExemptServer = aspect->value();
95 if (loopbackExemptClient && loopbackExemptServer)
96 m_loopbackArguments = QStringList{"--loopbackexempt", "clientserver"};
97 else if (loopbackExemptClient)
98 m_loopbackArguments = QStringList{"--loopbackexempt", "client"};
99 else if (loopbackExemptServer)
100 m_loopbackArguments = QStringList{"--loopbackexempt", "server"};
101 }
102
appendMessage(const QString & message,Utils::OutputFormat format)103 void WinRtRunnerHelper::appendMessage(const QString &message, Utils::OutputFormat format)
104 {
105 QTC_ASSERT(m_worker, return);
106 m_worker->appendMessage(message, format);
107 }
108
debug(const QString & debuggerExecutable,const QString & debuggerArguments)109 void WinRtRunnerHelper::debug(const QString &debuggerExecutable, const QString &debuggerArguments)
110 {
111 m_debuggerExecutable = debuggerExecutable;
112 m_debuggerArguments = debuggerArguments;
113 startWinRtRunner(Debug);
114 }
115
start()116 void WinRtRunnerHelper::start()
117 {
118 startWinRtRunner(Start);
119 }
120
stop()121 void WinRtRunnerHelper::stop()
122 {
123 if (m_process)
124 m_process->interrupt();
125 else
126 startWinRtRunner(Stop);
127 }
128
waitForStarted(int msecs)129 bool WinRtRunnerHelper::waitForStarted(int msecs)
130 {
131 QTC_ASSERT(m_process, return false);
132 return m_process->waitForStarted(msecs);
133 }
134
onProcessReadyReadStdOut()135 void WinRtRunnerHelper::onProcessReadyReadStdOut()
136 {
137 QTC_ASSERT(m_process, return);
138 appendMessage(QString::fromLocal8Bit(m_process->readAllStandardOutput()), Utils::StdOutFormat);
139 }
140
onProcessReadyReadStdErr()141 void WinRtRunnerHelper::onProcessReadyReadStdErr()
142 {
143 QTC_ASSERT(m_process, return);
144 appendMessage(QString::fromLocal8Bit(m_process->readAllStandardError()), Utils::StdErrFormat);
145 }
146
onProcessFinished()147 void WinRtRunnerHelper::onProcessFinished()
148 {
149 QTC_ASSERT(m_process, return);
150 m_process->disconnect();
151 m_process->deleteLater();
152 m_process = nullptr;
153 emit finished();
154 }
155
onProcessError(QProcess::ProcessError processError)156 void WinRtRunnerHelper::onProcessError(QProcess::ProcessError processError)
157 {
158 QTC_ASSERT(m_process, return);
159 appendMessage(tr("Error while executing the WinRT Runner Tool: %1\n").arg(
160 m_process->errorString()), Utils::ErrorMessageFormat);
161 m_process->disconnect();
162 m_process->deleteLater();
163 m_process = nullptr;
164 emit error(processError);
165 }
166
startWinRtRunner(const RunConf & conf)167 void WinRtRunnerHelper::startWinRtRunner(const RunConf &conf)
168 {
169 using namespace Utils;
170 CommandLine cmdLine(FilePath::fromString(m_runnerFilePath), {});
171 if (m_device) {
172 cmdLine.addArg("--device");
173 cmdLine.addArg(QString::number(m_device->deviceId()));
174 }
175
176 QtcProcess *process = nullptr;
177 bool connectProcess = false;
178
179 switch (conf) {
180 case Debug:
181 cmdLine.addArg("--debug");
182 cmdLine.addArg(m_debuggerExecutable);
183 if (!m_debuggerArguments.isEmpty()) {
184 cmdLine.addArg("--debugger-arguments");
185 cmdLine.addArg(m_debuggerArguments);
186 }
187 Q_FALLTHROUGH();
188 case Start:
189 cmdLine.addArgs({"--start", "--stop", "--wait", "0"});
190 connectProcess = true;
191 QTC_ASSERT(!m_process, m_process->deleteLater());
192 m_process = new QtcProcess(this);
193 process = m_process;
194 break;
195 case Stop:
196 cmdLine.addArg("--stop");
197 process = new QtcProcess(this);
198 break;
199 }
200
201 if (m_device->type() == Constants::WINRT_DEVICE_TYPE_LOCAL)
202 cmdLine.addArgs({"--profile", "appx"});
203 else if (m_device->type() == Constants::WINRT_DEVICE_TYPE_PHONE ||
204 m_device->type() == Constants::WINRT_DEVICE_TYPE_EMULATOR)
205 cmdLine.addArgs({"--profile", "appxphone"});
206
207 cmdLine.addArgs(m_loopbackArguments);
208 cmdLine.addArg(m_executableFilePath);
209 cmdLine.addArgs(m_arguments, CommandLine::Raw);
210
211 appendMessage(cmdLine.toUserOutput(), NormalMessageFormat);
212
213 if (connectProcess) {
214 connect(process, &QtcProcess::started, this, &WinRtRunnerHelper::started);
215 connect(process, &QtcProcess::finished, this, &WinRtRunnerHelper::onProcessFinished);
216 connect(process, &QtcProcess::errorOccurred, this, &WinRtRunnerHelper::onProcessError);
217 connect(process, &QtcProcess::readyReadStandardOutput, this, &WinRtRunnerHelper::onProcessReadyReadStdOut);
218 connect(process, &QtcProcess::readyReadStandardError, this, &WinRtRunnerHelper::onProcessReadyReadStdErr);
219 }
220
221 process->setUseCtrlCStub(true);
222 process->setCommand(cmdLine);
223 process->setEnvironment(m_worker->runControl()->buildEnvironment());
224 process->setWorkingDirectory(QFileInfo(m_executableFilePath).absolutePath());
225 process->start();
226 }
227