1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
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.
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.
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.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Tool_Abstract.h"
28 #include <QMutexLocker>
30 #include <QProcessEnvironment>
34 * Win32 API definitions
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
);
43 quint64
AbstractTool::s_lastLaunchTime
= 0ui
64;
44 QMutex
AbstractTool::s_mutex_startProcess
;
45 HANDLE
AbstractTool::s_handle_jobObject
= NULL
;
46 unsigned int AbstractTool::s_jobObjRefCount
= 0U;
51 static const DWORD START_DELAY
= 333; //in milliseconds
52 static const quint64 START_DELAY_NANO
= START_DELAY
* 1000 * 10; //in 100-nanosecond intervals
57 AbstractTool::AbstractTool(void)
59 static CreateJobObjectFun CreateJobObjectPtr
= NULL
;
60 static SetInformationJobObjectFun SetInformationJobObjectPtr
= NULL
;
62 QMutexLocker
lock(&s_mutex_startProcess
);
64 if(s_jobObjRefCount
< 1U)
66 DWORD osVersionNo
= lamexp_get_os_version();
67 if(LAMEXP_MIN_OS_VER(osVersionNo
, 5, 1))
69 if((!CreateJobObjectPtr
) || (!SetInformationJobObjectPtr
))
71 QLibrary
Kernel32Lib("kernel32.dll");
72 CreateJobObjectPtr
= (CreateJobObjectFun
) Kernel32Lib
.resolve("CreateJobObjectA");
73 SetInformationJobObjectPtr
= (SetInformationJobObjectFun
) Kernel32Lib
.resolve("SetInformationJobObject");
76 if(CreateJobObjectPtr
&& SetInformationJobObjectPtr
)
78 HANDLE jobObject
= CreateJobObjectPtr(NULL
, NULL
);
79 if((jobObject
!= NULL
) && (jobObject
!= INVALID_HANDLE_VALUE
))
81 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo
;
82 memset(&jobExtendedLimitInfo
, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
));
83 memset(&jobExtendedLimitInfo
.BasicLimitInformation
, 0, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION
));
84 jobExtendedLimitInfo
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
| JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
;
85 if(SetInformationJobObjectPtr(jobObject
, JobObjectExtendedLimitInformation
, &jobExtendedLimitInfo
, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
)))
87 s_handle_jobObject
= jobObject
;
88 s_jobObjRefCount
= 1U;
92 qWarning("Failed to set job object information!");
93 CloseHandle(jobObject
);
98 qWarning("Failed to create the job object!");
107 m_firstLaunch
= true;
113 AbstractTool::~AbstractTool(void)
115 QMutexLocker
lock(&s_mutex_startProcess
);
117 if(s_jobObjRefCount
>= 1U)
120 if((s_jobObjRefCount
< 1U) && s_handle_jobObject
)
122 CloseHandle(s_handle_jobObject
);
123 s_handle_jobObject
= NULL
;
129 * Initialize and launch process object
131 bool AbstractTool::startProcess(QProcess
&process
, const QString
&program
, const QStringList
&args
)
133 static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr
= NULL
;
135 QMutexLocker
lock(&s_mutex_startProcess
);
137 if(currentTime() <= s_lastLaunchTime
)
142 emit
messageLogged(commandline2string(program
, args
) + "\n");
144 QProcessEnvironment env
= process
.processEnvironment();
145 if(env
.isEmpty()) env
= QProcessEnvironment::systemEnvironment();
146 env
.insert("TEMP", QDir::toNativeSeparators(lamexp_temp_folder2()));
147 env
.insert("TMP", QDir::toNativeSeparators(lamexp_temp_folder2()));
148 process
.setProcessEnvironment(env
);
150 if(!AssignProcessToJobObjectPtr
)
152 QLibrary
Kernel32Lib("kernel32.dll");
153 AssignProcessToJobObjectPtr
= (AssignProcessToJobObjectFun
) Kernel32Lib
.resolve("AssignProcessToJobObject");
156 process
.setProcessChannelMode(QProcess::MergedChannels
);
157 process
.setReadChannel(QProcess::StandardOutput
);
158 process
.start(program
, args
);
160 if(process
.waitForStarted())
162 if(AssignProcessToJobObjectPtr
&& s_handle_jobObject
)
164 if(!AssignProcessToJobObjectPtr(s_handle_jobObject
, process
.pid()->hProcess
))
166 qWarning("Failed to assign process to job object!");
169 if(!SetPriorityClass(process
.pid()->hProcess
, BELOW_NORMAL_PRIORITY_CLASS
))
171 SetPriorityClass(process
.pid()->hProcess
, IDLE_PRIORITY_CLASS
);
178 emit
statusUpdated(0);
179 m_firstLaunch
= false;
182 s_lastLaunchTime
= currentTime() + START_DELAY_NANO
;
186 emit
messageLogged("Process creation has failed :-(");
187 QString errorMsg
= process
.errorString().trimmed();
188 if(!errorMsg
.isEmpty()) emit
messageLogged(errorMsg
);
191 process
.waitForFinished(-1);
193 s_lastLaunchTime
= currentTime() + START_DELAY_NANO
;
198 * Convert program arguments to single string
200 QString
AbstractTool::commandline2string(const QString
&program
, const QStringList
&arguments
)
202 QString commandline
= (program
.contains(' ') ? QString("\"%1\"").arg(program
) : program
);
204 for(int i
= 0; i
< arguments
.count(); i
++)
206 commandline
+= (arguments
.at(i
).contains(' ') ? QString(" \"%1\"").arg(arguments
.at(i
)) : QString(" %1").arg(arguments
.at(i
)));
213 * Convert long path to short path
215 QString
AbstractTool::pathToShort(const QString
&longPath
)
218 DWORD buffSize
= GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath
.utf16()), NULL
, NULL
);
222 wchar_t *buffer
= new wchar_t[buffSize
];
223 DWORD result
= GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath
.utf16()), buffer
, buffSize
);
225 if(result
> 0 && result
< buffSize
)
227 shortPath
= QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer
));
233 return (shortPath
.isEmpty() ? longPath
: shortPath
);
236 const quint64
AbstractTool::currentTime(void)
239 GetSystemTimeAsFileTime(&fileTime
);
242 temp
.HighPart
= fileTime
.dwHighDateTime
;
243 temp
.LowPart
= fileTime
.dwLowDateTime
;
245 return temp
.QuadPart
;