#include #define STRICT #define XVT_INCL_NATIVE #include #if XVT_OS == XVT_OS_WIN #include #include #include #endif #if XVT_OS == XVT_OS_SCOUNIX #include #include #endif #include #include #include #include #include #include #include // @doc EXTERNAL // @mfunc Controlla se il processo puo' essere eseguito // // @rdesc Ritorna i seguenti valori: // // @flag TRUE | Se l'applicazione puo' essere eseguita // @flag FALSE | Se l'applicazione non puo' essere eseguita bool TExternal_app::can_run() const // @comm Se si opera sotto Windows si controlla se vi sono risorse necessarie // per l'esecuzione del processo, altrimenti viene tornato sempre TRUE. { #if XVT_OS == XVT_OS_WIN const TFixed_string p(_path); const bool big = p.find("cg0") == 0 && p.right(2) == "-1"; const int richieste = big ? 50 : 15; const int libere = GetFreeSystemResources(GFSR_SYSTEMRESOURCES); return libere >= richieste; #else return TRUE; #endif } // @doc EXTERNAL // @mfunc Esegue il processo // // @rdesc Ritorna il codice di uscita del processo (-1 in caso di errore). word TExternal_app::run( bool async, // @parm Per eseguire il processo in parallelo (default FALSE) bool utente) // @parm Permette di inserire il nome dell'utente nella riga // di comando(default TRUE) // @comm Se

e' FALSE aspetta che termini il processo in esecuzione prima di iniziare il nuovo { TFilename path(_path); TString name(path.name()); int p = name.find(' '); if (p >=0) name = name.left(p); const bool our_app = name.len() > 2 && (isalpha(name[0]) || name[0] == '7') && isalnum(name[1]) && isdigit(name[2]); if (!our_app) utente = FALSE; if (utente) #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32 path << " /u" << user(); #else path << " -u" << user(); #endif _error = 0; _exitcode = 0; // save cwd xvt_fsys_save_dir(); const TFilename dir(path.path()); if (dir.not_empty()) { DIRECTORY d; if (xvt_fsys_convert_str_to_dir((char *) (const char *) dir, &d)) xvt_fsys_set_dir(&d); } if (our_app) { TString parms(_path); TString new_suffix; int p = parms.find(' '); if (p < 0) { parms = ""; new_suffix = "_0"; } else { parms = parms.mid(p + 1); p = parms.find(' '); if (p >= 0) new_suffix = parms.left(p); else new_suffix = parms; if (new_suffix[0] == '-') new_suffix[0] = '_'; else new_suffix = "__"; } TFilename newpath(dir); if (newpath.not_empty()) newpath << '/'; newpath << name << new_suffix; newpath.ext("exe"); if (fexist(newpath)) { newpath.ext(""); newpath << parms; path = newpath; if (utente) #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32 path << " /u" << user(); #else path << " -u" << user(); #endif } } #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32 if (can_run()) { main_app().begin_wait(); #if XVT_OS == XVT_OS_WIN HL_LOGOUT(); _exitcode = WinExec((char*)(const char*)path, SW_SHOW); if (_exitcode >= 32) { if (!async) { TTemp_window tw(TASK_WIN); if (utente) { tw.iconize(); tw.deactivate(); } HTASK child = NULL; TASKENTRY te; te.dwSize = sizeof(TASKENTRY); for (bool ok = TaskFirst(&te); ok; ok = TaskNext(&te)) if (te.hInst == (HINSTANCE)_exitcode) { child = te.hTask; break; } // Warning! child could be NULL if you run that beast called Foxpro main_app().wait_for((word)child); for (byte i = 0; main_app().waiting() == (word)child; i++) { // Esegue il controllo solo ogni 256 cicli if (i == 0 && ok && TaskFindHandle(&te, child) == FALSE) { main_app().wake_up(); // Annulla attesa del processo break; } xvt_app_process_pending_events(); } if (utente) { tw.maximize(); tw.activate(); xvt_app_process_pending_events(); } } xvt_statbar_refresh(); } #else STARTUPINFO start; PROCESS_INFORMATION pi; start.cb = sizeof(start); start.lpReserved = start.lpDesktop = start.lpTitle = NULL; start.dwX = start.dwY = start.dwXSize = start.dwYSize = CW_USEDEFAULT; start.dwXCountChars = start.dwYCountChars = start.dwFillAttribute = 0L; start.dwFlags = STARTF_USESHOWWINDOW; start.wShowWindow = SW_SHOW ; start.cbReserved2 = 0; start.lpReserved2 = NULL; start.hStdInput = NULL; start.hStdOutput = NULL ; start.hStdError = NULL; BOOL started = CreateProcess(NULL,(char*)(const char*)path, NULL, NULL, FALSE, 0, NULL, NULL, &start, &pi); if (started) { HANDLE hProcess = pi.hProcess; if (!async) { TTemp_window tw(TASK_WIN); if (utente) { tw.iconize(); tw.deactivate(); } if (WaitForSingleObject(hProcess, INFINITE) != 0xFFFFFFFF) { unsigned long exitcode; if (GetExitCodeProcess(hProcess, &exitcode)) _exitcode = (int) exitcode; else _exitcode = -2; } if (utente) { tw.maximize(); tw.activate(); } } else _exitcode = 0; CloseHandle(pi.hThread); CloseHandle(hProcess); } else _exitcode = -1; #endif main_app().end_wait(); } else _exitcode = 1; #if XVT_OS == XVT_OS_WIN _error = _exitcode; switch (_exitcode) { case 0: case 1: error_box("Risorse insufficienti per eseguire '%s'", (const char*)_path); break; case 2: case 3: error_box("Impossibile trovare '%s'", (const char*)_path); break; case 16: error_box("'%s' e' gia' in esecuzione", (const char*)_path); break; default: if (_exitcode < 32 && _exitcode != 8) error_box("Impossibile eseguire '%s':\nErrore %u", (const char*)_path, _exitcode); else { if (_exitcode != 8) _error = 0; _exitcode = 0; } break; } #else switch (_exitcode) { case -2: error_box("Impossibile ricevere il valore di ritorno da '%s':\nErrore %ld", (const char*)_path, GetLastError()); break; case -1: error_box("Impossibile eseguire '%s':\nErrore %ld", (const char*)_path, GetLastError()); break; case 8: error_box("Risorse insufficienti per eseguire '%s'", (const char*)_path); break; case 0: break; default: error_box("Valore di ritorno di '%s':\n %ld", (const char*)_path, _exitcode); break; } #endif #else switch (fork()) { case -1: _error = errno; _exitcode = -1; break; case 0: const char* s = strdup(path); char* p = strchr(s, ' '); if (p) *p = '\0'; const char* pathn = strdup(s); const char* args[21]; int i = 0; args[i++] = pathn; while ((i < 20) && (p)) { s = p + 1; p = strchr(s, ' '); if (p) *p = '\0'; args[i++] = strdup(s); } args[i] = NULL; for (i = 3; i < _NFILE; i++) fcntl(i,F_SETFD,1); // execvp( path, NULL); execvp ( pathn , args ); exit ( -1 ); default: if(wait(&_exitcode) == -1) { error_box("Impossibile eseguire '%s':\nErrore %d", (const char*)_path, _exitcode); _exitcode = -1; } else _exitcode = _exitcode >> 8; break; } _error = errno; xvt_app_escape(XVT_ESC_CH_REFRESH); #endif // restore cwd xvt_fsys_restore_dir(); // update counts if (_exitcode == 0) _count++; #if XVT_OS == XVT_OS_WIN // Ignora volutamente il return code da HL_LOGIN(). Se va bene riprende il posto // altrimenti fa lo stesso. Infatti puo' capitare con una chiave di rete, che // nel lasso di tempo trascorso dalla HL_LOGOUT() dell'applicazione chiamata, // a questa HL_LOGIN() [approssimativamente qualche decimo di secondo], qualche altro // programma si inserisca, occupando magari anche l'ultimo posto disponibile. // Quindi se si verificasse tale sfigatissima condizione, sicuramente // non ci saranno piu' posti liberi nell'HL_server: il programma comunque non // puo' interrompersi a meta'; ecco perche il valore di ritorno di HL_LOGIN viene // ignorato. HL_LOGIN(ModAd, DONT_CARE, REFKEY, VERKEY); #endif return _exitcode; } TExternal_app::TExternal_app(const char* p) { _path = p; _count = 0; _error = 0; _exitcode = 0; }