mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 12:30:23 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			117 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "NonInheritingProcess.hpp"
 | |
| 
 | |
| #ifdef Q_OS_WIN
 | |
| #ifndef WIN32_LEAN_AND_MEAN
 | |
| #define WIN32_LEAN_AND_MEAN
 | |
| #endif
 | |
| #ifndef NOMINMAX
 | |
| #define NOMINMAX
 | |
| #endif
 | |
| #ifndef _UNICODE
 | |
| #define _UNICODE
 | |
| #endif
 | |
| #ifdef _WIN32_WINNT
 | |
| #undef _WIN32_WINNT
 | |
| #endif
 | |
| #define _WIN32_WINNT 0x0601
 | |
| #include <windows.h>
 | |
| #endif
 | |
| 
 | |
| #include <memory>
 | |
| #include <functional>
 | |
| 
 | |
| #include "pimpl_impl.hpp"
 | |
| 
 | |
| namespace
 | |
| {
 | |
| #ifdef Q_OS_WIN
 | |
|   struct start_info_deleter
 | |
|   {
 | |
|     void operator () (STARTUPINFOEXW * si)
 | |
|     {
 | |
|       if (si->lpAttributeList)
 | |
|         {
 | |
|           ::DeleteProcThreadAttributeList (si->lpAttributeList);
 | |
|         }
 | |
|       delete si;
 | |
|     }
 | |
|   };
 | |
| #endif
 | |
| }
 | |
| 
 | |
| class NonInheritingProcess::impl
 | |
| {
 | |
| public:
 | |
| #ifdef Q_OS_WIN
 | |
|   void extend_CreateProcessArguments (QProcess::CreateProcessArguments * args)
 | |
|   {
 | |
|     // 
 | |
|     //   Here we modify the  CreateProcessArguments structure to use a
 | |
|     // STARTUPINFOEX extended  argument to  CreateProcess. In  that we
 | |
|     // set up  a list of  handles for the  new process to  inherit. By
 | |
|     // doing   this  we   stop  all   inherited  handles   from  being
 | |
|     // inherited. Unfortunately UpdateProcThreadAttribute does not let
 | |
|     // us set  up an empty handle  list, so we populate  the list with
 | |
|     // the three standard stream  handles that QProcess::start has set
 | |
|     // up  as Pipes  to do  IPC. Even  though these  Pipe handles  are
 | |
|     // created with inheritance disabled, UpdateProcThreadAtribute and
 | |
|     // CreateProcess don't seem to mind, which suits us fine.
 | |
|     //
 | |
|     // Note: that we cannot just clear the inheritHandles flag as that
 | |
|     // stops the standard stream  handles being inherited which breaks
 | |
|     // our   IPC    using   std(in|out|err).    Only   be    using   a
 | |
|     // PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute  in a STARTUPINFOEX
 | |
|     // structure  can  we  avoid  the  all  or  nothing  behaviour  of
 | |
|     // CreateProcess /w respect to handle inheritance.
 | |
|     // 
 | |
|     BOOL fSuccess;
 | |
|     SIZE_T size {0};
 | |
|     LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = nullptr;
 | |
|     ::InitializeProcThreadAttributeList (nullptr, 1, 0, &size);
 | |
|     lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST> (::HeapAlloc (::GetProcessHeap (), 0, size));
 | |
|     fSuccess = !!lpAttributeList;
 | |
|     if (fSuccess)
 | |
|       {
 | |
|         fSuccess = ::InitializeProcThreadAttributeList (lpAttributeList, 1, 0, &size);
 | |
|       }
 | |
|     if (fSuccess)
 | |
|       {
 | |
|         // empty list of handles
 | |
|         fSuccess = ::UpdateProcThreadAttribute (lpAttributeList, 0,
 | |
|                                                 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
 | |
|                                                 &args->startupInfo->hStdInput, 3 * sizeof (HANDLE),
 | |
|                                                 nullptr, 0);
 | |
|       }
 | |
|     if (fSuccess)
 | |
|       {
 | |
|         start_info_.reset (new STARTUPINFOEXW);
 | |
|         start_info_->StartupInfo = *args->startupInfo;
 | |
|         start_info_->StartupInfo.cb = sizeof (STARTUPINFOEXW);
 | |
|         start_info_->lpAttributeList = lpAttributeList;
 | |
|         args->startupInfo = reinterpret_cast<Q_STARTUPINFO*> (start_info_.get ());
 | |
|         args->flags |= EXTENDED_STARTUPINFO_PRESENT;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   using start_info_type = std::unique_ptr<STARTUPINFOEXW, start_info_deleter>;
 | |
|   start_info_type start_info_;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| NonInheritingProcess::NonInheritingProcess (QObject * parent)
 | |
|   : QProcess {parent}
 | |
| {
 | |
| #ifdef Q_OS_WIN
 | |
|   using namespace std::placeholders;
 | |
| 
 | |
|   // enable cleanup after process starts or fails to start
 | |
|   connect (this, &QProcess::started, [this] {m_->start_info_.reset ();});
 | |
|   connect (this, &QProcess::errorOccurred, [this] (QProcess::ProcessError) {m_->start_info_.reset ();});
 | |
|   setCreateProcessArgumentsModifier (std::bind (&NonInheritingProcess::impl::extend_CreateProcessArguments, &*m_, _1));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| NonInheritingProcess::~NonInheritingProcess ()
 | |
| {
 | |
| }
 |