OSDN Git Service

f216bea0efb6e373db7c7a25ca8c89c317993515
[qt-creator-jp/qt-creator-jp.git] / src / plugins / projectexplorer / winguiprocess.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "winguiprocess.h"
35 #include "consoleprocess.h"
36
37 #include <utils/qtcprocess.h>
38 #include <utils/winutils.h>
39
40 #include <QtCore/QDir>
41
42 using namespace ProjectExplorer::Internal;
43
44 WinGuiProcess::WinGuiProcess(QObject *parent)
45     : QThread(parent)
46 {
47     m_pid = 0;
48     m_exitCode = 0;
49 }
50
51 WinGuiProcess::~WinGuiProcess()
52 {
53     stop();
54 }
55
56 bool WinGuiProcess::start(const QString &program, const QString &args)
57 {
58     m_program = program;
59     m_args = args;
60
61     if (!isRunning()) {
62         QThread::start(QThread::NormalPriority);
63         return true;
64     }
65     return false;
66 }
67
68 void WinGuiProcess::stop()
69 {
70     if (m_pid)
71         TerminateProcess(m_pid->hProcess, 1);
72     wait();
73 }
74
75 bool WinGuiProcess::isRunning() const
76 {
77     return QThread::isRunning();
78 }
79
80 bool WinGuiProcess::setupDebugInterface(HANDLE &bufferReadyEvent, HANDLE &dataReadyEvent, HANDLE &sharedFile, LPVOID &sharedMem)
81 {
82
83     bufferReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_BUFFER_READY");
84     if (!bufferReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS)
85         return false;
86     dataReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_DATA_READY");
87     if (!dataReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS)
88         return false;
89     sharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, L"DBWIN_BUFFER");
90     if (!sharedFile || GetLastError() == ERROR_ALREADY_EXISTS)
91         return false;
92     sharedMem = MapViewOfFile(sharedFile, FILE_MAP_READ, 0, 0,  512);
93     if (!sharedMem)
94         return false;
95     return true;
96 }
97
98 void WinGuiProcess::run()
99 {
100     if (m_pid)
101         return;
102
103     STARTUPINFO si;
104     ZeroMemory(&si, sizeof(si));
105     si.cb = sizeof(si);
106
107     m_pid = new PROCESS_INFORMATION;
108     ZeroMemory(m_pid, sizeof(PROCESS_INFORMATION));
109
110     m_exitCode = 0;
111     bool started = false;
112
113     HANDLE bufferReadyEvent = NULL;
114     HANDLE dataReadyEvent = NULL;
115     HANDLE sharedFile = NULL;
116     LPVOID sharedMem = 0;
117
118     do {
119
120         const bool dbgInterface = setupDebugInterface(bufferReadyEvent, dataReadyEvent, sharedFile, sharedMem);
121
122         QString pcmd, pargs;
123         QtcProcess::prepareCommand(m_program, m_args, &pcmd, &pargs, &m_environment, &m_workingDir);
124         const QString cmdLine = createWinCommandline(pcmd, pargs);
125         const QStringList env = m_environment.toStringList();
126         started = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
127                                       0, 0, TRUE, CREATE_UNICODE_ENVIRONMENT,
128                                       env.isEmpty() ? 0
129                                           : createWinEnvironment(fixWinEnvironment(env)).data(),
130                                           workingDirectory().isEmpty() ? 0
131                                               : (WCHAR*)QDir::convertSeparators(workingDirectory()).utf16(),
132                                               &si, m_pid);
133
134         if (!started) {
135             emit processMessage(tr("The process could not be started: %1").
136                                 arg(Utils::winErrorMessage(GetLastError())), true);
137             emit processFinished(0);
138             break;
139         }
140
141         if (!dbgInterface) {
142             // Text is filtered in qmlengine.cpp
143             emit receivedDebugOutput(Utils::AbstractProcess::msgWinCannotRetrieveDebuggingOutput(), true);
144             WaitForSingleObject(m_pid->hProcess, INFINITE);
145         } else {
146             LPSTR  message;
147             LPDWORD processId;
148             HANDLE toWaitFor[2];
149
150             message = reinterpret_cast<LPSTR>(sharedMem) + sizeof(DWORD);
151             processId = reinterpret_cast<LPDWORD>(sharedMem);
152
153             SetEvent(bufferReadyEvent);
154
155             toWaitFor[0] = dataReadyEvent;
156             toWaitFor[1] = m_pid->hProcess;
157
158             for (bool stop = false; !stop;) {
159                 DWORD ret = WaitForMultipleObjects(2, toWaitFor, FALSE, INFINITE);
160
161                 switch (ret) {
162                 case WAIT_OBJECT_0 + 0:
163                     if (*processId == m_pid->dwProcessId)
164                         emit receivedDebugOutput(QString::fromLocal8Bit(message), false);
165                     SetEvent(bufferReadyEvent);
166                     break;
167                 case WAIT_OBJECT_0 + 1:
168                     stop = true;
169                     break;
170                 }
171             }
172         }
173     } while (false);
174
175     if (started) {
176         GetExitCodeProcess(m_pid->hProcess, &m_exitCode);
177         emit processFinished(static_cast<int>(m_exitCode));
178     }
179
180     if (sharedMem)
181         UnmapViewOfFile(sharedMem);
182     if (sharedFile != NULL)
183         CloseHandle(sharedFile);
184     if (bufferReadyEvent != NULL)
185         CloseHandle(bufferReadyEvent);
186     if (dataReadyEvent != NULL)
187         CloseHandle(dataReadyEvent);
188     if (m_pid->hProcess != NULL)
189         CloseHandle(m_pid->hProcess);
190     if  (m_pid->hThread != NULL)
191         CloseHandle(m_pid->hThread);
192     delete m_pid;
193     m_pid = 0;
194 }
195
196 qint64 WinGuiProcess::applicationPID() const
197 {
198     if (m_pid)
199         return m_pid->dwProcessId;
200     return 0;
201 }
202
203 int WinGuiProcess::exitCode() const
204 {
205     return static_cast<int>(m_exitCode);
206 }