// $Header: /MeWin/Src/WINEXEC.S 51    3/19/96 20:40 Dan $

macro_file WinExec;

#include windows.sh
#include mew_dlgs.sh
#include metools.sh
#include winexec.sh
#include shellapi.sh
#include IDEXE.SH
#include DIALOG.SH
#include STDDLGS.SH
#include MEWLIB.SH
#include MEW.SH

#ifdef _DEBUG_
	#include DBUG.SH
	#include SPRINTF.SH
  #include MSGLOG.SH
#endif

#DEFINE Exec_Use_Semiphore 1

#define _DosExecFile		"DOSEXEC"
#define _Os2ExecFile		"OS2EXEC"
#define _W32ExecFile		"W32EXEC"

#define _ExeExt					".EXE"
#define _IniExt					".INI"
#define _OutExt					".OUT"
#define _SemExt					".SEM"
#define _RunExt					".RUN"
#define _StartExt				".GO"

//#define _Task_Modeless	0
#define _Task_Modeless 	( dlg_Modeless | dlg_NoParDisable )

#define id_Tsk_TaskLst	1000
#define id_Tsk_Process	2001

#define _ExecTask 			"ExecTask_"

global {
	str g_ExecTasks				"ExecTasks";
	str g_TaskOutFile			"!TaskOutFile";

	int g_ExecTaskCnt			"ExecTaskCnt";
	int g_TaskWin					"!TaskWin";
	int g_hTaskDlg				"!hTaskDlg";
}

prototype WINEXEC {
	int  _ExecProcessRC( int ExeType, str OutFile );
	void _ExecTimerEvent( );
	int  _ExecTaskNo( int TaskNo );
	int  _ExecSetTask( int TaskNo, int EventHan, str ExecBkgTaskMac, str Task );
	int  _TaskUpdateLst( );
}

int WinExecAndWait( str Path, str Working_Dir, int Flags, str Title,
				str Semiphore_File ) Trans2
{
	int line_height = 0, font_height = 0, font_width = 0, dfont = 0;
	int main_dlg = 0, visibility = SW_ShowNormal, loop_res = 0;

	int InstanceID, result = _EXEC_Success;

	int Using_Semiphore = ( Svl( Semiphore_File ) != 0 );

	int frame_is_enabled;
	int tr = refresh;

	int NoExec           = ( Flags & _EP_Flags_NoExec );
	int NoWait           = ( Flags & ( _EP_Flags_DontWait | _EP_Flags_RunBkg ) );
	int ShowBypassDlg    = !( Flags & ( _EP_Flags_NoBypass | _EP_Flags_DontWait ) );
	int RunBkg           = ( Flags & _EP_Flags_RunBkg );
	int NoSavFile				 = Flags & _EP_Flags_NoSavFile;
	int SavActivateFlags = ActivateFlags;

	struct TMsg Msg;

	Refresh = False;
	Working;

	ExecErrorCode = 0;

	if ( RunBkg ) {
		ShowBypassDlg = False;
	}
	if ( NoSavFile ) {
		ActivateFlags &= 0xFFFFFFFF ^ _SaveOnDeactivate;
	}
	switch ( flags & 0x000f0000 ) {
		case _EP_FLAGS_HIDE :
			visibility = SW_Hide;
			break;

		case _EP_FLAGS_MINIMIZED :
			visibility = SW_ShowMinimized;
			break;

		case _EP_FLAGS_MAXIMIZED :
			visibility = SW_ShowMaximized;
			break;
	}

	call Build_Exec_Box;

	if ( Using_Semiphore ) {
		set_file_attr( semiphore_file, 0 );
		error_level = 0;
		del_file(semiphore_file);
		error_level = 0;
	}

	if ( NoExec ) {

		int Han;

		if ( S_Create_File( Path, Han ) == 0 ) {  // Create start file
			S_Close_File( Han );
		}
	}
	else {
		int param_index = xpos(" ", path, 1 );

		if(!param_index )
			param_index = svl(path) + 1;

			/*  this is still in the works.
		if(flags & _EP_FLAGS_VMEXEC )
		{
			struct vmdef vmd;
			title = "";             // title of window if in windowed mode
			exePath = copy(Path, 1,param_index - 1 );// Path of .exe to run.
			exeArgs = copy(Path, param_index + 1, 2048 ); // Argument list.
			workDir = working_dir;           // Working drive/dir.
			pifFlags = fPifWindow;           // PIF flags.
			disFlags = 0;           // Display flags.
			pageWant = 640 / 4;     // Desired V86 pages for VM.
			pageMin  = 300 / 4;     // Minimum V86 pages for VM.
			forePriority = 100;       // Foreground priority.
			backPriority = 50;       // Background priority.
			kbMaxEMS     = 4000;       // Maximum EMS KB.
			kbMinEMS     = 0;       // Minimum EMS KB.
			kbMaxXMS     = 4000;       // Maximum XMS KB.
			kbMinXMS     = 0;       // Minimum XMS KB.

			VMExec( &vmdef );
		}
		else { */
			if ( Svl( Working_Dir ) != 0 ) {
			Working_Dir = GetShortName(working_dir);
				if ( ( Svl( Working_Dir ) > 3 ) &&
						( Copy( Working_Dir, Svl( Working_Dir ), 1) == "\\" ) ) {
					Working_Dir = Copy( Working_Dir, 1, Svl( Working_Dir ) - 1 );
				}
			}

			InstanceID = ShellExecute( Frame_Handle, "OPEN",
					Copy( Path, 1, Param_Index - 1 ),
					Copy(Path, param_index + 1, Svl( Path) - Param_Index ),
					Working_Dir, Visibility );
//		}


		if(InstanceID < 32) // a value less than 32 indicates an Exec error
		{
			call Kill_Exec_Box;
			ExecErrorCode = InstanceId;
			refresh = tr;
			return ( _EXEC_Error );
		}
	}
	Working;
	if ( Result == _Exec_Success ) {
		do {
			while ( PeekMessage( &Msg, 0, 0, 0, PM_REMOVE ) ) {
				if( Msg.Message == WM_QUIT) {
					PostMessage( msg.hwnd, msg.message, msg.wparam, msg.lparam );
					Result = _EXEC_Abort;
					break;
				}
				if ( ShowBypassDlg ) {
					if ( Msg.Message == wm_Mew_DlgReturn ) {
						if ( ( Msg.WParam == 2 ) || ( Msg.WParam == 999 ) ) {
							Result = _EXEC_Abort;
							break;
						}
					}
				}
				TranslateMessage( &Msg );
				DispatchMessage( &Msg );
				Working;
			}
			if ( NoWait ) {
				if ( RunBkg ) {
					if ( ( NoWait & _EP_Flags_DontWait ) == 0 ) {

						int TaskNo = _ExecTaskNo( 0 );
						int EventHan = Set_Timer_Event( "_ExecTimerEvent /#=" + Str( TaskNo ) +
								"/I=" + Str( InstanceId ) + "/S=" + Semiphore_File, 18, 0 );

						_ExecSetTask( TaskNo, EventHan, BkgTaskMac, Title );
						BkgTaskMac = "";
						ExecErrorCode = TaskNo;
					}
					SetFocus( Window_Handle );
				}
				Result = _Exec_Abort;
			}
			else if ( Using_Semiphore ) {
				Loop_Res = File_Exists( Semiphore_File ) == 1;
				if ( Loop_Res ) {
					if ( ( NoExec == False ) && ( ExecKeep == 0 ) ) {
						Loop_Res = False;
						Using_Semiphore = False;
					}
				}
			}
			else {
				Loop_Res = ( GetModuleUsage( InstanceId ) == 0 );
		  }
		} while ( !Result && !Loop_Res );
	}
	call Kill_Exec_Box;
	Refresh = tr;
	if ( ( ExecKeep > 0 ) && Svl( Semiphore_File ) || RunBkg ) {
		if ( ( ExecId == _Exe_Id_Dos ) || ( ExecId == _Exe_Id_Os2 ) ||
				( ExecId == _Exe_Id_Nt ) ) {
			SetFocus( Window_Handle );
		}
	}
	ActivateFlags = SavActivateFlags;
	return ( Result );


Build_Exec_Box:
	if ( Svl( Title ) == 0 ) {
		Title = Path;
	}
	if ( ShowBypassDlg ) {
		main_dlg = Create_MEW_Dlg( "Executing...", "", frame_handle, 0);

		Get_MEW_Dlg_Metrics( main_dlg, line_height, font_height, font_width, dfont );

		int dc = GetDc( main_dlg );

		Selectobject( dc, dfont );

		int l = GetTextExtent( dc, title, svl(title) + 1) & 0xFFFF;

		if ( l > 500 ) {
			l = 500;
		}
		if ( l < 100 ) {
			l = 100;
		}
		ReleaseDC( main_dlg, dc );

		Create_MEW_Ctrl( "STATIC", "", SS_BLACKFRAME,1,7,l + 8 ,line_height * 3 + 6,main_dlg,1004,app_handle, 0);
		Create_MEW_Ctrl( "STATIC", title, SS_CENTER,font_width,10,l ,line_height * 3,main_dlg,1004,app_handle, 0);

		Create_MEW_Ctrl( "BUTTON", "Bypass", bs_defpushbutton ,(l / 2) - (font_width * 7),5 * line_height,font_width * 14,line_height + (font_height / 2),main_dlg,2,app_handle, 0);

		EnableWindow( main_dlg, TRUE );
		BringWindowToTop( main_dlg );
		ShowWindow( main_dlg, TRUE );
	}
	/* else
	{
		frame_is_enabled = IsWindowEnabled(frame_handle);
		if(frame_is_enabled)
			EnableWindow( frame_handle, false );
	} */
	ret;

Kill_Exec_Box:
	if ( Main_Dlg != 0 ) {
		Destroy_Mew_Dlg( Main_Dlg );
	}
	/* else
	{
		if(frame_is_enabled)
			EnableWindow(frame_handle, true );
	} */
	ret;

}  // WinExecAndWait

int DosExec( str Path,  str Working_Dir, int Visibility, str Stdio_File,
				str StdErr_File, int Flags ) Trans2
{
	if ( Flags & _EP_Flags_SkipExec ) {
		if ( Flags & _EP_Flags_RunBkg ) {
			Flags |= _EP_Flags_DontWait;
		}
		return ( WinExecAndWait( Path, Working_Dir, Flags, "", "" ) );
	}

	int tr = refresh;
	int tw = window_id;
	int result;
	int ohandle;
	int NoWait = ( Flags & ( _EP_Flags_DontWait | _EP_Flags_RunBkg ) );
	int ExecRunning;
	int Win32 = False;

	str ExeName = _DosExecFile;

	if ( ( g_UseW32Exec && ( BaseOs == _BaseOs_Nt ) ) || ( ExecId & _Exe_Id_Nt ) ) {
		if ( ( BaseOs == _BaseOs_Windows ) || ( BaseOs == _BaseOs_Nt ) ) {
			Win32 = True;
			ExeName = _W32ExecFile;
		}
	}

	str Out_File 			 = TempFileName( ExeName + _OutExt );
	str Ini_File 			 = TempFileName( ExeName + _IniExt );
	str Semiphore_File = TempFileName( ExeName + _SemExt );
	str StartFile 		 = TempFileName( ExeName + _StartExt );

	if ( Win32 ) {
		ExecId = _Exe_Id_Nt;
		ExecRunning = QueryExec( False, _QExecW32 );
		if ( g_W32ExecInUse ) {
			ExecErrorCode = _ExecEC_ExecInUse;
			return ( _Exec_Error );
		}
		g_W32ExecInUse = True;
	}
	else {
		ExecId = _Exe_Id_Dos;
		ExecRunning = QueryExec( False, _QExecDos );
		if ( g_DosExecInUse ) {
			ExecErrorCode = _ExecEC_ExecInUse;
			return ( _Exec_Error );
		}
		g_DosExecInUse = True;
	}
	g_TaskOutFile = Out_File;

	Refresh = False;
	Create_Window;
	File_Name = Ini_File;

	Put_Line( "/O=" + Stdio_File );
	Down;
	Put_Line( "/E=" + Stderr_File );
	Down;
	Put_Line( "/C=" + Path );
	Down;
	if ( Exec_Use_Semiphore ) {
		Del_File( Semiphore_File );
		Put_Line( "/S=" + Semiphore_File );
	}
	Down;
	Put_Line( "/R=" + Str( ( ExecNoDisplay == 0 ) * 2 ) );
	if ( Svl( Working_Dir ) == 0 ) {
		Working_Dir = GetShortName(Get_Path( FExpand( "" ) ));
	}
	if ( ( Svl( Working_Dir ) > 3 ) &&
			( Copy( Working_Dir, Svl( Working_Dir ), 1 ) == "\\" ) ) {
		Working_Dir = Copy( Working_Dir, 1, Svl( Working_Dir ) - 1 );
	}
	Down;
	Put_Line( "/W=" + Working_Dir );
	Down;
	Put_Line( "/K=" + Str( ExecKeep != 0 ) );

	Save_File;

	Delete_Window;
	Switch_Win_Id( Tw );

	if ( ExecRunning == True ) {       // DOSEXEC already running
		Flags |= _EP_Flags_NoExec;
		Result = WinExecAndWait( StartFile, Working_Dir, Flags, Path,
				Semiphore_File );
	}
	else {
		if ( ExecKeep > 0 ) {
			if ( S_Create_File( StartFile, OHandle ) == 0 ) {  // Create start file
				S_Close_File( OHandle );
			}
			StartFile = " " + StartFile;
		}
		else {
			StartFile = "";
		}
		if ( Win32 || ( DosExecMethod == _DosExec_Direct ) ) {
			Result = WinExecAndWait( _UtilsDir + ExeName + ".EXE " + Ini_File + " " +
					Out_File + StartFile, Working_Dir, Flags, Path, Semiphore_File );
		}
		else {
			int fh;
			str PifN[ 128 ];

			PifN = CreateUserPath( ExeName  + "X.PIF", False );

			int pifn_exists = (file_exists( pifn ) == 1);

			if ( pifn_exists ) {
				int lfn = GetFileTime( pifn );
				if ( lfn < GetFileTime(_UtilsDir + ExeName + ".PIF"))
				{
					PifN_Exists = False;
				}
			}

			if ( !pifn_exists ) {
				if ( Copy_File( _UtilsDir + ExeName + ".PIF", pifn, false ) != 0) {
					PifN = _UtilsDir + ExeName + ".PIF";
				}
			}

			if( s_open_file( pifn, 2, fh ) == 0)
			{
				if( s_move_file_ptr( fh, 0, 0x24 ) == 0)
				{
					int count;
					str tstr[80];
					s_read_bytes( tstr, fh, 63 );

					tstr = caps(shorten_str(tstr));
					if ( Get_Path( TStr ) != _UtilsDir ) {
						if ( s_move_file_ptr( fh, 0, 0x24 ) == 0) {
							TStr = _UtilsDir + Truncate_Path( TStr ) + Char( 0 );
							Pad_Str( TStr, 63, " " );
							TStr = Copy( TStr, 1, 63 );
							Count = 63;
							S_Write_Bytes( TStr, Fh, Count );
						}
					}
				}
				s_close_file(fh);
			}
			result = WinExecAndWait( pifn + ' ' + ini_file + ' ' + out_file + StartFile,
					working_dir, flags, path, semiphore_file);
		}
	}
	if ( NoWait != _EP_Flags_RunBkg  ) {
		ExecReturnCode = _ExecProcessRC( ExecId, Out_File );
	}
	g_TaskOutFile = "";
	Refresh = tr;
	return ( Result );

}  // DosExec

int Os2Exec( str Path, str Working_Dir, int Visibility, str Stdio_File,
				str Stderr_File, int Flags ) Trans2
{
	if ( Flags & _EP_Flags_SkipExec ) {
		if ( Flags & _EP_Flags_RunBkg ) {
			Flags |= _EP_Flags_DontWait;
		}
		return ( WinExecAndWait( Path, Working_Dir, Flags, "", "" ) );
	}

	int TRefresh = Refresh;
	int OrgWinId = Window_Id;
	int Result;
	int OHandle;
	int NoWait = ( Flags & ( _EP_Flags_DontWait | _EP_Flags_RunBkg ) );
	int ExecRunning;

	str Out_File = TempFileName( _Os2ExecFile + _OutExt );
	str Ini_File = TempFileName( _Os2ExecFile + _IniExt );
	str Semiphore_File = TempFileName( _Os2ExecFile + _SemExt );
	str StartFile = TempFileName( _Os2ExecFile + _StartExt );

	ExecId = _Exe_Id_Os2;
	ExecRunning = QueryExec( False, _QExecOs2 );
	if ( g_Os2ExecInUse ) {
		ExecErrorCode = _ExecEC_ExecInUse;
		return ( _Exec_Error );
	}
	g_TaskOutFile = Out_File;
	g_Os2ExecInUse = True;

	Refresh = False;
	Create_Window;
	File_Name = Ini_File;

	Put_Line( "/O=" +  Stdio_File );
	Down;
	Put_Line( "/E=" + Stderr_File );
	Down;
	Put_Line( "/C=" + Path );
	Down;
	Del_File( Semiphore_File );
	Put_Line( "/S=" + Semiphore_File );
	Down;
	Put_Line( "/R=" + Str( ( ExecNoDisplay == 0 ) * 2 ) );
	Down;
	if ( Svl( Working_Dir ) == 0 ) {
		Working_Dir = GetShortName(Get_Path( FExpand( "" ) ));
	}
	if ( ( Svl( Working_Dir ) > 3 ) &&
			( Copy( Working_Dir, Svl( Working_Dir ), 1 ) == "\\" ) ) {
		Working_Dir = Copy( Working_Dir, 1, Svl( Working_Dir) - 1 );
	}
	Put_Line( "/W=" + Working_Dir );
	Down;
	Put_Line( "/K=" + Str( ExecKeep != 0 ) );

	Save_File;
	Delete_Window;
	Switch_Win_Id( OrgWinId );

	if ( ExecRunning == True ) {					// OS2EXEC already running
		Flags |= _EP_FLAGS_NOEXEC;
		Result = WinExecAndWait( StartFile, Working_Dir, Flags, Path,
				Semiphore_File );
	}
	else {
		if ( ExecKeep > 0 ) {
			if ( S_Create_File( StartFile, OHandle ) == 0 ) {  // Create start file
				S_Close_File( OHandle );
			}
			StartFile = " " + StartFile;
		}
		else {
			StartFile = "";
		}
		Result = WinExecAndWait( _UtilsDir + _Os2ExecFile + _ExeExt + " " +
				Ini_File + " " + Out_File + StartFile, Working_Dir, Flags, Path,
				Semiphore_File);
	}
	if ( NoWait != _EP_Flags_RunBkg  ) {
		ExecReturnCode = _ExecProcessRC( ExecId, Out_File );
	}
	g_TaskOutFile = "";
	Refresh = TRefresh;
	return( Result );

}  // Os2Exec

int QueryExec(
			int Exit 		 = Parse_Int( "/EXIT=", MParm_Str ),
			int ExecType = Parse_Int( "/T=", MParm_Str ) ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 08-Jul-95  14:07

	Function: Check for currently running EXEC program and shut it down when Exit
						is True.

							 Copyright (C) 1995 by American Cybernectics, Inc.
********************************************************************( ldh )***/
{
	str RunFile;

	int Result;

	switch ( ExecType ) {
		case _QExecDos :
			RunFile = _DosExecFile;
			break;

		case _QExecOs2 :
			RunFile = _Os2ExecFile;
			break;

		case _QExecW32 :
			RunFile = _W32ExecFile;
			break;
	}
	RunFile = TempFileName( RunFile + _RunExt );
	Result = ( File_Exists( RunFile ) == 1 );
	if ( Result == True ) {
		Del_File( RunFile );
		Error_Level = 0;
		Result = ( File_Exists( RunFile ) == 1 );
		if ( Result == False ) {
			switch ( ExecType ) {
				case _QExecDos :
					g_DosExecInUse = False;
					break;

				case _QExecOs2 :
					g_Os2ExecInUse = False;
					break;

				case _QExecDos :
					g_Os2ExecInUse = False;
					break;
			}
		}
	}
	if ( Result && Exit ) {
		ExecId = _Exe_Id_Dos;
		switch ( ExecType ) {
			case _QExecW32 :
				ExecId = _Exe_Id_Nt;

			case _QExecDos :
				DosExec( "EXIT", "", sw_ShowNormal, RunFile, RunFile,
						_EP_Flags_NoExec | _EP_Flags_DontWait );
				break;

			case _QExecOs2 :
				Os2Exec( "EXIT", "", sw_ShowNormal, Runfile, RunFile,
						_EP_Flags_NoExec | _EP_Flags_DontWait );
				break;
		}
	}
	return ( Result );

}  // QueryExec

void ExecShutdown( )
/******************************************************************************
															 Multi-Edit Macro
															 03-Jul-95  15:55

  Function: Prompt for and shutdown the running DosExec and Os2Exec and W32Exec
 						programs.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	str ExeNameStr = "DOSOS2W32";
	str	ExeName;

	int Jx;

	for ( Jx = _QExecDos; Jx <= _QExecW32; ++Jx ) {
		ExeName = Copy( ExeNameStr, ( Jx * 3 ) + 1, 3 ) + "EXEC";
		if ( QueryExec( False, Jx ) ) {
			if ( ExecShutdown == _ExecExit_Prompt ) {
				Return_Int = ( VerifyDlg( "Do you wish to shut it down?",
						ExeName + " Running", "", id_Std_Yes, 0 ) == id_Std_Yes );
			}
			else {
				Return_Int = ( ExecShutdown != _ExecExit_Keep );
			}
			if ( Return_Int ) {
				QueryExec( True, Jx );
			}
		}
	}
}  // ExecShutdown

int ExecTranslate( str &CmdLine )
/******************************************************************************
															 Multi-Edit Macro
															 24-Oct-95  10:11

	Function: `description`
	Entry   : `entry`
	Exit    : `exit`

							 Copyright (C) 1995 by American Cybernetics, Inc.
********************************************************************( ldh )***/
{
	int Result = _exe_id_Unknown;
	int Jx;
	int Jy;

	str TStr;

	if ( Jx = XPos( "<X", CmdLine,1 ) ) {
		CmdLine = Str_Del( CmdLine, Jx, 2 );
		Jy = XPos( ">", CmdLine, Jx );
		if ( Jy > 0 ) {
			Jy -= Jx;
			TStr = Copy( CmdLine, Jx, Jy );
			switch ( TStr ) {
				case "DOS" :
					Result = _exe_id_Dos;
					break;

				case "OS2" :
					Result = _exe_id_Os2;
					break;

				case "W16" :
				case "W32" :
					Result = _exe_id_Windows;
					break;

				case "W32C" :
					Result = _exe_id_Nt;
					break;
			}
			CmdLine = Str_Del( CmdLine, Jx, Jy + 1 );
		}
	}
	return ( Result );

}  // ExecTranslate

int ExecProg(
			str prog[1024]  = parse_str("/PROG=", mparm_str),
      str working_dir = parse_str("/WD=",mparm_str),
      str stdout_file = parse_str("/RED=", mparm_str),
      str stderr_file = parse_str("/REDERR=", mparm_str),
			int flags 			= parse_int("/FLAGS=", mparm_str )
		) trans2
{
  str cmd_line[MAX_LINE_LENGTH],
      tstr,
      tdir[1024] = GetShortName(Fexpand(""));
	str Ext[ 3 ];

	int Cmd 			 = ( ( Flags & _EP_Flags_Comspec ) != 0 );
	int BoundAsDos = ( ( Flags & _EP_Flags_BndAsDos ) != 0 );
  int Result     = _Exec_Error;
	int Jx;

	ExecReturnCode = 0;
  ExecErrorCode = 2;

	Set_Global_Int( "Menu_Level", Global_Int( "Menu_Level" ) + 1 ); //prevents autosave

	if ( BaseOs == _BaseOs_Unknown ) {    // Set BaseOs global if not set
		BaseOs = IdBaseOs( );
	}
	ExecId = ExecTranslate( Prog );
	if ( ExecId == _exe_id_Unknown ) {
		switch ( Flags & _EP_Flags_ExeMask ) {  // Check for exe type override
			case _EP_Flags_ExeDos :
				ExecId = _exe_id_Dos;
				break;

			case _EP_Flags_ExeWin :
				ExecId = _exe_id_Windows;
				break;

			case _EP_Flags_ExeOs2 :
				ExecId = _exe_id_Os2;
				break;

			case _EP_Flags_ExeW32C :
				ExecId = _exe_id_Nt;
				break;

			default:
				ExecId = _exe_id_Unknown;
		}
	}
	ExeType = ExecId;
	Prog = Remove_Space( TranslateCmdLine( Prog, GetShortName( File_Name ) ) );
	Jx = 1;
	if ( XPos( "\"", Prog, 1 ) == 1 ) {
		Jx = XPos( "\"", Prog, Jx + 1 );
	}
	Jx = XPos( " ", Prog, Jx );
	if ( Jx > 0 ) {
		Cmd_Line = Copy( Prog, Jx, 128 );
		Prog = Copy( Prog, 1, Jx - 1 );
	}
	if ( Flags & _EP_FLAGS_WDPROG ) {
		Working_Dir = Get_Path( Prog );
	}
//	if ( Working_Dir != '' ) {
//		if ( Svl( Working_Dir ) > 3 ) {
//			if ( Copy( Working_Dir, Svl( Working_Dir ), 1) == '\' ) {
//				Working_Dir = Copy( Working_Dir, 1, Svl( Working_Dir ) - 1 );
//			}
//		}
//	}
	TStr = Caps( Get_Path( Prog ) );
  if ( Svl( TStr ) == 0 ) {

    str WinDir;

    GetWindowsDirectory( WinDir, 255 );

		if ( Svl( Working_Dir ) != 0 ) {
			TStr = Working_Dir + ";";
		}
    TStr += Get_Environment( "PATH" ) + ";" + WinDir;
	}
	TStr = ExecSearchPath( Prog, TStr );
	if ( Svl( TStr ) != 0 ) {
		Prog = TStr;
		Ext = Caps( Get_Extension( TStr ) );
		if ( ( Ext == "BAT" ) || ( Ext == "CMD" ) ) {
			Cmd = 1;
		}
	}
  if ( Cmd || ( Svl( TStr ) != 0 ) ) {
    if ( StdOut_File ==  "" ) {
      StdOut_File = "NUL";
    }
    if ( StdErr_File ==  "" ) {
      StdErr_File = "NUL";
    }
    if ( ExecId == _Exe_Id_UnKnown ) {
      IdExe( Prog );
      if ( ExeType & ( _Exe_Id_Nt | _Exe_Id_Gui ) ) {
        ExecId = _Exe_Id_Windows;
      }
      else {
        ExecId = ExeType & _Exe_Id_OsMask;
      }
      if ( ( BaseOs != _BaseOs_Os2 ) && ( ExeType & _Exe_Id_Bound ) &&
          ( ExecId == _Exe_Id_Os2 ) ) {
        BoundAsDos = True;
      }
    }
    if ( BoundAsDos ) {
      if ( ( ExeType & _Exe_Id_Bound ) != 0 ) {
        ExecId = _Exe_Id_Dos;
      }
    }
    if ( Cmd ) {
      if ( ( BaseOs == _BaseOs_Os2 ) &&  ( ExecId == _Exe_Id_Os2 ) ) {
        Result = Os2Exec( "CMD.EXE /C " + Prog + Cmd_Line, Working_Dir,
            sw_ShowNormal, Stdout_File, Stderr_File, Flags );
      }
      else {
        Result = DosExec( Comspec + " /C " + Prog + Cmd_Line, Working_Dir,
            sw_ShowNormal, Stdout_File, Stderr_File, Flags );
      }
    }
    else {
      if ( ( ExecId == _Exe_Id_Dos ) || ( ExecId == _Exe_Id_Nt ) ) {
        Result = DosExec( Prog + Cmd_Line, Working_Dir, sw_ShowNormal,
            Stdout_File, Stderr_File, Flags );
      }
      else if ( ( BaseOs == _BaseOs_Os2 ) && ( ExecId == _Exe_Id_Os2 ) ) {
        Result = Os2Exec( Prog + Cmd_Line, Working_Dir, sw_ShowNormal,
            Stdout_File, Stderr_File, Flags );
      }
      else {
        Result = WinExecAndWait( Prog + Cmd_Line, Working_Dir, Flags, "" , "" );
      }
    }
    if ( Svl( Working_Dir ) != 0 ) {
      if ( Svl( TDir ) > 3 ) {
        if ( Copy( TDir, Svl( TDir ), 1 ) == "\\" ) {
          TDir = Copy( TDir, 1, Svl( TDir ) - 1 );
        }
      }
      Change_Dir( TDir );
    }
	}
	else {
    MsgDlg( "Program \"" + Prog + "\" could not be found!", "Exec Error", "", 1 );
	}
	Set_Global_Int( "Menu_Level", Global_Int( "Menu_Level"  ) - 1 ); //prevents autosave
	return ( Result );

}  // ExecProg

macro Exec Trans2 {
/*******************************************************************************
																MULTI-EDIT MACRO

	Description:  Executes a DOS command or program

	Parameters:
								Return_Str = the command line
								/CMD=1		Use COMMAND.COM (or COMSPEC equivalent).
												/WAIT=1   Wait for a key
												/CMDLN=1  Write the command line in the window.
								/RED=str  Redirect stdout to file str
								/REDERR=str Redirect stderr to file str.

										NOTE:  To redirect STDERR to the same file as STDOUT, simply specify
												 	/REDERR=STDOUT

								/APPEND=1 Append redirect file instead of overwrite.

	Returns:			The exit code of the DOS command or program will be in the
								integer EXIT_CODE.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/

	int flags = 0;

	if ( parse_int("/CMD=", mparm_str) == 1 )
	{
		flags |= _EP_FLAGS_COMSPEC;
	}
	if( parse_int("/APPEND=", mparm_str) == 1)
	{
		flags |= _EP_FLAGS_APPEND;
	}


	return_int = ExecProg( return_str, "",parse_str("/RED=", mparm_str),
												 parse_str("/REDERR=", mparm_str),
												 flags );
}  // EXEC

str ExecSearchPath( str Program[ 1024 ], str FPath[ 1024 ] ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 03-Jul-95  15:58

  Function: Searches for a filename in a given path TranslateCmdLine is called
						to parse out any metacommands BEFORE the search takes place.  When
						extension is blank will try to find an executable file .COM .EXE
						.BAT .CMD

  Entry   : str Program	- The executable file name to search for
						str FPath		- The path to search

  Exit    : str					-	Complete path and filename, or a NUL string if the
													search was not successful.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

  str TPath[ 1024 ];
	str Ext = "COMEXEBATCMD";
	str TProg;

	int Jx;
	int Jy = 0;
	int NoExt;
	int ExtLen = Svl( Ext );

	Program = TranslateCmdLine( Remove_Space( Program ), "" );
	if ( Copy( Program, 1, 1 ) == "\"" ) {
		Program = Copy( Program, 2, Svl( Program ) - 2 );
	}
	TPath = TranslateCmdLine( FPath, "" );
	FPath = "";
	NoExt = Get_Extension( Program ) == "";
	while ( True ) {
		if ( NoExt ) {
			for ( Jx = 1; Jx < ExtLen; Jx = Jx + 3 ) {
				TProg = Program + "." + Copy( Ext, Jx, 3 );
				if ( File_Exists( FPath + TProg ) ) {
					return ( GetShortName( FExpand( FPath + TProg ) ) );
				}
			}
		}
		else {
			if ( File_Exists( FPath + Program ) ) {
				return ( GetShortName( FExpand( FPath + Program ) ) );
			}
		}
		if ( Jy > Svl( TPath ) ) {
			return ( "" );
		}
		Jx = XPos( ";", TPath, Jy + 1 );
		if ( Jx == 0 ) {
			Jx = Svl( TPath ) + 1;
		}
		FPath = Remove_Space( Copy( TPath, Jy + 1, Jx - Jy - 1 ) );
		if ( Copy( FPath, 1, 1 ) == "\"" ) {
			FPath = Copy( FPath, 2, Svl( FPath ) - 2 );
		}
		if ( ( Svl( FPath ) > 0 ) && ( Copy( FPath, Svl( FPath ), 1 ) != "\\" ) ) {
			FPath += "\\";
		}
		Jy = Jx;
	}
}  // ExecSearchPath

macro ProgSetupDlg Trans2 {
/*******************************************************************************
  ProgSetupDlg - 4/25/95 5:28PM

  by Todd Johnson, copyright 1995 by American Cybernetics, Inc.

*******************************************************************************/

  int dlg;
  str gs = global_str(parse_str("/GSTR=", mparm_str));

  str working_dir = parse_str("/WD=", gs);


  int flags = parse_int("/F=", gs );

  int dirmode = parse_int("/DM=", gs );
  int ExeType = 1;
  int ShowMode = 0;

	switch ( Flags & _EP_Flags_ExeMask ) {
		case _EP_Flags_ExeDos :
			ExeType = 2;
			break;

		case _EP_Flags_ExeWin :
			ExeType = 3;
			break;

		case _EP_Flags_ExeOs2 :
			ExeType = 4;
			break;

		case _EP_Flags_ExeW32C :
			ExeType = 5;
			break;
	}
  DlgCreate(dlg);

  DlgAddCtrl( dlg, Dlg_GroupBox, "Working directory", 1,1,56, 3,2000, 0,"" );
  DlgAddCtrl( dlg, DLG_RadioButton, "C&urrent", 2, DLG_PosOffset + 1, 0, 0, 2101, 0, "");
  DlgSetInt( dlg, 2101, dirmode == 0 );
  DlgAddCtrl( dlg, DLG_RadioButton, "&Source file", DLG_PosOffset + 12, DLG_PosOffset, 0, 0, 2102, 0, "");
  DlgSetInt( dlg, 2102, dirmode == 1 );
  DlgAddCtrl( dlg, DLG_RadioButton, "Pro&gram", DLG_PosOffset + 16, DLG_PosOffset, 0, 0, 2103, 0, "");
  DlgSetInt( dlg, 2103, dirmode == 2 );
  DlgAddCtrl( dlg, DLG_RadioButton, "Speci&fied", DLG_PosOffset + 12, DLG_PosOffset, 0, 0, 2104, 0, "");
  DlgSetInt( dlg, 2104, dirmode == 3 );
  DlgAddCtrl( dlg, DLG_Text, working_dir, 2, DLG_PosOffset + 1, 53, 0, 2105, 0, "" );

  DlgAddCtrl( dlg, Dlg_static, "E&xecutable Type:", 1,DLG_PosOffset + 2,0, 0,-1, 0,"" );
  DlgAddCtrl( dlg, Dlg_Choice,"Auto detect()Dos()Windows()Os/2()Win32 console()",
			DLG_PosOffset + 18, DLG_PosOffset,
			18, 0,
			2106, 0, "" );
  DlgSetInt( dlg, 2106, exetype );

  DlgAddCtrl( dlg, Dlg_GroupBox, "Show", 1,DLG_PosOffset + 2,20, 4,-1, 0,"" );
  DlgAddCtrl( dlg, DLG_RadioButton, "N&ormal", 2, DLG_PosOffset + 1, 0, 0, 2201, 0, "");
  DlgSetInt( dlg, 2201, (flags & _EP_FLAGS_SHOWMASK) == _EP_FLAGS_NORMAL );
  DlgAddCtrl( dlg, DLG_RadioButton, "M&inimized", 2, DLG_PosOffset + 1, 0, 0, 2202, 0, "");
  DlgSetInt( dlg, 2202, (flags & _EP_FLAGS_SHOWMASK) == _EP_FLAGS_MINIMIZED );
  DlgAddCtrl( dlg, DLG_RadioButton, "M&aximized", 2, DLG_PosOffset + 1, 0, 0, 2203, 0, "");
  DlgSetInt( dlg, 2203, (flags & _EP_FLAGS_SHOWMASK) == _EP_FLAGS_MAXIMIZED );

  DlgAddCtrl( dlg, Dlg_GroupBox, "Options", 23,7,34, 4,-1, 0,"" );
  DlgAddCtrl( dlg, DLG_CheckBox, "&Wait for program to finish", DLG_PosOffset + 1, DLG_PosOffset + 1, 0, 0, 2301, 0, "");
  DlgSetInt( dlg, 2301, (flags & _EP_FLAGS_DONTWAIT) != _EP_FLAGS_DONTWAIT  );

  DlgAddCtrl( Dlg, DLG_CheckBox, "&Run in background",
			dlg_PosOffset + 0, dlg_PosOffset + 1,
			0, 0,
			2302, 0, "" );
  DlgSetInt( Dlg, 2302, ( Flags & _EP_Flags_RunBkg ) != 0 );

  DlgAddCtrl( Dlg, DLG_CheckBox, "&No auto file save when run",
			dlg_PosOffset + 0, dlg_PosOffset + 1,
			0, 0,
			2303, 0, "" );
  DlgSetInt( Dlg, 2303, ( Flags & _EP_Flags_NoSavFile ) != 0 );

  DlgAddCtrl( dlg, DLG_PushButton, "OK", 1, 12, DLG_StanBtnWidth, 0, 100, 0, "/R=1");
  DlgAddCtrl( dlg, DLG_PushButton, "Cancel", DLG_PosOffset | (Dlg_StanBtnWidth + 2), DLG_PosOffset, DLG_StanBtnWidth, 0, 101, 0, "/R=0");
  DlgAddCtrl( dlg, DLG_PushButton, "&Help", 46, DLG_PosOffset, DLG_StanBtnWidth, 0, 102, 0, "/R=2");


  if(DlgExecute( dlg, 100, "Program Setup", "", "", 0 ))
  {
      flags = 0;
      working_dir = DlgGetStr(dlg, 2105 );
      dirmode = 0;

      if(DlgGetInt( dlg, 2102 ) )
      {
        dirmode = 1;
      }
      else
      if(DlgGetInt( dlg, 2103 ) )
      {
        dirmode = 2;
      }
      else
      if(DlgGetInt( dlg, 2104 ) )
      {
        dirmode = 3;
      }


      if(DlgGetInt( dlg, 2202 ) )
      {
        flags |= _EP_FLAGS_MINIMIZED;
      }
      else
      if(DlgGetInt( dlg, 2203 ) )
      {
        flags |= _EP_FLAGS_MAXIMIZED;
      }

      ExeType = DlgGetInt( Dlg, 2106 );
      if ( ExeType == 2 ) {
        Flags |= _EP_Flags_ExeDos;
			}
      else if ( ExeType == 3 ) {
        Flags |= _EP_Flags_ExeWin;
			}
      else if ( ExeType == 4 ) {
        Flags |= _EP_Flags_ExeOs2;
			}
			else if ( ExeType == 5 ) {
				Flags |= _EP_Flags_ExeW32C;
			}
      if ( !DlgGetInt( Dlg, 2301 ) ) {
        Flags |= _EP_Flags_DontWait | _EP_Flags_SkipExec;
			}
			if ( DlgGetInt( Dlg, 2302 ) ) {
				Flags |= _EP_Flags_RunBkg | _EP_Flags_DontWait | _EP_Flags_SkipExec;
			}
			if ( DlgGetInt( Dlg, 2303 ) ) {
				Flags |= _EP_Flags_NoSavFile;
			}
      set_global_str(parse_str("/GSTR=", mparm_str),
                    "/WD=" + double_slashes( working_dir ) +
                    "/F=" +  str(flags) + "/DM=" + str(dirmode)
                    );
  }
  DlgKill(dlg);

} // ProgSetupDlg

void CmdExec( str prog = parse_str("/P=", mparm_str),
              str working_dir = parse_str("/WD=", mparm_str ),
              int flags = parse_int("/F=", mparm_str),
              int work_loc = parse_int("/DM=", mparm_str) ) Trans2
{
/*******************************************************************************
  CmdExec - 4/26/95 10:18AM

  by Todd Johnson, copyright 1995 by American Cybernetics, Inc.

 This macro handles execution of a program as a command.  This is used by
 the key-command mapping when a program is assigned to a command.

*******************************************************************************/
  switch ( work_loc )
  {
    case 0 :
        working_dir = "";
        break;

    case 1 :
        working_dir = get_path( file_name );
        break;

    case 2 :
        working_dir = "";
        flags |= _EP_FLAGS_WDPROG;
        break;

    case 3 :
        working_dir = TranslateCmdLine( working_dir, GetShortName(file_name) );
  }
  ExecProg( prog, working_dir, "", "", Flags );

} // CmdExec

int _ExecProcessRC( int ExeType, str OutFile ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 24-May-95  11:48

  Function: Return the return code from the captured OutFile

  Entry   : int ExeType		- The type of executable run
						str OutFile		- The filename of the captured output

  Exit    : int 		- The return code parsed from OutFile

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int OHandle;
	int ReturnCode = 0;

	str TStr;

	switch ( ExeType ) {
		case _Exe_Id_Dos :
			g_DosExecInUse = False;
			break;

		case _Exe_Id_Os2 :
			g_Os2ExecInUse = False;
			break;

		case _Exe_Id_Nt :
			g_W32ExecInUse = False;
			break;

		default:
			return ( ReturnCode );
	}
	if ( S_Open_File( OutFile, 0, OHandle ) == 0 ) {
		if ( S_Read_Bytes( TStr, OHandle, 127 ) == 0 ) {
			ReturnCode = Parse_Int( "/RETURN_CODE=", TStr );
		}
		S_Close_File( OHandle );
	}
	return ( ReturnCode );

}  // ExecProcessRC

int _ExecTaskNo( int TaskNo ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 23-May-95  12:43

  Function: Get and add a new task number to the task list (TaskNo == 0) or
						Remove TaskNo from the task list and delete its globals.

  Entry   : int TaskNo
							0				- Return a new task number.
							#				- Remove # task from the list.

  Exit    : int
							0			- No task removed
							#			- New or removed task number

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/


	str TStr;
	str GStr = g_ExecTasks;

	if ( TaskNo == 0 ) {									// Add new TaskNo
		do {
			TStr = "/" + Str( ++TaskNo ) + "=";
		} while ( XPos( TStr, GStr, 1 ) );
		g_ExecTasks = GStr + TStr;
		++g_ExecTaskCnt;
	}
	else {																// Delete TaskNo from list
		TStr = "/" + Str( TaskNo ) + "=";
		if ( XPos( TStr, GStr, 1 ) ) {
			Var_Remove_Str( TStr, GStr );
			g_ExecTasks = GStr;
			Set_Global_Str( _ExecTask + Str( TaskNo ), "" );
			--g_ExecTaskCnt;
		}
		else {
			TaskNo = 0;
		}
	}
	return ( TaskNo );

}  // _ExecTaskNo

int _ExecSetTask( int TaskNo, int EventHan, str ExecBkgTaskMac, str Task ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 18-May-95  12:28

  Function:

  Entry   :

  Exit    :

  Globals :

  Macros  :

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int ExeType;

	str GStr = _ExecTask + Str( TaskNo );
	str HStr = "\x7F" + "H=";
	str TStr;

	if ( EventHan == 0 ) {
		TStr = Global_Str( GStr );
		EventHan = Parse_Int( HStr, TStr );
		Var_Remove_Str( HStr, TStr );
		ExeType = Parse_Int( "\x7F" + "ID=", TStr );
		HStr = Parse_Str( "\x7F" + "OF=", TStr );
		ExeType = _ExecProcessRC( ExeType, HStr );
		TStr += "\x7F" + "RC=" + Str( ExeType );
		Set_Global_Str( GStr, TStr );
		_TaskUpdateLst( );
		// Beep on task done when global is set True
		if ( g_BeepTaskDone ) {
			Beep;
		}
	}
	else {

		int Jx = XPos( " ", Task, 1 );

		if ( Jx == 0 ) {
			Jx = Svl( Task );
		}
		else {
			TStr = Copy( Task, Jx, Svl( Task ) - Jx + 1 );
		}
		TStr = HStr + Str( EventHan ) + "\x7F" + "M=" + ExecBkgTaskMac +
				"\x7F" + "C=" + Truncate_Path( Copy( Task, 1, Jx ) ) + TStr +
				"\x7F" + "ID=" + Str( ExecId ) + "\x7F" + "OF=" + g_TaskOutFile;
		Set_Global_Str( GStr, TStr );
		ExecTaskDlg( False );
	}
	return ( EventHan );

}  // _ExecSetTask

void _ExecTimerEvent( ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 23-May-95  12:45

  Function: Background task timer event macro.

  Entry   :

  Exit    :

  Globals :

  Macros  :

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int Result;
	int InstanceId = Parse_Int( "/I=", MParm_Str );

	str Semiphore = Parse_Str( "/S=", MParm_Str );

	if ( Svl( Semiphore ) != 0 ) {
		Result = File_Exists( Semiphore ) == 1;
	}
	else {
		Result = GetModuleUsage( InstanceID ) == 0;
	}
	if ( Result ) {

		int TaskNo = Parse_Int( "/#=", MParm_Str );

		Result = _ExecSetTask( TaskNo, 0, "", "" );
		Kill_Timer_Event( Result );
	}
}  // _ExecTimerEvent

int _TaskUpdateLst( ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 22-May-95  18:37

  Function: Update the task list list box from the defined globals

  Entry   :

  Exit    :

  Globals :

  Macros  :

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	if ( g_hTaskDlg == 0 ) {							// Return when task list not shown
		return ( False );
	}

	int OrgWin = Window_Id;
	int TRefresh = Refresh;
	int hLstWin = GetDlgItem( g_hTaskDlg, id_Tsk_TaskLst );
	int Keep = True;
	int Cnt;
	int Jx;
	int Jy;
	int TaskNo;

	str EvCntStr;
	str Line;
	str EventStr;

	Cnt = ExecChkTask( 0 );
	if ( Cnt == 0 ) {
		SendMessage( hLstWin, lb_ResetContent, 0, 0 );
		return ( False );
	}
	EvCntStr = g_ExecTasks;
	Refresh = False;
	if ( Switch_Win_Id( g_TaskWin ) ) {
		Erase_Window;
		File_Name = "TASKLST.TMP";
		Jy = 2;
    SendMessage( hLstWin, wm_SetRedraw, 0, 0 );
    SendMessage( hLstWin, lb_ResetContent, 0, 0 );
		while ( Cnt-- > 0 ) {
			Jx = XPos( "=", EvCntStr, Jy );
			if ( Jx ) {
				EventStr = Copy( EvCntStr, Jy, Jx - Jy );
				Jy = Jx + 2;
				Val( TaskNo, EventStr );
				Line = Global_Str( _ExecTask + Str( TaskNo ) );
				if ( Parse_Int( "\x7F" + "H=", Line ) == 0 ) {
					Line += "\x7F" + "CM=1";
				}
				Put_Line( "\x7F" + "#=" + Str( TaskNo ) + Line );
    		SendMessage( hLstWin, lb_AddString, 0, 0 );
				Down;
			}
		}
    SendMessage( hLstWin, lb_AddString, 0, 0 );
    SendMessage( hLstWin, wm_SetRedraw, 1, 0 );
    SendMessage( hLstWin, lb_DeleteString, 0, 0 );
		Tof;
    SendMessage( hLstWin, lb_SetCurSel, C_Line - 1, 0 );
		Switch_Win_Id( OrgWin );
	}
	Refresh = TRefresh;
	return ( Keep );

}  // _TaskUpdateLst

int _TaskMsgProc(
        int &RetVal,
        int Window,
        int Message,
        int WParam,
        int LParam,
        str Parms
    ) No_Break Trans2
{
/******************************************************************************
															 Multi-Edit Macro
															 01-Mar-95  16:04

  Function: The task list dialog message proc macro.

  Entry   :

  Exit    :

  Globals :

  Macros  :

							 Copyright (C) 1995 by American Cybernectics, Inc.
********************************************************************( ldh )***/

	int OrgWin = Window_Id;
	int TRefresh = Refresh;
	int TaskNo;
	int Done;

	str TaskStr;

	switch ( Message ) {

		case wm_Destroy :
			Refresh = False;
			if ( Switch_Win_Id( g_TaskWin ) ) {
				Delete_Window;
				Switch_Win_Id( OrgWin );
			}
			g_TaskWin = 0;
			g_hTaskDlg = 0;
			break;

		case wm_Command :
    	switch( WParam ) {
				case dlg_WCmd_Init :
					g_hTaskDlg = Window;
					_TaskUpdateLst( );
					ShowWindow( GetDlgItem( Window, id_Tsk_Process ), sw_Hide );
					return ( True );

				case 998 :
					WParam = GetDefaultButton( Window );
					if ( WParam ) {
						PostMessage( Window, wm_Command, WParam, LParam );
					}
					return( True );

				case id_Tsk_Process :
					Refresh = False;
					if ( Switch_Win_Id( g_TaskWin ) ) {
						TaskStr = Get_Line( );
						TaskNo = Parse_Int( "\x7F" + "#=", TaskStr );
						Switch_Win_id( OrgWin );
						Done = ExecProcessTask( TaskNo, TaskStr, True );
						SetActiveWindow( Frame_Handle );
						if ( Done && ( g_ExecTaskCnt == 0 ) ) {
							if ( _Task_Modeless ) {
								DestroyWindow( Window );
							}
						}
						Refresh = TRefresh;
						return ( True );
					}
					break;
			}
			break;

		case wm_SysCommand :
			if ( WParam == sc_Close ) {
				if ( _Task_Modeless ) {
					DestroyWindow( Window );
					RetVal = 0;
					return ( True );
				}
			}
			break;
	}
	Refresh = TRefresh;
  return ( DlgMessageProc( RetVal, Window, Message, WParam, LParam, Parms ) );

}  // _TaskMsgProc

void ExecTaskDlg( int SwitchFocus = Parse_Int( "/S=", MParm_Str ) ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 23-May-95  12:45

  Function: Show and update the running tasks list modeless dialog.

  Entry   : int SwitchFocus	- When True will cause the focus to be changed
															to the task list dialog. ( "/S=1" )

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int OrgWin = Window_Id;
	int TRefresh = Refresh;
	int Dlg;
	int hDlg;
	int X;
	int Y;

	str Title = "Background Tasks";

  struct tRect Rect;

	if ( g_hTaskDlg != 0 ) {
		_TaskUpdateLst( );
		if ( SwitchFocus != 0 ) {
			SetActiveWindow( g_hTaskDlg );
		}
		return ( );
	}
	if ( ExecQueryNoTasks( ) ) {
		Make_Message( "No tasks defined." );
		return ( );
	}

	Refresh = False;
	Switch_Window( Window_Count );
	Create_Window;
	File_Name = "TASKLST.TMP";
	g_TaskWin = Window_Id;
	Window_Attr = 0x80;

	DlgCreate( Dlg );
  DlgAddCtrl( Dlg, dlg_ListBox, "\x7F" + "CM=/T=4/W=15/H=15" +
					"\x7F" + "#=/W=2/IS=1" + "\x7F" + "C=/W=80",
      1, 1,
      25, 3,
      id_Tsk_TaskLst, 0, "/INCO=1/WIN=" + Str( Cur_Window ) + "/HSCROLL=192" );

  DlgAddCtrl( Dlg, dlg_PushButton, "OK",
      1, 1,
      10, 0,
      id_Tsk_Process, dlgf_DefButton, "" );

  GetWindowRect( Client_Handle, &Rect );
	X = Rect.Right;
	Y = Rect.Top;

	hDlg = DlgBuild( Dlg, Title, "", "", _Task_Modeless | dlg_NoCenter );
  Auto_Size_Mew_Dlg ( hDlg, 100, 100 );
	GetWindowRect( hDlg, &Rect );
	X -= Rect.Right - Rect.Left + 1;
  if ( SendMessage( Client_Handle, wm_MDIGetActive, 0, 0 ) & 0xFFFF0000 ) {
    X -= GetSystemMetrics( sm_cxVScroll ) - 1;
  }
  SetWindowPos( hDlg, 0, X, Y, 0, 0, swp_NoSize | Swp_NoZOrder );

  DlgExecute( Dlg, id_Tsk_TaskLst, Title, "", "/HOOK=_TaskMsgProc",
			_Task_Modeless );
	if ( SwitchFocus == 0 ) {
		SetActiveWindow( Frame_Handle );
	}
	Switch_Win_Id( OrgWin );
	Refresh = TRefresh;

}  // ExecTaskDlg

int ExecChkTask( int TaskNo ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 23-May-95  12:43

	Function: Return the number of background task running ( TaskNo == 0 ) or
 						the handle number of the running task TaskNo.

							 Copyright (C) 1995 by American Cybernectics, Inc.
********************************************************************( ldh )***/

	int Result;

	if ( TaskNo == 0 ) {
		Result = g_ExecTaskCnt;
	}
	else {
	 	Result = Parse_Int( "\x7F" + "H=", Global_Str( _ExecTask + Str( TaskNo ) ) );
	}
	return ( Result );

}  // ExecChkTask

int ExecProcessTask( int TaskNo, str TaskStr, int Prompt ) Trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 23-May-95  15:09

  Function: Run the process macro for TaskNo and remove the task from the
						running task list.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int Result = True;
	int ExeType;
	int hTaskEvent;

	str TStr;

	if ( Svl( TaskStr ) == 0 ) {
		TaskStr = Global_Str( _ExecTask + Str( TaskNo ) );
	}
	ExeType = Parse_Int( "\x7F" + "ID=", TaskStr );
	hTaskEvent = Parse_Int( "\x7F" + "H=", TaskStr );
	if ( hTaskEvent != 0 ) {
		// Check if EXE is still running
		switch ( ExeType ) {
			case _Exe_Id_Dos :
				Result = QueryExec( False, _QExecDos );
				break;

			case _Exe_Id_Os2 :
				Result = QueryExec( False, _QExecOs2 );
				break;

			case _Exe_Id_Nt :
				Result = QueryExec( False, _QExecW32 );
				break;
		}
		if ( Result == True ) {
			if ( Prompt ) {
				TStr = "Task #" + Str( TaskNo ) + " is still running." +
						"\\nDo you want to remove it from the task list?";
				Result = ( VerifyDlg( TStr, "Task Process", "", id_std_No, 0 ) ==
						id_Std_Yes );
			}
			if ( Result ) {
				switch ( ExeType ) {
					case _Exe_Id_Dos :
						g_DosExecInUse = False;
						break;

					case _Exe_Id_Os2 :
						g_Os2ExecInUse = False;
						break;

					case _Exe_Id_Nt :
						g_W32ExecInUse = False;
						break;
				}
				Kill_Timer_Event( hTaskEvent );
				Make_Message( "Task #" + Str( TaskNo ) + " removed from task list" );
			}
		}
		else {
			Beep;
			Kill_Timer_Event( hTaskEvent );
			Make_Message( "Task was stopped, removed from task list" );
			Result = True;
		}
	}
	else {
		ExecId = ExeType;
		TStr = Parse_Str( "\x7F" + "F=", TaskStr );
		ExecReturnCode = Parse_Int( "\x7F" + "RC=", TaskStr );
		TStr = Parse_Str( "\x7F" + "M=", TaskStr );
		if ( Svl( TStr ) != 0 ) {
			Rm( TStr );
		}
	}
	if ( Result == True ) {
		_ExecTaskNo( TaskNo );						// Remove TaskNo from the task list
		_TaskUpdateLst( );								// Update task list dialog
	}
	return ( Result );

}  // ExecProcessTask

int ExecQueryNoTasks( ) {
/******************************************************************************
															 Multi-Edit Macro
															 06-Jul-95  12:40

  Function: Check to see if there are no tasks defined.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	return ( g_ExecTaskCnt == 0 );

}  // ExecQueryNoTasks

int QueryRunTasks( int Prompt = Parse_Int( "/P=", MParm_Str ) ) {
/******************************************************************************
															 Multi-Edit Macro
															 10-Jul-95  10:21

  Function: Checks to see if any background tasks are running. A remove task
						prompt is shown when Prompt is True

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	int OrgWin = Window_Id;
	int TRefresh = Refresh;
	int Result = False;
	int Cnt = g_ExecTaskCnt;
	int Jx;
	int Jy;
	int TaskNo;
	int ShowTasks = False;
	int Dlg;
	int CtrlId = 100;
	int MsgX = 9;

	str EvCntStr;
	str EventStr;
	str TStr;
	str Line[ Max_Line_Length ];

	if ( Cnt != 0 ) {
		if ( Prompt ) {
			Refresh = False;
			Switch_Window( Window_Count );
			Create_Window;
			File_Name = "EXITTASK.TMP";
			Window_Attr = 0x80;
		}
		EvCntStr = g_ExecTasks;
		Jy = 2;
		while ( Cnt-- > 0 ) {
			Jx = XPos( "=", EvCntStr, Jy );
			if ( Jx ) {
				EventStr = Copy( EvCntStr, Jy, Jx - Jy );
				Jy = Jx + 2;
				Val( TaskNo, EventStr );
				Line = Global_Str( _ExecTask + Str( TaskNo ) );
				Result = Parse_Int( "\x7F" + "H=", Line );
				if ( Result ) {
					if ( Prompt ) {
						Put_Line( "\x7F" + "#=" + Str( TaskNo ) + Line );
						Down;
						ShowTasks = True;
					}
					else {
						break;
					}
				}
			}
		}
		if ( Prompt ) {
			if ( ShowTasks ) {
				DlgCreate( Dlg );
  			DlgAddCtrl( Dlg, dlg_Icon, "IC_QUESTION",
      			1, dlg_Units | dlg_Units_HLine,
						0, 0,
      			CtrlId, 0, "" );

				DlgAddCtrl( Dlg, dlg_BlackFrame, "",
						MsgX - 1, dlg_Units | dlg_Units_HLine,
						35, 1,
						++CtrlId, 0, "" );

				DlgAddCtrl( Dlg, dlg_Static, "Remove all running task?",
						MsgX, dlg_PosOffset + 0,
						0, 0,
						++CtrlId, 0, "" );

  			DlgAddCtrl( Dlg, dlg_PushButton, "&Yes",
      			MsgX, dlg_PosOffset | dlg_Units_3HLines,
      			dlg_StanBtnWidth, 0,
      			id_Std_Yes, dlgf_DefButton, "" );

  			DlgAddCtrl( Dlg, dlg_PushButton, "&No",
      			dlg_PosOffset + dlg_StanBtnWidth + 2, dlg_PosOffset + 0,
      			dlg_StanBtnWidth, 0,
      			id_Std_No, 0, "" );

  			DlgAddCtrl( Dlg, dlg_PushButton, "&Help",
      			dlg_PosOffset + dlg_StanBtnWidth + 2, dlg_PosOffset + 0,
      			dlg_StanBtnWidth, 0,
      			id_Std_Help, 0, "/R=2" );

				DlgAddCtrl( Dlg, dlg_Static, "Running Tasks:",
						MsgX, dlg_PosOffset | dlg_Units_3HLines,
						0, 0,
						++CtrlId, 0, "" );
  			DlgAddCtrl( Dlg, dlg_ListBox, "\x7F" + "CM=/T=4/W=15/H=15" +
								"\x7F" + "#=/W=2/IS=1" + "\x7F" + "C=/W=80",
      			dlg_NegOffset + 1, dlg_PosOffset + 1,
      			35, 3,
      			id_Tsk_TaskLst, 0, "/WIN=" + Str( Cur_Window ) + "/HSCROLL=192" );

  			Jx = DlgExecute( Dlg, id_Tsk_TaskLst, "Running Tasks", "", "", 0 );
				DlgKill( Dlg );
				if ( Jx == id_Std_Yes ) {
					Tof;
					while ( !At_Eof ) {
						Line = Get_Line( );
						Down;
						TaskNo = Parse_Int( "\x7F" + "#=", Line );
						ExecProcessTask( TaskNo, Line, False );
					}
					Result = False;
				}
				else {
					Result = True;
				}
			}
			if ( Result == False ) {
				// Remove task list dialog
				if ( g_hTaskDlg ) {
					if ( _Task_Modeless ) {
						DestroyWindow( g_hTaskDlg );
					}
				}
			}
			Delete_Window;
			Switch_Win_Id( OrgWin );
			Refresh = TRefresh;
		}
	}
	Return_Int = Result;
	return ( Result );

}  // QueryRunTasks
