/src/qt/qtbase/src/corelib/io/qprocess_wince.cpp

https://gitlab.com/x33n/phantomjs · C++ · 342 lines · 235 code · 57 blank · 50 comment · 36 complexity · 6450645af68766c3a66e44b2c346cee0 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the QtCore module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qprocess.h"
  42. #include "qprocess_p.h"
  43. #include "qwindowspipewriter_p.h"
  44. #include <qdir.h>
  45. #include <qfileinfo.h>
  46. #include <qregexp.h>
  47. #include <qtimer.h>
  48. #include <qwineventnotifier.h>
  49. #include <qdebug.h>
  50. #include <private/qthread_p.h>
  51. #ifndef QT_NO_PROCESS
  52. QT_BEGIN_NAMESPACE
  53. //#define QPROCESS_DEBUG
  54. void QProcessPrivate::destroyPipe(Q_PIPE pipe[2])
  55. {
  56. Q_UNUSED(pipe);
  57. }
  58. void QProcessPrivate::destroyChannel(Channel *channel)
  59. {
  60. Q_UNUSED(channel);
  61. }
  62. static QString qt_create_commandline(const QString &program, const QStringList &arguments)
  63. {
  64. QString args;
  65. if (!program.isEmpty()) {
  66. QString programName = program;
  67. if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
  68. programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
  69. programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
  70. // add the prgram as the first arg ... it works better
  71. args = programName + QLatin1Char(' ');
  72. }
  73. for (int i=0; i<arguments.size(); ++i) {
  74. QString tmp = arguments.at(i);
  75. // Quotes are escaped and their preceding backslashes are doubled.
  76. tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
  77. if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
  78. // The argument must not end with a \ since this would be interpreted
  79. // as escaping the quote -- rather put the \ behind the quote: e.g.
  80. // rather use "foo"\ than "foo\"
  81. int i = tmp.length();
  82. while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\'))
  83. --i;
  84. tmp.insert(i, QLatin1Char('"'));
  85. tmp.prepend(QLatin1Char('"'));
  86. }
  87. args += QLatin1Char(' ') + tmp;
  88. }
  89. return args;
  90. }
  91. QProcessEnvironment QProcessEnvironment::systemEnvironment()
  92. {
  93. QProcessEnvironment env;
  94. return env;
  95. }
  96. void QProcessPrivate::startProcess()
  97. {
  98. Q_Q(QProcess);
  99. bool success = false;
  100. if (pid) {
  101. CloseHandle(pid->hThread);
  102. CloseHandle(pid->hProcess);
  103. delete pid;
  104. pid = 0;
  105. }
  106. pid = new PROCESS_INFORMATION;
  107. memset(pid, 0, sizeof(PROCESS_INFORMATION));
  108. q->setProcessState(QProcess::Starting);
  109. QString args = qt_create_commandline(QString(), arguments);
  110. if (!nativeArguments.isEmpty()) {
  111. if (!args.isEmpty())
  112. args += QLatin1Char(' ');
  113. args += nativeArguments;
  114. }
  115. #if defined QPROCESS_DEBUG
  116. qDebug("Creating process");
  117. qDebug(" program : [%s]", program.toLatin1().constData());
  118. qDebug(" args : %s", args.toLatin1().constData());
  119. qDebug(" pass environment : %s", environment.isEmpty() ? "no" : "yes");
  120. #endif
  121. QString fullPathProgram = program;
  122. if (!QDir::isAbsolutePath(fullPathProgram))
  123. fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath();
  124. fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\'));
  125. success = CreateProcess((wchar_t*)fullPathProgram.utf16(),
  126. (wchar_t*)args.utf16(),
  127. 0, 0, false, 0, 0, 0, 0, pid);
  128. if (!success) {
  129. cleanup();
  130. processError = QProcess::FailedToStart;
  131. emit q->error(processError);
  132. q->setProcessState(QProcess::NotRunning);
  133. return;
  134. }
  135. q->setProcessState(QProcess::Running);
  136. // User can call kill()/terminate() from the stateChanged() slot
  137. // so check before proceeding
  138. if (!pid)
  139. return;
  140. if (threadData->hasEventDispatcher()) {
  141. processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
  142. QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
  143. processFinishedNotifier->setEnabled(true);
  144. }
  145. // give the process a chance to start ...
  146. Sleep(SLEEPMIN * 2);
  147. _q_startupNotification();
  148. }
  149. bool QProcessPrivate::processStarted()
  150. {
  151. return processState == QProcess::Running;
  152. }
  153. qint64 QProcessPrivate::bytesAvailableFromStdout() const
  154. {
  155. return 0;
  156. }
  157. qint64 QProcessPrivate::bytesAvailableFromStderr() const
  158. {
  159. return 0;
  160. }
  161. qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
  162. {
  163. return -1;
  164. }
  165. qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
  166. {
  167. return -1;
  168. }
  169. static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId)
  170. {
  171. DWORD currentProcId = 0;
  172. GetWindowThreadProcessId(hwnd, &currentProcId);
  173. if (currentProcId == (DWORD)procId)
  174. PostMessage(hwnd, WM_CLOSE, 0, 0);
  175. return TRUE;
  176. }
  177. void QProcessPrivate::terminateProcess()
  178. {
  179. if (pid) {
  180. EnumWindows(qt_terminateApp, (LPARAM)pid->dwProcessId);
  181. PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
  182. }
  183. }
  184. void QProcessPrivate::killProcess()
  185. {
  186. if (pid)
  187. TerminateProcess(pid->hProcess, 0xf291);
  188. }
  189. bool QProcessPrivate::waitForStarted(int)
  190. {
  191. Q_Q(QProcess);
  192. if (processStarted())
  193. return true;
  194. if (processError == QProcess::FailedToStart)
  195. return false;
  196. processError = QProcess::Timedout;
  197. q->setErrorString(QProcess::tr("Process operation timed out"));
  198. return false;
  199. }
  200. bool QProcessPrivate::drainOutputPipes()
  201. {
  202. return true;
  203. }
  204. bool QProcessPrivate::waitForReadyRead(int msecs)
  205. {
  206. return false;
  207. }
  208. bool QProcessPrivate::waitForBytesWritten(int msecs)
  209. {
  210. return false;
  211. }
  212. bool QProcessPrivate::waitForFinished(int msecs)
  213. {
  214. Q_Q(QProcess);
  215. #if defined QPROCESS_DEBUG
  216. qDebug("QProcessPrivate::waitForFinished(%d)", msecs);
  217. #endif
  218. QIncrementalSleepTimer timer(msecs);
  219. forever {
  220. if (!pid)
  221. return true;
  222. if (WaitForSingleObject(pid->hProcess, timer.nextSleepTime()) == WAIT_OBJECT_0) {
  223. _q_processDied();
  224. return true;
  225. }
  226. if (timer.hasTimedOut())
  227. break;
  228. }
  229. processError = QProcess::Timedout;
  230. q->setErrorString(QProcess::tr("Process operation timed out"));
  231. return false;
  232. }
  233. void QProcessPrivate::findExitCode()
  234. {
  235. DWORD theExitCode;
  236. if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
  237. exitCode = theExitCode;
  238. //### for now we assume a crash if exit code is less than -1 or the magic number
  239. crashed = (exitCode == 0xf291 || (int)exitCode < 0);
  240. }
  241. }
  242. void QProcessPrivate::flushPipeWriter()
  243. {
  244. }
  245. qint64 QProcessPrivate::pipeWriterBytesToWrite() const
  246. {
  247. return 0;
  248. }
  249. qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
  250. {
  251. Q_UNUSED(data);
  252. Q_UNUSED(maxlen);
  253. return -1;
  254. }
  255. bool QProcessPrivate::waitForWrite(int msecs)
  256. {
  257. Q_UNUSED(msecs);
  258. return false;
  259. }
  260. void QProcessPrivate::_q_notified()
  261. {
  262. }
  263. bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
  264. {
  265. Q_UNUSED(workingDir);
  266. QString args = qt_create_commandline(QString(), arguments);
  267. bool success = false;
  268. PROCESS_INFORMATION pinfo;
  269. QString fullPathProgram = program;
  270. if (!QDir::isAbsolutePath(fullPathProgram))
  271. fullPathProgram.prepend(QDir::currentPath().append(QLatin1Char('/')));
  272. fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\'));
  273. success = CreateProcess((wchar_t*)fullPathProgram.utf16(),
  274. (wchar_t*)args.utf16(),
  275. 0, 0, false, CREATE_NEW_CONSOLE, 0, 0, 0, &pinfo);
  276. if (success) {
  277. CloseHandle(pinfo.hThread);
  278. CloseHandle(pinfo.hProcess);
  279. if (pid)
  280. *pid = pinfo.dwProcessId;
  281. }
  282. return success;
  283. }
  284. QT_END_NAMESPACE
  285. #endif // QT_NO_PROCESS