OSDN Git Service

55e219446d47abd00ab81dff56953226a04d59fb
[lamexp/LameXP.git] / src / Tool_Abstract.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "Tool_Abstract.h"
23
24 #include "Global.h"
25
26 #include <QProcess>
27 #include <QMutex>
28 #include <QMutexLocker>
29 #include <QLibrary>
30 #include <QProcessEnvironment>
31 #include <QDir>
32
33 /*
34  * Win32 API definitions
35  */
36 typedef HANDLE (WINAPI *CreateJobObjectFun)(__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes, __in_opt LPCSTR lpName);
37 typedef BOOL (WINAPI *SetInformationJobObjectFun)(__in HANDLE hJob, __in JOBOBJECTINFOCLASS JobObjectInformationClass, __in_bcount(cbJobObjectInformationLength) LPVOID lpJobObjectInformation, __in DWORD cbJobObjectInformationLength);
38 typedef BOOL (WINAPI *AssignProcessToJobObjectFun)(__in HANDLE hJob, __in HANDLE hProcess);
39
40 /*
41  * Static vars
42  */
43 QMutex *AbstractTool::m_mutex_startProcess = NULL;
44 HANDLE AbstractTool::m_handle_jobObject = NULL;
45
46 /*
47  * Constructor
48  */
49 AbstractTool::AbstractTool(void)
50 {
51         static CreateJobObjectFun CreateJobObjectPtr = NULL;
52         static SetInformationJobObjectFun SetInformationJobObjectPtr = NULL;
53
54         if(!m_mutex_startProcess)
55         {
56                 m_mutex_startProcess = new QMutex();
57         }
58
59         if(!m_handle_jobObject)
60         {
61                 if(!CreateJobObjectPtr || !SetInformationJobObjectPtr)
62                 {
63                         QLibrary Kernel32Lib("kernel32.dll");
64                         CreateJobObjectPtr = (CreateJobObjectFun) Kernel32Lib.resolve("CreateJobObjectA");
65                         SetInformationJobObjectPtr = (SetInformationJobObjectFun) Kernel32Lib.resolve("SetInformationJobObject");
66                 }
67                 if(CreateJobObjectPtr && SetInformationJobObjectPtr)
68                 {
69                         m_handle_jobObject = CreateJobObjectPtr(NULL, NULL);
70                         if(m_handle_jobObject == INVALID_HANDLE_VALUE)
71                         {
72                                 m_handle_jobObject = NULL;
73                         }
74                         if(m_handle_jobObject)
75                         {
76                                 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo;
77                                 memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
78                                 jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
79                                 SetInformationJobObjectPtr(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
80                         }
81                 }
82         }
83
84         m_firstLaunch = true;
85 }
86
87 /*
88  * Destructor
89  */
90 AbstractTool::~AbstractTool(void)
91 {
92         if(m_handle_jobObject)
93         {
94                 CloseHandle(m_handle_jobObject);
95                 m_handle_jobObject = NULL;
96         }
97 }
98
99 /*
100  * Initialize and launch process object
101  */
102 bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args)
103 {
104         static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr = NULL;
105         
106         QMutexLocker lock(m_mutex_startProcess);
107         emit messageLogged(commandline2string(program, args) + "\n");
108
109         QProcessEnvironment env = process.processEnvironment();
110         if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
111         env.insert("TEMP", QDir::toNativeSeparators(lamexp_temp_folder2()));
112         env.insert("TMP", QDir::toNativeSeparators(lamexp_temp_folder2()));
113         process.setProcessEnvironment(env);
114         
115         if(!AssignProcessToJobObjectPtr)
116         {
117                 QLibrary Kernel32Lib("kernel32.dll");
118                 AssignProcessToJobObjectPtr = (AssignProcessToJobObjectFun) Kernel32Lib.resolve("AssignProcessToJobObject");
119         }
120         
121         process.setProcessChannelMode(QProcess::MergedChannels);
122         process.setReadChannel(QProcess::StandardOutput);
123         process.start(program, args);
124         
125         if(process.waitForStarted())
126         {
127                 
128                 if(AssignProcessToJobObjectPtr)
129                 {
130                         AssignProcessToJobObjectPtr(m_handle_jobObject, process.pid()->hProcess);
131                 }
132                 if(!SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_PRIORITY_CLASS))
133                 {
134                         SetPriorityClass(process.pid()->hProcess, IDLE_PRIORITY_CLASS);
135                 }
136                 
137                 lock.unlock();
138                 
139                 if(m_firstLaunch)
140                 {
141                         emit statusUpdated(0);
142                         m_firstLaunch = false;
143                 }
144                 
145                 return true;
146         }
147
148         emit messageLogged("Process creation has failed :-(");
149         QString errorMsg= process.errorString().trimmed();
150         if(!errorMsg.isEmpty()) emit messageLogged(errorMsg);
151
152         process.kill();
153         process.waitForFinished(-1);
154         return false;
155 }
156
157 /*
158  * Convert program arguments to single string
159  */
160 QString AbstractTool::commandline2string(const QString &program, const QStringList &arguments)
161 {
162         QString commandline = (program.contains(' ') ? QString("\"%1\"").arg(program) : program);
163         
164         for(int i = 0; i < arguments.count(); i++)
165         {
166                 commandline += (arguments.at(i).contains(' ') ? QString(" \"%1\"").arg(arguments.at(i)) : QString(" %1").arg(arguments.at(i)));
167         }
168
169         return commandline;
170 }
171
172 /*
173  * Convert long path to short path
174  */
175 QString AbstractTool::pathToShort(const QString &longPath)
176 {
177         QString shortPath;
178         DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
179         
180         if(buffSize > 0)
181         {
182                 wchar_t *buffer = new wchar_t[buffSize];
183                 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
184
185                 if(result > 0 && result < buffSize)
186                 {
187                         shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
188                 }
189
190                 delete[] buffer;
191         }
192
193         return (shortPath.isEmpty() ? longPath : shortPath);
194 }
195