void LaunchWithSumatra(InstanceData *data, const char *url_utf8) { if (!file::Exists(data->filepath)) plogf("sp: NPP_StreamAsFile() error: file doesn't exist"); ScopedMem<WCHAR> url(str::conv::FromUtf8(url_utf8)); // escape quotation marks and backslashes for CmdLineParser.cpp's ParseQuoted if (str::FindChar(url, '"')) { WStrVec parts; parts.Split(url, L"\""); url.Set(parts.Join(L"%22")); } if (str::EndsWith(url, L"\\")) { url[str::Len(url) - 1] = '\0'; url.Set(str::Join(url, L"%5c")); } // prevent overlong URLs from making LaunchProcess fail if (str::Len(url) > 4096) url.Set(NULL); ScopedMem<WCHAR> cmdLine(str::Format(L"\"%s\" -plugin \"%s\" %d \"%s\"", data->exepath, url ? url : L"", (HWND)data->npwin->window, data->filepath)); data->hProcess = LaunchProcess(cmdLine); if (!data->hProcess) { plogf("sp: NPP_StreamAsFile() error: couldn't run SumatraPDF!"); data->message = _TR("Error: Couldn't run SumatraPDF!"); } }
bool LaunchProcess(const CommandLine& cmdline, const LaunchOptions& options, ProcessHandle* process_handle) { return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle); }
static BaseEngine *ps2pdf(const WCHAR *fileName) { // TODO: read from gswin32c's stdout instead of using a TEMP file ScopedMem<WCHAR> shortPath(path::ShortPath(fileName)); ScopedMem<WCHAR> tmpFile(path::GetTempPath(L"PsE")); ScopedFile tmpFileScope(tmpFile); ScopedMem<WCHAR> gswin32c(GetGhostscriptPath()); if (!shortPath || !tmpFile || !gswin32c) return NULL; // try to help Ghostscript determine the intended page size ScopedMem<WCHAR> psSetup; RectI page = ExtractDSCPageSize(fileName); if (!page.IsEmpty()) psSetup.Set(str::Format(L" << /PageSize [%i %i] >> setpagedevice", page.dx, page.dy)); ScopedMem<WCHAR> cmdLine(str::Format( L"\"%s\" -q -dSAFER -dNOPAUSE -dBATCH -dEPSCrop -sOutputFile=\"%s\" -sDEVICE=pdfwrite -c \".setpdfwrite%s\" -f \"%s\"", gswin32c, tmpFile, psSetup ? psSetup : L"", shortPath)); fprintf(stderr, "- %s:%d: using '%ls' for creating '%%TEMP%%\\%ls'\n", path::GetBaseName(__FILE__), __LINE__, gswin32c.Get(), path::GetBaseName(tmpFile)); // TODO: the PS-to-PDF conversion can hang the UI for several seconds HANDLE process = LaunchProcess(cmdLine, NULL, CREATE_NO_WINDOW); if (!process) return NULL; DWORD timeout = 10000; #ifdef DEBUG // allow to disable the timeout for debugging purposes if (GetEnvironmentVariable(L"SUMATRAPDF_NO_GHOSTSCRIPT_TIMEOUT", NULL, 0)) timeout = INFINITE; #endif DWORD exitCode = EXIT_FAILURE; WaitForSingleObject(process, timeout); GetExitCodeProcess(process, &exitCode); TerminateProcess(process, 1); CloseHandle(process); if (exitCode != EXIT_SUCCESS) return NULL; size_t len; ScopedMem<char> pdfData(file::ReadAll(tmpFile, &len)); if (!pdfData) return NULL; ScopedComPtr<IStream> stream(CreateStreamFromData(pdfData, len)); if (!stream) return NULL; return PdfEngine::CreateFromStream(stream); }
// based on http://mdb-blog.blogspot.com/2013/01/nsis-lunch-program-as-user-from-uac.html // uses $WINDIR\explorer.exe to launch cmd // Other promising approaches: // - http://blogs.msdn.com/b/oldnewthing/archive/2013/11/18/10468726.aspx // - http://brandonlive.com/2008/04/27/getting-the-shell-to-run-an-application-for-you-part-2-how/ // - http://www.codeproject.com/Articles/23090/Creating-a-process-with-Medium-Integration-Level-f // Approaches tried but didn't work: // - http://stackoverflow.com/questions/3298611/run-my-program-asuser // - using CreateProcessAsUser() with hand-crafted token // It'll always run the process, might fail to run non-elevated if fails to find explorer.exe // Also, if explorer.exe is running elevated, it'll probably run elevated as well. void RunNonElevated(const WCHAR *exePath) { ScopedMem<WCHAR> cmd, explorerPath; WCHAR buf[MAX_PATH] = { 0 }; UINT res = GetWindowsDirectory(buf, dimof(buf)); if (0 == res || res >= dimof(buf)) goto Run; explorerPath.Set(path::Join(buf, L"explorer.exe")); if (!file::Exists(explorerPath)) goto Run; cmd.Set(str::Format(L"\"%s\" \"%s\"", explorerPath.Get(), exePath)); Run: HANDLE h = LaunchProcess(cmd ? cmd : exePath); SafeCloseHandle(&h); }
// === PUBLIC === bool TTYProcess::startTTY(QString prog, QStringList args, QString workdir){ if(workdir=="~"){ workdir = QDir::homePath(); } QDir::setCurrent(workdir); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); setenv("TERM","vt100",1); //vt100: VT100 emulation support unsetenv("TERMCAP"); /*setenv("TERMCAP","mvterm|vv100|mvterm emulator with ANSI colors:\ :pa#64:Co#8:AF=\E[3%dm:AB=\E[4%dm:op=\E[100m:tc=vt102:",1); //see /etc/termcap as well*/ QStringList filter = env.keys().filter("XTERM"); for(int i=0; i<filter.length(); i++){ unsetenv(filter[i].toLocal8Bit().data()); } //if(env.contains("TERM")){ unsetenv("TERM"); } //else if(env.contains //Turn the program/arguments into C-compatible arrays char cprog[prog.length()]; strcpy(cprog, prog.toLocal8Bit().data()); char *cargs[args.length()+2]; QByteArray nullarray; for(int i=0; i<args.length()+2; i++){ // First arg needs to be the program if ( i == 0 ) { cargs[i] = new char[ prog.toLocal8Bit().size()+1]; strcpy( cargs[i], prog.toLocal8Bit().data() ); } else if(i<args.length()){ cargs[i] = new char[ args[i].toLocal8Bit().size()+1]; strcpy( cargs[i], args[i].toLocal8Bit().data() ); }else{ cargs[i] = NULL; } } qDebug() << "PTY Start:" << prog; //Launch the process attached to a new PTY int FD = 0; pid_t tmp = LaunchProcess(FD, cprog, cargs); qDebug() << " - PID:" << tmp; qDebug() << " - FD:" << FD; if(tmp<0){ return false; } //error else{ childProc = tmp; //Load the file for close notifications //TO-DO //Watch the socket for activity sn= new QSocketNotifier(FD, QSocketNotifier::Read); sn->setEnabled(true); connect(sn, SIGNAL(activated(int)), this, SLOT(checkStatus(int)) ); ttyfd = FD; qDebug() << " - PTY:" << ptsname(FD); return true; } }
static PdfEngine *ps2pdf(const WCHAR *fileName) { // TODO: read from gswin32c's stdout instead of using a TEMP file ScopedMem<WCHAR> shortPath(path::ShortPath(fileName)); ScopedMem<WCHAR> tmpFile(path::GetTempPath(L"PsE")); ScopedFile tmpFileScope(tmpFile); ScopedMem<WCHAR> gswin32c(GetGhostscriptPath()); if (!shortPath || !tmpFile || !gswin32c) return NULL; ScopedMem<WCHAR> cmdLine(str::Format(L"\"%s\" -q -dSAFER -dNOPAUSE -dBATCH -dEPSCrop -sOutputFile=\"%s\" -sDEVICE=pdfwrite -c .setpdfwrite -f \"%s\"", gswin32c, tmpFile, shortPath)); if (GetEnvironmentVariable(L"MULOG", NULL, 0)) { wprintf(L"ps2pdf: using Ghostscript from '%s'\n", gswin32c.Get()); wprintf(L"ps2pdf: for creating '%s'\n", tmpFile.Get()); } // TODO: the PS-to-PDF conversion can hang the UI for several seconds HANDLE process = LaunchProcess(cmdLine, NULL, CREATE_NO_WINDOW); if (!process) return NULL; DWORD exitCode = EXIT_FAILURE; WaitForSingleObject(process, 10000); GetExitCodeProcess(process, &exitCode); TerminateProcess(process, 1); CloseHandle(process); if (exitCode != EXIT_SUCCESS) return NULL; size_t len; ScopedMem<char> pdfData(file::ReadAll(tmpFile, &len)); if (!pdfData) return NULL; ScopedComPtr<IStream> stream(CreateStreamFromData(pdfData, len)); if (!stream) return NULL; if (GetEnvironmentVariable(L"MULOG", NULL, 0)) printf("ps2pdf: PDF conversion successful\n"); return PdfEngine::CreateFromStream(stream); }
// returns true if the double-click was handled and false if it wasn't bool OnInverseSearch(WindowInfo *win, int x, int y) { if (!HasPermission(Perm_DiskAccess) || gPluginMode) return false; if (!win->IsDocLoaded() || win->dm->engineType != Engine_PDF) return false; // Clear the last forward-search result win->fwdSearchMark.rects.Reset(); InvalidateRect(win->hwndCanvas, NULL, FALSE); // On double-clicking error message will be shown to the user // if the PDF does not have a synchronization file if (!win->pdfsync) { int err = Synchronizer::Create(win->loadedFilePath, static_cast<PdfEngine *>(win->dm->engine), &win->pdfsync); if (err == PDFSYNCERR_SYNCFILE_NOTFOUND) { // We used to warn that "No synchronization file found" at this // point if gGlobalPrefs->enableTeXEnhancements is set; we no longer // so do because a double-click has several other meanings // (selecting a word or an image, navigating quickly using links) // and showing an unrelated warning in all those cases seems wrong return false; } if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("Synchronization file cannot be opened")); return true; } gGlobalPrefs->enableTeXEnhancements = true; } int pageNo = win->dm->GetPageNoByPoint(PointI(x, y)); if (!win->dm->ValidPageNo(pageNo)) return false; PointI pt = win->dm->CvtFromScreen(PointI(x, y), pageNo).Convert<int>(); ScopedMem<WCHAR> srcfilepath; UINT line, col; int err = win->pdfsync->DocToSource(pageNo, pt, srcfilepath, &line, &col); if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("No synchronization info at this position")); return true; } WCHAR *inverseSearch = gGlobalPrefs->inverseSearchCmdLine; if (!inverseSearch) // Detect a text editor and use it as the default inverse search handler for now inverseSearch = AutoDetectInverseSearchCommands(); ScopedMem<WCHAR> cmdline; if (inverseSearch) cmdline.Set(win->pdfsync->PrepareCommandline(inverseSearch, srcfilepath, line, col)); if (!str::IsEmpty(cmdline.Get())) { // resolve relative paths with relation to SumatraPDF.exe's directory ScopedMem<WCHAR> appDir(GetExePath()); if (appDir) appDir.Set(path::GetDir(appDir)); ScopedHandle process(LaunchProcess(cmdline, appDir)); if (!process) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); } else if (gGlobalPrefs->enableTeXEnhancements) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); if (inverseSearch != gGlobalPrefs->inverseSearchCmdLine) free(inverseSearch); return true; }
/*----------------------------------------------------------------------------- Background thread for managing the state of the agent -----------------------------------------------------------------------------*/ void CurlBlastDlg::ThreadProc(void) { LoadSettings(); // configure the desktop resolution WaitForSingleObject(testingMutex, INFINITE); SetupScreen(); ReleaseMutex(testingMutex); // wait for the statup delay SetStatus(_T("Starting up...")); DWORD ms = startupDelay; while( ms > 0 && WaitForSingleObject(hMustExit,0) == WAIT_TIMEOUT) { Sleep(500); ms -= 500; } // launch the watchdog TCHAR path[MAX_PATH]; GetModuleFileName(NULL, path, MAX_PATH); lstrcpy(PathFindFileName(path), _T("wptwatchdog.exe")); CString watchdog; watchdog.Format(_T("\"%s\" %d"), path, GetCurrentProcessId()); HANDLE process = NULL; LaunchProcess(watchdog, &process); if (process) CloseHandle(process); if (WaitForSingleObject(hMustExit,0) == WAIT_TIMEOUT) { DoStartup(); } // handle the periodic cleanup until it is time to exit Alive(); DWORD msCleanup = 500; DWORD msTemp = 20000; while(WaitForSingleObject(hMustExit,0) == WAIT_TIMEOUT) { if (!msCleanup) { CloseDialogs(); KillProcs(); msCleanup = 500; } else msCleanup -= 500; if (!msTemp) { if (WaitForSingleObject(testingMutex, 0) != WAIT_TIMEOUT) { ClearTemp(); msTemp = 20000; ReleaseMutex(testingMutex); } } else msTemp -= 500; CheckAlive(); Sleep(500); } // signal and wait for all of the workers to finish KillWorker(); // shut down the url manager urlManager.Stop(); }
/** * Read command line parameters and control the launching of the agents. */ void MainL() { LOG_MSG( "ENTER: t_multi_agent_launcher MainL()"); TInt ret = KErrNone; TInt numAgents = KNumAgents; TInt numTargets = KNumTargets; TInt numTestRuns = KNumTestRuns; TInt argc = User::CommandLineLength(); HBufC* commandLine = NULL; LOG_MSG2("t_multi_agent_launcher: MainL(): argc=%d", argc); if(argc) { commandLine = HBufC::NewLC(argc); TPtr commandLineBuffer = commandLine->Des(); User::CommandLine(commandLineBuffer); RBuf printCommandLine; CleanupClosePushL( printCommandLine ); printCommandLine.CreateL( commandLine->Des().Length() ); printCommandLine.Copy( commandLine->Des() ); printCommandLine.Collapse(); LOG_MSG2("t_multi_agent_launcher: command line = %S", &printCommandLine); CleanupStack::PopAndDestroy( &printCommandLine ); // create a lexer and read through the command line TLex lex(*commandLine); while (!lex.Eos()) { // only look for options with first character '-' if (lex.Get() == '-') { TChar arg = lex.Get(); switch ( arg ) { case 'n': lex.Val( numAgents ); LOG_MSG2("t_multi_agent_launcher: parsed numAgents as %d", numAgents); break; case 'm': lex.Val( numTargets ); LOG_MSG2("t_multi_agent_launcher: parsed numTargets as %d", numTargets); break; case 't': lex.Val( numTestRuns ); LOG_MSG2("t_multi_agent_launcher: parsed numTestRuns as %d", numTestRuns); break; default: LOG_MSG("t_multi_agent_launcher: unknown argument ignoring it"); break; } } } } // Note: below is a workaround to overcome an issue with RTest server crashing // when writing to the windows console from different agents (on different CPUs // at the same time). To overcome this we get signaled by the agents when they have // completed their tests so that we can do a RTest complete RSemaphore launchSemaphore; CleanupClosePushL(launchSemaphore); ret = launchSemaphore.CreateGlobal(KLaunchSemaphoreName, 0); LOG_MSG2( ">Target Launcher : RSemaphore.CreateGlobal ret %d", ret); User::LeaveIfError( ret ); ret = launchSemaphore.OpenGlobal(KLaunchSemaphoreName); LOG_MSG2( ">Target Launcher : RSemaphore.OpenGlobal ret %d", ret); User::LeaveIfError( ret ); //Now launch the requested number of apps for the requested number of test runs for( TInt j = 0; j < numTestRuns; j++ ) { for( TInt i = 0; i < numAgents; i++ ) { RBuf targetName; targetName.CleanupClosePushL(); targetName.CreateL(KAgentExe()); RProcess aProc; CleanupClosePushL(aProc); RBuf launcherOptions; CleanupClosePushL(launcherOptions); const TInt additionalWords = 2; launcherOptions.CreateL( KAgentOptions().Length() + additionalWords ); // Apply offset: launcherOptions.Format( .., .., i * numTargets, ..) // workaround to ensure we have the same binary for multiple agents. // e.g. So if offset = 0, agent attaches to app1, app2, app3, app4, app5 // if offset = 5, agent attached to app6, app7, app8, app9, app10 etc. // Note: apps need to be in rom otherwise the agent will fail on an assert // (with KErrNotFound) launcherOptions.Format( KAgentOptions(), (TUint)numTargets, i * numTargets, 0); ret = LaunchProcess( aProc, targetName, launcherOptions ); CleanupStack::PopAndDestroy(3,&targetName); User::LeaveIfError(ret); } } // Wait for all agents to do their testing before checking the semaphore User::After(12000000); LOG_MSG( ">Target Launcher: Semaphore wait"); for (TInt i = 0; i < numAgents; i ++) { //We need this delay just in case an agent crashes and never signals the sem ret = launchSemaphore.Wait(100000); if( ret != KErrNone ) { LOG_MSG3("launchSemaphore.Wait ret %d for agent %d", ret, i); break; } } LOG_MSG2( "testing for Semaphore ret %d", ret); // We only want to have one RTest instance at any one time since otherwise RTest can panic RTest test(_L("T_MULTI_AGENT_LAUNCHER")); test.Start(_L("t_multi_agent_launcher Check for agents finishing correctly")); test(ret == KErrNone); test.End(); test.Close(); CleanupStack::PopAndDestroy(&launchSemaphore); // launchSemaphore if( commandLine ) CleanupStack::PopAndDestroy(commandLine); LOG_MSG("EXIT: t_multi_agent_launcher MainL()"); }
/** * Read command line parameters and control the launching of targets. * Create global launch semaphore KLaunchSemaphoreName */ void MainL() { TInt numApps = KNumApps; TInt numLaunches = KNumLaunches; TInt launchControl = 0; TInt argc = User::CommandLineLength(); HBufC* commandLine = NULL; RDebug::Printf( ">Launcher Process() argc=%d", argc ); if( argc ) { commandLine = HBufC::NewLC(argc); TPtr commandLineBuffer = commandLine->Des(); User::CommandLine(commandLineBuffer); RBuf printCommandLine; CleanupClosePushL( printCommandLine ); printCommandLine.CreateL( commandLine->Des().Length() ); printCommandLine.Copy( commandLine->Des() ); printCommandLine.Collapse(); RDebug::Printf( ">command line = %S", &printCommandLine ); CleanupStack::PopAndDestroy( &printCommandLine ); // create a lexer and read through the command line TLex lex(*commandLine); while (!lex.Eos()) { // only look for options with first character '+', other switches are for the targets if (lex.Get() == '+') { TChar arg = lex.Get(); switch (arg) { case 'n': lex.Val( numApps ); RDebug::Printf("parsed numApps as %d", numApps); break; case 'm': lex.Val( numLaunches ); RDebug::Printf("parsed numLaunches as %d", numLaunches ); break; case 'o': lex.Val( launchControl ); RDebug::Printf("parsed launchControl as %d", launchControl); break; default: // unknown argument ignore it break; }//switch }// if + }//while }//if argc RSemaphore launchSemaphore; TInt ret = KErrNone; CleanupClosePushL( launchSemaphore ); ret = launchSemaphore.CreateGlobal( KLaunchSemaphoreName, 0 ); RDebug::Printf( ">Target Launcher : RSemaphore.CreateGlobal ret %d", ret); User::LeaveIfError( ret ); ret = launchSemaphore.OpenGlobal( KLaunchSemaphoreName ); RDebug::Printf( ">Target Launcher : RSemaphore.OpenGlobal ret %d", ret); User::LeaveIfError( ret ); //Only now indicate to the launcher that we have fully started, so they can find and open the semaphore RProcess::Rendezvous(KErrNone); //Now launch the requested number of apps for the requested number of launches for( ; numLaunches > 0; numLaunches-- ) { for( TInt launchIndex = numApps; launchIndex > 0; launchIndex-- ) { RDebug::Printf( ">Target Launcher: Semaphore wait app %d, launch %d", launchIndex, numLaunches ); launchSemaphore.Wait(); RBuf targetName; CleanupClosePushL( targetName ); RDebug::Printf( ">Target Launcher: targetName.Create %d, launch %d", launchIndex, numLaunches ); targetName.Create( KTargetExe().Length() + 2 ); if( launchControl == 1 ) { // Reverse the order of the apps launched by reversing the index in the name RDebug::Printf( ">Target Launcher: targetName.Format %d, launch %d", numApps - launchIndex + 1, numLaunches ); targetName.Format( KTargetExe(), numApps - launchIndex + 1 ); } else { RDebug::Printf( ">Target Launcher: targetName.Format %d, launch %d", launchIndex, numLaunches ); targetName.Format( KTargetExe(), launchIndex ); } RProcess aProc; CleanupClosePushL( aProc ); RDebug::Printf( ">Target Launcher: LaunchProcess %d, launch %d", launchIndex, numLaunches ); RDebug::Printf( ">LaunchProcess %lS", &targetName ); TPtr cmdLinePtr( commandLine->Des() ); ret = LaunchProcess( aProc, targetName, cmdLinePtr ); CleanupStack::PopAndDestroy( &aProc ); RDebug::Printf( "<Target Launcher: LaunchProcess returned %d", ret ); CleanupStack::PopAndDestroy( &targetName ); User::LeaveIfError( ret ); //By now the add proc event should have been delivered to the //test app agent. } } launchSemaphore.Wait( 500000 ); CleanupStack::PopAndDestroy( &launchSemaphore ); if( commandLine ) CleanupStack::PopAndDestroy( commandLine ); }