int ToolRunner::Run_Capture(LPCTSTR command, LPCTSTR params, LPCTSTR dir) { tstring clopts(_T("\"\" ")); clopts.insert(1, command); clopts += params; if (!m_pWrapper->IsTextFilter()) { tstring tempstr(clopts); tempstr.insert(0, _T("> ")); tempstr += _T("\n"); m_pWrapper->_AddToolOutput(tempstr.c_str()); } if (_tcslen(dir) == 0) dir = NULL; OSVERSIONINFO osv = {sizeof(OSVERSIONINFO), 0, 0, 0, 0, _T("")}; ::GetVersionEx(&osv); bool bWin9x = osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS; SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), 0, 0}; sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; SECURITY_DESCRIPTOR sd; if (!bWin9x) { // On NT we can have a proper security descriptor... ::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); ::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.lpSecurityDescriptor = &sd; } HANDLE hWritePipe, hReadPipe; HANDLE hStdInWrite, hStdInRead; if (!::CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) { CLastErrorInfo lei; m_pWrapper->_AddToolOutput(_T("\n> Failed to create StdOut and StdErr Pipe: ")); m_pWrapper->_AddToolOutput((LPCTSTR)lei); return lei.GetErrorCode(); } // read handle, write handle, security attributes, number of bytes reserved for pipe - 0 default if (!::CreatePipe(&hStdInRead, &hStdInWrite, &sa, 0)) { CLastErrorInfo lei; m_pWrapper->_AddToolOutput(_T("\n> Failed to create StdIn Pipe: ")); m_pWrapper->_AddToolOutput((LPCTSTR)lei); return lei.GetErrorCode(); } ::SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0); ::SetHandleInformation(hStdInWrite, HANDLE_FLAG_INHERIT, 0); STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.hStdInput = hStdInRead; si.hStdOutput = hWritePipe; si.hStdError = hWritePipe; PROCESS_INFORMATION pi = {0, 0, 0, 0}; DWORD dwCreationFlags = CREATE_NEW_CONSOLE; // CREATE_NEW_PROCESS_GROUP; std::vector<TCHAR> cmdbuf(clopts.length() + 1); memcpy(&cmdbuf[0], clopts.c_str(), clopts.size() * sizeof(TCHAR)); bool bCreated = ::CreateProcess( NULL, &cmdbuf[0], &sa, /*LPSECURITY_ATTRIBUTES lpProcessAttributes*/ NULL, /*LPSECURITYATTRIBUTES lpThreadAttributes*/ TRUE, /*BOOL bInheritHandles*/ dwCreationFlags, /*DWORD dwCreationFlags*/ NULL, /*LPVOID lpEnvironment*/ dir, /*LPCTSTR lpWorkingDir*/ &si, /*LPSTARTUPINFO lpStartupInfo*/ &pi /*LPPROCESS_INFORMATION lpProcessInformation*/ ) != 0; if (!bCreated) { ::CloseHandle(hReadPipe); ::CloseHandle(hWritePipe); ::CloseHandle(hStdInRead); ::CloseHandle(hStdInWrite); CLastErrorInfo lei; m_pWrapper->_AddToolOutput(_T("\n> Failed to create process: ")); m_pWrapper->_AddToolOutput((LPCTSTR)lei); return lei.GetErrorCode(); } unsigned int dwBytesToWrite; unsigned char* stdinbuf; stdinbuf = m_pWrapper->GetStdIOBuffer(dwBytesToWrite); if (!dwBytesToWrite) stdinbuf = NULL; DWORD dwBytesAvail, dwBytesRead, exitCode, timeDeathDetected; dwBytesAvail = dwBytesRead = exitCode = timeDeathDetected = 0; DWORD dwBytesWritten = 0; bool bCompleted = false; BYTE buffer[TOOLS_BUFFER_SIZE]; while (!bCompleted) { Sleep(50); if (dwBytesToWrite > 0) { // We have a filter (we think), so write the filter data into the stdin // of the process we started. DWORD dwWrote; ::WriteFile(hStdInWrite, stdinbuf+dwBytesWritten, dwBytesToWrite, &dwWrote, NULL); dwBytesWritten += dwWrote; dwBytesToWrite -= dwWrote; if(dwBytesToWrite == 0) { // Now close stdin so that the filter doesn't wait forever for more data. ::CloseHandle(hStdInWrite); hStdInWrite = NULL; } } //The PeekNamedPipe function copies data from a named or // anonymous pipe into a buffer without removing it from the pipe. if (!::PeekNamedPipe(hReadPipe, NULL, 0, NULL, &dwBytesAvail, NULL) ) { dwBytesAvail = 0; } if (dwBytesAvail > 0) { BOOL bRead = ::ReadFile(hReadPipe, buffer, sizeof(buffer)-1, &dwBytesRead, NULL); buffer[dwBytesRead] = NULL; if (bRead && dwBytesRead) { CA2CT conv(reinterpret_cast<const char*>(buffer)); m_pWrapper->_AddToolOutput(&conv[0], -1); } else { // Couldn't read from the pipe, must be finished... bCompleted = true; } } else { exitCode = STILL_ACTIVE; // No data from the process, is it still active? ::GetExitCodeProcess(pi.hProcess, &exitCode); if (STILL_ACTIVE != exitCode) { if (bWin9x) { // If we're running on Windows 9x then we give the // process some time to return the remainder of its data. // We wait until a pre-set amount of time has elapsed and // then exit. if (timeDeathDetected == 0) { timeDeathDetected = ::GetTickCount(); } else { ///@todo Get this value from the registry... if ((::GetTickCount() - timeDeathDetected) > 500) { bCompleted = true; } } } else { // If NT, then the process is already dead. bCompleted = true; } } } // While we're here, we check to see if we've been told to close. if (!GetCanRun()) { if (WAIT_OBJECT_0 != ::WaitForSingleObject(pi.hProcess, 500)) { // We should do this only if the GUI process is stuck and // don't answer to a normal termination command. // This function is dangerous: dependant DLLs don't know the process // is terminated, and memory isn't released. m_pWrapper->_AddToolOutput(_T("\n> Forcefully terminating process...\n")); ::TerminateProcess(pi.hProcess, 1); } bCompleted = true; } } // while (!bCompleted) if (WAIT_OBJECT_0 != ::WaitForSingleObject(pi.hProcess, 1000)) { m_pWrapper->_AddToolOutput(_T("\n> Process failed to respond; forcing abrupt termination...")); ::TerminateProcess(pi.hProcess, 2); } ::GetExitCodeProcess(pi.hProcess, &exitCode); m_RetCode = exitCode; ::CloseHandle(pi.hProcess); ::CloseHandle(pi.hThread); ::CloseHandle(hReadPipe); ::CloseHandle(hWritePipe); ::CloseHandle(hStdInRead); if (hStdInWrite) // might already be closed ::CloseHandle(hStdInWrite); return m_RetCode; }
CString CCommonAppUtils::GetAppForFile ( const CString& fileName , const CString& extension , const CString& verb , bool applySecurityHeuristics) { CString application; // normalize file path CString fullFileName = ExpandEnvironmentStrings (fileName); CString normalizedFileName = L"\"" + fullFileName + L"\""; // registry lookup CString extensionToUse = extension.IsEmpty() ? CPathUtils::GetFileExtFromPath (fullFileName) : extension; if (!extensionToUse.IsEmpty()) { // lookup by verb CString documentClass; DWORD buflen = 0; AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_COMMAND, extensionToUse, verb, NULL, &buflen); std::unique_ptr<TCHAR[]> cmdbuf(new TCHAR[buflen + 1]); if (FAILED(AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_COMMAND, extensionToUse, verb, cmdbuf.get(), &buflen))) { documentClass = CRegString (extensionToUse + L"\\", L"", FALSE, HKEY_CLASSES_ROOT); CString key = documentClass + L"\\Shell\\" + verb + L"\\Command\\"; application = CRegString (key, L"", FALSE, HKEY_CLASSES_ROOT); } else { application = cmdbuf.get(); } // fallback to "open" if (application.IsEmpty()) { buflen = 0; AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_COMMAND, extensionToUse, L"open", NULL, &buflen); std::unique_ptr<TCHAR[]> cmdopenbuf (new TCHAR[buflen + 1]); if (FAILED(AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_COMMAND, extensionToUse, L"open", cmdopenbuf.get(), &buflen))) { CString key = documentClass + L"\\Shell\\Open\\Command\\"; application = CRegString (key, L"", FALSE, HKEY_CLASSES_ROOT); } else { application = cmdopenbuf.get(); } } } // normalize application path application = ExpandEnvironmentStrings (application); // security heuristics: // some scripting languages (e.g. python) will execute the document // instead of open it. Try to identify these cases. if (applySecurityHeuristics) { if ( (application.Find (L"%2") >= 0) || (application.Find (L"%*") >= 0)) { // consumes extra parameters // -> probably a script execution // -> retry with "open" verb or ask user if (verb.CompareNoCase (L"open") == 0) application.Empty(); else return GetAppForFile ( fileName , extension , L"open" , true); } } // exit here, if we were not successful if (application.IsEmpty()) return application; // resolve parameters if (application.Find (L"%1") < 0) application += L" %1"; if (application.Find(L"\"%1\"") >= 0) application.Replace(L"\"%1\"", L"%1"); application.Replace (L"%1", normalizedFileName); return application; }
int ToolRunner::Run_NoCapture(LPCTSTR command, LPCTSTR params, LPCTSTR dir) { int result = 0; tstring tempstr(_T("\"\" ")); tempstr.insert(1, command); tempstr += params; if (_tcslen(dir) == 0) dir = NULL; OSVERSIONINFO osv = {sizeof(OSVERSIONINFO), 0, 0, 0, 0, _T("")}; ::GetVersionEx(&osv); bool bWin9x = osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS; SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), 0, 0}; sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; SECURITY_DESCRIPTOR sd; if (!bWin9x) { // On NT we can have a proper security descriptor... ::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); ::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.lpSecurityDescriptor = &sd; } STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION pi = {0, 0, 0, 0}; std::vector<TCHAR> cmdbuf(tempstr.length()+1); memcpy(&cmdbuf[0], tempstr.c_str(), tempstr.size() * sizeof(TCHAR)); DWORD dwCreationFlags = CREATE_NEW_CONSOLE; // CREATE_NEW_PROCESS_GROUP - causes Ctrl-C to be disabled. bool bCreated = ::CreateProcess( NULL, &cmdbuf[0], &sa, /*LPSECURITY_ATTRIBUTES lpProcessAttributes*/ NULL, /*LPSECURITYATTRIBUTES lpThreadAttributes*/ TRUE, /*BOOL bInheritHandles*/ dwCreationFlags, /*DWORD dwCreationFlags*/ NULL, /*LPVOID lpEnvironment*/ dir, /*LPCTSTR lpWorkingDir*/ &si, /*LPSTARTUPINFO lpStartupInfo*/ &pi /*LPPROCESS_INFORMATION lpProcessInformation*/ ) != 0; if (!bCreated) { CLastErrorInfo lei; m_pWrapper->_AddToolOutput(_T("\n> Failed to create process: ")); m_pWrapper->_AddToolOutput((LPCTSTR)lei); return lei.GetErrorCode(); } // We're waiting for this one to finish because it's a filter process - // i.e. it will change the current file. if (m_pWrapper->IsFilter()) { ::WaitForSingleObject(pi.hProcess, INFINITE); DWORD dwExitCode; ::GetExitCodeProcess(pi.hProcess, &dwExitCode); result = dwExitCode; } else { result = pi.dwProcessId; } // Detach... ::CloseHandle(pi.hProcess); ::CloseHandle(pi.hThread); PostRun(); return result; }