team,

here is a version that works using just one thread to read the streams...it appears that reading stdio/stferr is not thread safe. i am not happy with how the streams are collected, as i believe it is still a bit eror prone. any suggestions/enhancements welcome.

thx,

mike

[CODE]

/*
* Copyright (C) 2002 by Michael Pitoniak (pitoniakm@msn.com).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
*
*   The Free Software Foundation, Inc.,
*   59 Temple Place - Suite 330
*   Boston, MA 02111-1307
*   USA
*/

package utils.dcomServices;

import java.net.UnknownHostException;
import java.util.logging.Level;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.core.IJIComObject;
import org.jinterop.dcom.core.JIComServer;
import org.jinterop.dcom.core.JIProgId;
import org.jinterop.dcom.core.JISession;
import org.jinterop.dcom.core.JIString;
import org.jinterop.dcom.core.JIVariant;
import org.jinterop.dcom.impls.JIObjectFactory;
import org.jinterop.dcom.impls.automation.IJIDispatch;

/*
* You create a WshShell object whenever you want to run a program locally, manipulate the contents of the registry,
* create a shortcut, or access a system folder. The WshShell object provides the Environment collection.
* This collection allows you to handle environmental variables (such as WINDIR, PATH, or PROMPT).
* Microsoft® Windows® Script Host (WSH) is a language-independent scripting host for Windows Script compatible
* scripting engines. It brings simple, powerful, and flexible scripting to the Windows 32-bit platform, allowing
* you to run scripts from both the Windows desktop and the command prompt. Windows Script Host is ideal for
* non-interactive scripting needs, such as logon scripting, administrative scripting, and machine automation.
* A Windows script is a text file. You can create a script with any text editor as long as you save your script
* with a WSH-compatible script extension (.js, vbs, or .wsf). In addition, WMI, for the most part, works exactly the same on remote computers as it does on the local computer. WSH, by contrast, is designed to work only on the local computer. To run WSH scripts remotely, you must use the WshController object and actually create two scripts: the script to be run and the script that allows that script to run remotely. (The WshController object is discussed in detail later in this chapter.)
* In addition, WMI, for the most part, works exactly the same on remote computers as it does on the local
* computer. WSH, by contrast, is designed to work only on the local computer. To run WSH scripts remotely,
* you must use the WshController object and actually create two scripts: the script to be run and the script
* that allows that script to run remotely. (The WshController object is discussed in detail later in this
* chapter.)
*/

public class DcomWScriptServices {
    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(DcomWScriptServices.class);
    private JIComServer comServer = null;
    private IJIDispatch dispatch = null;
    private IJIComObject unknown = null;
    private JISession session = null;
   
   
    public DcomWScriptServices(String hostIp, String domain, String userName, String passWord) throws JIException, UnknownHostException{
        //to debug DCOM change this level
        JISystem.getLogger().setLevel(Level.SEVERE);
        /*Let the j-Interop library do this for you. You can set the "autoRegistration" flag in the
          JISystem class. When the library encounters a "Class not registered" exception, it will
          perform all the registry changes if the autoRegistration flag is set. And then re-attempt
          loading the COM Server. Please have a look at MSSysInfo,MSWMI examples.*/
        JISystem.setAutoRegisteration(true);
        session = JISession.createSession(domain, userName, passWord);
        comServer = new JIComServer(JIProgId.valueOf("WScript.Shell"), hostIp, session);
        unknown = comServer.createInstance();
        dispatch = (IJIDispatch)JIObjectFactory.narrowObject(unknown.queryInterface(IJIDispatch.IID));
    }
   
    public void setCurrentDirectory(String path) throws JIException{
        logger.info(comServer.getProperties());
       
        JIVariant jv = (JIVariant)dispatch.get("CurrentDirectory");
        logger.info(jv.getObjectAsString().getString());
       
        int dispId = dispatch.getIDsOfNames("CurrentDirectory");
        logger.info(dispId);
        JIVariant variant = new JIVariant(path);
        dispatch.put(dispId,variant);
       
        jv = (JIVariant)dispatch.get("CurrentDirectory");
        logger.info(jv.getObjectAsString().getString());
    }
   
    //objShell.CurrentDirectory = "C:\Program Files\Microsoft Virtual PC\"
    //szRun = """Virtual PC.exe"" -singlepc -pc " & szImageName & " -launch"
    public void startVPC(String imageName) throws JIException, UnknownHostException{
       
        JIVariant jv = (JIVariant)dispatch.get("CurrentDirectory");
        logger.info(jv.getObjectAsString().getString());
       
        int dispId = dispatch.getIDsOfNames("CurrentDirectory");
        logger.info(dispId);
        JIVariant variant = new JIVariant("C:/Program Files/Microsoft Virtual PC/");
        dispatch.put(dispId,variant);
       
        jv = (JIVariant)dispatch.get("CurrentDirectory");
        logger.info(jv.getObjectAsString().getString());
       
        //get short file name with dir /x
        //String appName = "VIRTUA~1.EXE -singlepc -pc " + imageName + " -launch";
        //String appName = "\"Virtual PC.exe\" -singlepc -pc " + imageName + " -launch";
        //String appName = "notepad.exe";
        //logger.info(appName);
       
        //"""Virtual PC.exe"" -singlepc -pc " & szImageName & " -launch"
        JIVariant[] b = dispatch.callMethodA("Run", new Object[]{new JIString("\"Virtual PC.exe\" -singlepc -pc " + imageName + " -launch"),new JIVariant(1), new JIVariant(Boolean.FALSE)});
        logger.info(b[0].getObjectAsInt());
       
        //dispatch.callMethod("Exec", new Object[]{new JIString("\"Virtual PC.exe\" -singlepc -pc " + imageName + " -launch")});
    }
   
    /*Runs a program in a new process.

     * object.Run(strCommand, [intWindowStyle], [bWaitOnReturn]) 

     Arguments
    object
    WshShell object.

    strCommand
    String value indicating the command line you want to run. You must include any parameters you want to pass to the executable file.

    intWindowStyle
    Optional. Integer value indicating the appearance of the program's window. Note that not all programs make use of this information.

    bWaitOnReturn
    Optional. Boolean value indicating whether the script should wait for the program to finish executing before continuing to the next statement in your script. If set to true, script execution halts until the program finishes, and Run returns any error code returned by the program. If set to false (the default), the Run method returns immediately after starting the program, automatically returning 0 (not to be interpreted as an error code).

     Remarks
    The Run method returns an integer. The Run method starts a program running in a new Windows process. You can have your script wait for the program to finish execution before continuing. This allows you to run scripts and programs synchronously. Environment variables within the argument strCommand are automatically expanded. If a file type has been properly registered to a particular program, calling run on a file of that type executes the program. For example, if Word is installed on your computer system, calling Run on a *.doc file starts Word and loads the document. The following table lists the available settings for intWindowStyle.

    intWindowStyle
     Description
    
    0
     Hides the window and activates another window.
    
    1
     Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
    
    2
     Activates the window and displays it as a minimized window.
    
    3
     Activates the window and displays it as a maximized window.
    
    4
     Displays a window in its most recent size and position. The active window remains active.
    
    5
     Activates the window and displays it in its current size and position.
    
    6
     Minimizes the specified window and activates the next top-level window in the Z order.
    
    7
     Displays the window as a minimized window. The active window remains active.
    
    8
     Displays the window in its current state. The active window remains active.
    
    9
     Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
    
    10
     Sets the show-state based on the state of the program that started the application.
     */
    

    public int run(String command) throws Exception{
        JIVariant[] jvArr = dispatch.callMethodA("Run", new Object[]{new JIString(command), new JIVariant(1), new JIVariant(Boolean.TRUE)});
        return jvArr[0].getObjectAsInt();
    }
   
    /*
     * Runs an application in a child command-shell, providing access to the stdin/stdout/stderr channels,
     * and the sharing of environment variables.
     */
    public String exec(String command, long timeOuMs) throws Exception{
        /*IJIDispatch wshScriptExec = null;
        StdOutThread stdOutThread = null;
        try{
            JIVariant[] jvArr =  dispatch.callMethodA("Exec", new Object[]{new JIString(command)});
            wshScriptExec = (IJIDispatch)JIObjectFactory.narrowObject(jvArr[0].getObjectAsComObject());
            System.out.println("here");
            try{Thread.sleep(5000);}catch(Exception e){}
            stdOutThread = new StdOutThread(wshScriptExec);
            stdOutThread.start();
            System.out.println("started StdOutThread");
            stdOutThread.join(timeOuMs);
            System.out.println("joined up on StdOutThread");
            stdOutThread.stop();
        }catch(Exception e){
            logger.error(e, e);
        }finally{
            System.out.println("Terminating");
            try{wshScriptExec.callMethodA("Terminate");}catch(Exception e){}
            System.out.println("Done Terminating");
            System.out.println("destroyed");
        }
       
        return stdOutThread.getStdOut() + stdOutThread.getStdErr();*/
       
       
       
        ExecThread execThread = new ExecThread(command, timeOuMs);
        execThread.start();
        execThread.join(timeOuMs);
        return execThread.getResponse();
    }
   
   
   
    /*Runs an application in a child command-shell, providing access to the StdIn/StdOut/StdErr streams.

object.Exec(strCommand)

Arguments
object
WshShell object.

strCommand
String value indicating the command line used to run the script. The command line should appear exactly as it would if you typed it at the command prompt.

Remarks
The Exec method returns a WshScriptExec object, which provides status and error information about a script run with Exec along with access to the StdIn, StdOut, and StdErr channels. The Exec method allows the execution of command line applications only. The Exec method cannot be used to run remote scripts. Do not confuse the Exec method with the Execute method (of the WshRemote object).

*/
   
   
    public void destroySession() throws Exception{
        JISession.destroySession(session);
    }
   
    private class ExecThread extends Thread{
        String command = null;
        long timeOuMs;
        StreamReaderThread streamReaderThread = null;
       
        public ExecThread(String command, long timeOuMs){
            this.command = command;
            this.timeOuMs = timeOuMs;
        }
       
        public void run(){
            IJIDispatch wshScriptExec = null;
            try{
                JIVariant[] jvArr =  dispatch.callMethodA("Exec", new Object[]{new JIString(command)});
                wshScriptExec = (IJIDispatch)JIObjectFactory.narrowObject(jvArr[0].getObjectAsComObject());
                streamReaderThread = new StreamReaderThread(wshScriptExec);
                streamReaderThread.start();
                streamReaderThread.join(timeOuMs);
                streamReaderThread.stop();
            }catch(Exception e){
                logger.error(e, e);
            }finally{
                try{wshScriptExec.callMethodA("Terminate");}catch(Exception e){}
            }
        }
       
        public String getResponse(){
            return streamReaderThread.getStdOut() + streamReaderThread.getStdErr();
        }
    }
   
    private class StreamReaderThread extends Thread{
        IJIDispatch wshScriptExec = null;
        private StringBuffer stdOutBuffer = null;
        private StringBuffer stdErrBuffer = null;
       
        public StreamReaderThread(IJIDispatch wshScriptExec){
            this.wshScriptExec = wshScriptExec;
        }
       
        public void run(){
            JIVariant[] jvArr = null;
            try{
                stdOutBuffer = new StringBuffer();
                stdErrBuffer = new StringBuffer();
                JIVariant stdOutJIVariant =  wshScriptExec.get("StdOut");
                IJIDispatch stdOut = (IJIDispatch)JIObjectFactory.narrowObject(stdOutJIVariant.getObjectAsComObject());
                JIVariant stdErrJIVariant =  wshScriptExec.get("StdErr");
                IJIDispatch stdErr = (IJIDispatch)JIObjectFactory.narrowObject(stdErrJIVariant.getObjectAsComObject());
                while(!((JIVariant)stdOut.get("AtEndOfStream")).getObjectAsBoolean()){
                    stdOutBuffer.append(stdOut.callMethodA("ReadAll").getObjectAsString().getString());
                }
                while(!((JIVariant)stdErr.get("AtEndOfStream")).getObjectAsBoolean()){
                    stdErrBuffer.append(stdErr.callMethodA("ReadAll").getObjectAsString().getString());
                }
            }catch(Exception e){
                logger.error(e, e);
            }
        }
       
        public String getStdOut(){
            return stdOutBuffer.toString();
        }
       
        public String getStdErr(){
            return stdErrBuffer.toString();
        }
    }

   
    //"localhost", "ctron", "mpitonia", "ChrisSarah1"
    //"VPC003", "automation" , "automated_user", "@utom@tion"
    //"automationsvr01", "AUTOMATION", "Automated_User", "@utom@tion"
    public static void main(String[] args) {
        DcomWScriptServices wScriptServices = null;
       
        try{
            wScriptServices = new DcomWScriptServices("localhost", "ctron", "mpitonia", "TestHarness!");
            //wScriptServices.startVPC("VPC002");
            //logger.info(wScriptServices.exec("ping -n 3 -w 2000 localhost"));
            //logger.info(wScriptServices.exec("ipconfig"));
            System.out.println((wScriptServices.exec("cmd /C dir c:\\ann /s", 10000)));
            //logger.info(wScriptServices.exec("cmd /C echo test >> c:\\a.txt"));
            //logger.info(wScriptServices.run("cmd /C attrib +r  c:\\a.txt"));
            //logger.info(wScriptServices.run("notepad.exe"));
            //logger.info(wScriptServices.run("cmd /k"));
            //logger.info(wScriptServices.ping("localhost"));
        }catch (Exception e) {
            logger.error(e, e);
        }finally{
            try{
                wScriptServices.destroySession();
            }catch(Exception e){
                //silent
            }
        }
    }
   
}

{/CODE]