What is the best way to wait until a cmd is completed?

In the following JScript snippet (where oItem is the full path of a directory):

ClickData.Func.Command.RunCommand ('Cmd /C Dir "' + oItem + '" /R | Clip') DOpus.Delay (2000) var aADSLines = DOpus.GetClip ().split ("\r\n") I set the delay at 2000 ms empirically because with times much shorter than this, the Dir command was sometimes not completed before JScript rushed on and read only the partially written clip. This code is unsatisfactory, however, because two seconds is mostly far too long, and because another computer may be slower or faster.

QUESTION: What is the 'best practice' method of making JScript wait until a cmd has been completed?

Using WScript.Shell and the Run() or Execute() method it provides. At least Run() has a parameter to wait or not. Both methods have pros/cons, so which to use depends on what you like to do. If you run the commandline with DO, I guess you need to tell it to run "synced" or something with the sync modifier or cmd.SetModifier("sync").

Btw: There are more elegant ways to get folder content into the clipboard, but since this is unrelated to your actual question, I'll be quiet. o)

1 Like

tbone, you have saved the day yet again! The following code:

var oWSShell = new ActiveXObject ("WScript.Shell") var oItem = ClickData.func.sourcetab.path oWSShell.Run ('Cmd /C Dir "' + oItem + '" /R | Clip', 4, true) var aADSLines = DOpus.GetClip ().split ("\r\n") for (nn = 0; nn < aADSLines.length; nn++) // THIS IS JUST A CHECK. DOpus.Output (aADSLines [nn]) works in a flash in a small directory, but also grinds out the complete listing of C:\Windows\System32.

BTW is there a 'more elegant way' to get the results of dir oItem /R into the Clipboard? Getting directly at the results of the command Dir oItem is easy, but Dir oItem /R is beyond me, which is why I resorted to DOS (or whatever it should be called these days).

[quote]Btw: There are more elegant ways to get folder content into the clipboard, but since this is unrelated to your actual question, I'll be quiet. o)[/quote] Now it is not unrelated, because I am asking how? Because in a lot of posts I find your input to be a wealth! Thanks so much.

What's the overall aim?

Running the dir command is a pretty horrible way to do anything, I think. Trashing the clipboard content in the process makes it worse, unless the overall aim is to put things into the clipboard (but it looks like the clipboard is just being used as a conduit for the script, which isn't good as you lose whatever was in the clipboard as a side effect of using the script).

There are probably better ways to build up the directory listing in the script itself, without running external commands.

For "dir /R" specifically, which lists ntfs streams, there are not many options available. If the streams are what you are heading for, then using "dir" is fine I think, we had a little observation recently, so I think you know what you're doing: Is this sync procedure using metadata possible?

We could still work on that clipboard way of doing things. As Leo said, that's not optimal for most situations, although it's quite effective compared to not using the clipboard in this exact case. o) But to get around the clipboard, you'd need to capture/redirect the output of dir to some temporary files. The code below might help.

The core of all this is using Shell.Run() with "cmd.exe /C" just like you did, but here stderr + stdout have been redirected to files, which will be read after the command finished. Afaik, this is the only way to get all the output and the returncode of the executable. Consider trimimg down the Log()-thing and what else is not required here.

[code]///////////////////////////////////////////////////////////////////////////////
function RunHiddenAdvanced( exe, params, tmpFileBase, tmpFileExt, shell, fso){
Log("RunHiddenAdvanced():", "t", 1);
if (!fso) fso = new ActiveXObject("Scripting.FilesystemObject");
if (!shell) shell = new ActiveXObject("WScript.Shell");
if (!tmpFileBase) tmpFileBase = "DO.Temp.";
if (!tmpFileExt) tmpFileExt = ".txt";
var tmpFileStdout = CreateTmpFileName(tmpFileBase, tmpFileExt, fso).fullname;
var tmpFileStderr = tmpFileStdout+".err"+tmpFileExt;
var cmd = '%comspec% /c ""'+exe+'" '+params+' >"'+tmpFileStdout+'" 2>"'+tmpFileStderr+'""';
var result = {};
result.cmd = cmd;
Log(" CMD: "+cmd);
if (!fso.FileExists(exe)){
var msg = "Executable not found ["+exe+"]";
Log(msg, "e");
throw msg;
}
result.returncode = shell.Run( cmd, 0, true);

Log("Return: "+result.returncode, "d");
result.stdout = ReadFile(tmpFileStdout, fso); fso.DeleteFile(tmpFileStdout);
result.stderr = ReadFile(tmpFileStderr, fso); fso.DeleteFile(tmpFileStderr);
Log("-", "t", -1);
return result;

}
///////////////////////////////////////////////////////////////////////////////
function ReadFile( path, fso ){
Log("ReadFile():", "t");
fso = fso || new ActiveXObject("Scripting.FilesystemObject");
var content = "";
if (!fso.FileExists(path)){
Log("ReadFile(), file ["+path+"] not found.", "e");
return content;
}
Log("ReadFile(), opening ["+path+"]..", "d");
var file = fso.OpenTextFile( path, 1, -2); // Read, UseDefaultEncoding
if (!file.AtEndOfStream)
content = file.ReadAll();
file.Close();
Log("-", "t", -1);
return content;
}
///////////////////////////////////////////////////////////////////////////////
function CreateTmpFileName(prefix, extension, fso) {
if (!fso) fso = new ActiveXObject("Scripting.FilesystemObject");
var tFolder = fso.GetSpecialFolder(2); // 2 = temp folder
var tFile = fso.GetTempName();
if (prefix!=undefined) tFile=prefix+tFile;
if (extension!=undefined) tFile+=extension;
return {
path : tFolder.Path,
name : tFile,
fullname: tFolder.Path+'\'+tFile
};
}
///////////////////////////////////////////////////////////////////////////////
function Log(text, lvl, ind){ //XLog v0.41
var u,lvs={o:0,x:1,e:2,w:3,i:4,n:5,t:6,d:7,a:8},i=["","X","E","W","I","","","",""];
if (typeof XLog==(u="undefined")){var v=DOpus.Vars; if (v.Exists("XLog") && typeof XLogForce==u) {XLog=v.Get("XLog"); }}
if (typeof XLog==u){var c=Script.Config; if(typeof c!="undefined" && typeof c.XLog!=u){ XLog=c.XLog; }}
if (typeof XLog==u){XLog="normal";} if(XLog.paused===undefined){ if(XLog===true) var L=5;
else if(!isNaN(parseInt(XLog,10))) var L=XLog*1; else var L=lvs[(""+XLog).substring(0,1)]; XLog={paused:false,I:0,L:L};}
lvl=(lvl==undefined?5:lvs[lvl.substring(0,1).toLowerCase()]);
if (!(lvl && XLog.L && !XLog.paused && (lvl<=XLog.L))){ return;} var pad = (XLog.I==0?"":new Array(XLog.I+1).join(" "));
if (i[lvl])pad = i[lvl]+(!pad?" ":pad.substring(1)); if (text!="-"){ var d=DOpus; if (d.Version.AtLeast("11.13.1"))
d.Output(pad+text,((lvl==1||lvl==2)?1:0)); else d.Output(pad+text);}
ind=(ind!==undefined?ind:0);XLog.I+=ind;if(XLog.I<0)throw new Error("XLog indent went sub-zero.");
}

var result = RunHiddenAdvanced( "my.exe", "-param1 /option2");
Log("result.code : " + result.returncode);
Log("result.stdout: " + result.stdout);
Log("result.stderr: " + result.stderr);
[/code]

1 Like

Thank you very much, tbone. I actually have no problem with trashing the clipboard, mostly because I routinely use ClipCache, so that all my recent clips are nicely stored for quick access with minimum keystrokes. The code I have written is running smoothly and correctly, so I will rest content with the second snippet I posted above.

I will, however, continue reading your code carefully for a while yet. Many of the approaches I have never even dreamt of before.

Your welcome and I get your point, if the clipboard route works for you, even with much less code, why not! o)

Whatever you do with these streams, please show and demo the final result. Looks kinda interesting.
Maybe we can reuse the parsing you do on the clipboard/dir content or something, don't know yet. o)