Skip to main content
Known Participant
November 4, 2005
Question

How to run the callback fucntion onReceive[Static+callback]-onResult-onError and sendData?

  • November 4, 2005
  • 20 replies
  • 2819 views
Hi, everybody,
I can run this script in indesign cs2 very well,
But now I went to get the target running script is OK or No, and When it completed,
Now I would like those info. send back to the sender, then do some otherthings.
So, help me how to get those infors, include the errorMsg.

Thanks advanced!

jxswm

//=======================================================

//RunScript
//Usage:
//Define the scriptEnum and runTargetScript(scriptEnum), all is OK!
//Set the scriptEnum.scriptStr = null, will do not run the ScriptString;
//Set the scriptEnum.fileURI = null, will do not run the ScriptFile;
//Set the scriptEnum.isRunTargetApp = true, will run the target program before run the script;
//Set the scriptEnum.isBringToFront = false, will not bring the target program 's main window
//is not brought to the front of the screen.
//eg:
//In indesign CS2, run below script, you can see the result

do{
var scriptEnum = {};
scriptEnum.senderAppName = "indesign";
scriptEnum.targetAppName = "bridge";//"illustrator";//"photoshop";//"bridge"
scriptEnum.isRunTargetApp = true;
scriptEnum.isBringToFront = true;
scriptEnum.fileURI = null;//"D:\\Adobe\\Adobe Indesign CS2\\Presets\\Scripts\\File+Folder\\00)FilesReport.js";
scriptEnum.scriptStr =
"alert(\"Hellow World! From " + scriptEnum.senderAppName + "-> " + scriptEnum.targetAppName + "\");\n"+
"var result = {}; \n"+
"result.file = new File(\"c:\\1.jpg\");\n"+
"result.toSource();";

if(!validateSenderScriptVersion(scriptEnum)){break;}
#target indesign

if(!runScript(scriptEnum)){
alert("Run the script failure!");
break;
}
}while(false);

function validateSenderScriptVersion(scriptEnum){
switch(scriptEnum.senderAppName){
case "indesign": return app.version != 3; break;
default: break;
}
return false;
}

function runScript(scriptEnum){
if(BridgeTalk.appName != scriptEnum.senderAppName ){return false;}
var targetAppName = scriptEnum.targetAppName;
if(!BridgeTalk.getSpecifier(targetAppName)){return false;}
if(scriptEnum.isRunTargetApp){
if(!BridgeTalk.isRunning(targetAppName)){
var runtime = 0;
var totalDelayTime = 180*1000;
var periodDelyTime = 3*1000;
if(scriptEnum.isBringToFront){
if(BridgeTalk.launch(targetAppName)){
//There might be a queued for sending later for still not run the target app,
//so wait it 15s until the target app run completly.
//if(delayTime(180*1000, 3*1000, !BridgeTalk.isRunning(targetAppName))){return false;}
while(totalDelayTime > runtime && !BridgeTalk.isRunning(targetAppName)){
$.sleep(periodDelyTime);
runtime += periodDelyTime;
}
if(!BridgeTalk.isRunning(targetAppName)){return false;}
}else{return false;}
}else{
if(BridgeTalk.launch(targetAppName, "background")){
while(totalDelayTime > runtime && !BridgeTalk.isRunning(targetAppName)){
$.sleep(periodDelyTime);
runtime += periodDelyTime;
}
if(!BridgeTalk.isRunning(targetAppName)){return false;}
}else{return false;}
}
}
}
var sStr = scriptEnum.scriptStr;
if(!sStr || sStr == ""){sStr = load(scriptEnum.fileURI);}
if(!sStr || sStr == ""){return false;}
if(!runScriptAString(sStr, targetAppName, scriptEnum.isBringToFront)){
return false;
}
return true;
}
This topic has been closed for replies.

20 replies

Known Participant
November 6, 2005
OK, Thanks!! That is much clearer. And please don't apologize for your English, it's certainly better than my Chinese!!

The issue you're going to have is remembering the where you are in the process in InDesign between chained bridgetalk calls.

Here's a script (set to run in the ESTK) that will do that for you. It uses photoshop, and simply opens and closes each file to be processed. If you add your ID code, and add the code to make Photoshop do what you want, you'll be there.

If there's a chance of doing this on more than one file, you may want to make it a bridge script. It would be interesting - perhaps very interesting to many people - select a set of ID files in Bridge, it would open, get the images, do the processing in Photoshop for each image, re-link them in ID, and then move on to the next ID file...

And we could certainly show progress bars in for the entire process and for each file.

Think about it, I'll help you if you want to try it.

Bob
Adobe Workflow Scripting

#target estoolkit;
// when you'r ready to acutally run this thing, change the target (above) to indesign!!!!

// this up here is just to get a list of files to work on
var d = Folder.selectDialog();
var files = d.getFiles();

// below here should run just fine in InDesign, all you need to to is get the list of files and fill in
// the functions that take action in either InDesign or Photoshop

// The reason for creating a FileIterator class is to give you an instance of an object that remembers
// where it is in the process, it tracks it's own index into the file list.
// The onResult and onError handlers execute in the context of the original BridgeTalk message,
// so if you save a reference to your FileIterator instance in the BridgeTalk message, you can access it
// using "this" inside the onResult and onError handlers. see line 23 below - we create a FileIterator property
// on the BridgeTalk message
FileIterator = function( files ) {
this.files = files;
this.index = -1; // because we use a pre-increment in the execute phase - start at -1, so the first file is index 0
this.resultStates = new Array();
}
FileIterator.prototype.run = function() {
var bt = new BridgeTalk();
bt.FileIterator = this;
bt.target = "photoshop";
bt.body = this.getScript();
bt.onResult = function( msg ) {
// if you're here, the file was successfully processed, so get the file from the FileIterator
// note that since we're maintaining state here, you don't actually need what's in the message
var sucessfullyProcessedFile = this.FileIterator.files[ this.FileIterator.index ];
// this next line stores the result for future processing (when everything's over),
// true -means it sucessfully processed, false means it did not.
this.FileIterator.resultStates.push( true );
// here, you do whatever you needed in InDesign - relink, for example
// I don't know what UI Indesign supports, but you would also update your progress bar here
// because this example executes in estoolkit, I am using a writeln;
$.writeln( "Processed ( " + this.FileIterator.index + " ): " + sucessfullyProcessedFile.name );
// here we check to see if we've processed the whole array, if so, don't send another message,
// and move on to writing a log file or whatever...

if ( ( this.FileIterator.index + 1 ) == this.FileIterator.files.length ) {
return;
} else {
var bt = new BridgeTalk();
bt.FileIterator = this.FileIterator;
bt.target = "photoshop";
bt.body = this.FileIterator.getScript();
bt.onResult = this.onResult;
bt.onError = this.onError;
bt.send();
}
}
bt.onError = function( msg ) {
var failedFile = this.FileIterator.files[ this.FileIterator.index ];
// here, do the processing on a failed file using the variable failedFile
this.FileIterator.resultStates.push( false ); // for a failed file
$.writeln( "Failed ( " + this.FileIterator.index + " ): " + sucessfullyProcessedFile.name );
if ( ( this.FileIterator.index + 1 ) == this.FileIterator.files.length ) {
return;
} else {
var bt = new BridgeTalk();
bt.FileIterator = this.FileIterator;
bt.target = "photoshop";
bt.body = this.FileIterator.getScript();
bt.onResult = this.onResult;
bt.onError = this.onError;
bt.send();
}
}
// someplace around here you will initialize your progress bars, if possible in InDesign
bt.send();
}

FileIterator.prototype.getScript = function() {
var remoteScript = "var f = " + this.files[ ++this.index ].toSource() + ";\n";
remoteScript += "remoteScript = " + FileIterator.remoteScript.toString() + "\n";
remoteScript += "remoteScript( f );\n";
return remoteScript;
}
// this is the function we will be executing in Photoshop - after the doc = app.open( file ) statement,
// put in your magic for Photoshop.
// IMPORTANT - REMEMBER that this function will be executing on PHOTOSHOP's environment!
// It will execute ONCE for each file that you have in your list.
FileIterator.remoteScript = function( file ) {
var startDialogMode = app.displayDialogs;
app.diaplayDialogs = DialogModes.NO;
var doc = app.open( file );
// doc.save();
doc.close( SaveOptions.DONOTSAVECHANGES );
app.displayDialogs = startDialogMode;
}

// the next two lines initialize and kick off the process
var fileIterator = new FileIterator( files );
fileIterator.run();
"FileIterator is Running!";
_jxswm_Author
Known Participant
November 6, 2005
Thank Bob and Andrew,

Your kind answers give me a lot of informations.

I want to run a script in indesign cs2, call the photoshop cs2 appilication, open the linked image file that linked in the indesign's activeDocument, change the image size and resolution in photoshop, save it and close the file in photoshop, then relink the image in indesign document.

In this process, I must know whether the photoshop can open a image or not and can change the image size and save it to the original image file, so I must send a message to the Indesign and let indesign process the returned message, if the photoshop can do the change size and set resolution, then Indesign will do the relink function, if not sucess or get a error message, do an another function,
In this process, I also must know when the Photoshop finninsh the above actions, then Indesign begin the relink function, if the photoshop still incompleted the process, it is nosense of the Indesign do the relink function; if suncess, then begin the next image... until all images processed.

My indesign document have more than 800 images , so I want the photoshop to do the repeating work, and also want a progress bar to show the process in Indesign, if indesign can not do the progress bar, I must create a text file to report the script running log.

This is all!
Sorry for my poor English.

Now I can using the onResult fucntion, and process the lastest result message and the error message.

But I still can not konw whether one image processed sucessful or not, then goto the next image,

Please help me again to get this function and not abort the indisgn script.
I still don't know how to use the BridgeTalk onReceive function. I need some simple codes like the onReceive function to understand the onReceive function.

My homelaguage is chinese,
Because my poor English,
can you understand my ideas this time?

Thanks again!

jxswm
Known Participant
November 5, 2005
By 'wait' I meant sleep of course.

Andrew
Known Participant
November 5, 2005
I had some thoughts on this also. What can and can't de done depends on the detail and neither Robert nor myself have really understood the detail yet. But anyway...

It is not hard to get a script to use BridgeTalk to start a script in another app.

It is also not hard to pass data between scripts on two apps - you can either build the data into the BridgeTalk string, or save it to a file and then read that file from the target script.

If necessary you can use 'wait' to halt one script while it waits for data and if the data is in an external file you can check the lastmodified date of that file to establish when it updates (I don't like this method because I suspect it chews up processing resource but it does work).

One way to acheieve back-and-forth communication is to allow your originating scripts to end and to be restarted again by the target script (it is sometimes possible to write the scripts at each end so that they interact as if it is a single sequence). The key to this making sense is that the originating script has to finish pretty much immediately after sending the BT - otherwise there is a risk that it gets restarted before it is finished leading to an error.

It is also trivial to pass the error message by passing 'e' from a catch statement to the other script.

None of this may help but they are just some ideas.

Andrew
Known Participant
November 5, 2005
BTW, what's your native language? You're doing something I certainly can't do - explain a technical issue in a foreign language...

Perhaps I can get someone to translate for us.

Bob
Known Participant
November 5, 2005
Still not certain exactly what you're trying to do, but here goes.

I think that one thing you are missing is that BridgeTalk messages are sent asynchronously. When you execute BridgeTalk.send(), the message will be sent, and your script in the sending application will continue.

The onResult handler of your original BridgeTalk message is called when the remote script completes execution. The onError handler executes if the remote script causes an error.

Here's a script that executes in the ESTK, and communicates with bridge.

It generates a script to be executed in bridge, passing it an array of numbers. The remote script takes the last number in the array, adds 1 to it, and sends the array back.

The onResult handler checks to see if the returned array's length is less than 20, if so, it creates a new bridgetalk message, and generates the script again with the data returned from the previous message. (it then writes the length to the JS console in ESTK). If the length is more than 20, it sends a script to Bridge that will definitely cause an error (to show you how the onError handler works).

Open the ESTK, paste in the script, and execute it. To see the flow, place debugger statements in the onResult hander, the onError handler, and at the top of the remote script. You can then step through the entire execution cycle.

I hope this gives you the information you need.

Bob
Adobe WAS Scripting

#target estoolkit

var target = "bridge";
var data = new Array();
data[0] = 0;

var getScript = function( data ) {
var remoteScript = "var data = " + data.toSource() + ";\n";
remoteScript += "var n = data[ data.length - 1 ] + 1;\n";
remoteScript += "data.push( n );\n";
remoteScript += "data.toSource();\n";
return remoteScript;
}

onResultHandler = function( bt ) {
data = eval( bt.body );
var msg = new BridgeTalk();
msg.target = target;
if ( data.length < 20 ) { // if less than 20 round trips, keep going
$.writeln( "array length: " + data.length );
msg.body = getScript( data );
} else { // once we're at 20, send something that will cause an error in bridge
msg.body = "fred.barney = 12;";
}
msg.onResult = onResultHandler;
msg.onError = onErrorHandler;
msg.send();
}
onErrorHandler = function( bt ) {
alert( bt.body );
}

var bt = new BridgeTalk();
bt.target = target;
bt.body = getScript( data );
bt.onResult = onResultHandler;
bt.onError = onErrorHandler;

bt.send();
_jxswm_Author
Known Participant
November 5, 2005
Btw:
In lib1, I can not find some objs or function, like function isValidReference()..
In lib1, obj sendBridgeTalkMessage->bt.onResult = onResultHandler;
the onResultHandler method not defined?---
Here I can not make a sucess, please give me a simple example, like process a arrayData responsed from the target.

Thanks.

jxswm
_jxswm_Author
Known Participant
November 5, 2005
Bob,

//--------------------------
It looks like you're trying to get bi-directional BT messages going back and forth. That won't work.
----------------------------
My goal:
Run an Adobe CS2 program by one of the Adobe CS2 programs, eg,
Sender: Indesign CS2,
Target: Photoshop CS2,
I run above code, if the Photoshop CS2 have not launched, I using a While+$.sleep(time)+isRunning function to check, until the Photoshop CS2 launched in 3 minutes, if over 3 minitues, then timeout, kill the progress,
Then, I run the Photoshop CS2 Script by bt.send(), this time the Indesign CS2 is going to run the next line, my key goal is here:
I WANT TO KONOW
If the Photoshop CS2 program running script meetting any Error,---send a ErrorMsg to Indesign, then I process the ErrorMsg in the sender(Indesign CS2);
If the Photoshop CS2 program running script has finninshed the running program,---send a OKMsg to the sender(Indesign CS2), then I run the next line of the main script(Indesign cs2 script, not the Photoshop cs2 script);
If the Photoshop CS2 program running script lastest line and get a result, ----send the result Msg or data or obj to Indesign ,then the Indesign main script using the Result and process the result or data or obj;

One word, build a Mode such as:
Action->Msg->More Action->moreMsg->MoreAction....

jxswm
Known Participant
November 4, 2005
I'm not certain what you're trying to do with the BridgeTalk code there. It looks like you're trying to get bi-directional BT messages going back and forth. That won't work. Please fill me in on exactly what you're trying to do, and I'll help where I can.


Regardless, here's a few pointers.

There are two "BridgeTalks" and they are different.

var bt = new BridgeTalk(); - creates a new instance of a BridgeTalk Message.

There is also a BridgeTalk global object that provides support services for bridgetalk messages.

BridgeTalk.appName, BridgeTalk.launch(), BridgeTalk.onReceive...

BridgeTalk.onReceive is the handler that is called when an app receives a BridgeTalk message. The typical BridgeTalk.onReceive handler in each of the Adobe apps is something like:

BridgeTalk.onReceive = function( iac ) {
return eval( $.level = 0;iac.body );
}

BridgeTalk has two known bugs.

1. Any message that is queued, will not be able to send a result back. The connection between the onResult handler and the original message is broken in the queue. So if you launch an app, you must wait until that app is fully launched before acutally sending a BT message. There is a library function - startTargetApplication() that does this in the foreground (and locks the sending app until the target app is ready to receive messages). I also have some code here that launches a target app as a background process and calls you code to continue once the app is launched. It requires the app to have scheduled tasks imlemented, so it won't work from ID.

2. Each BT message can only send back ONE result. The sendResult() call should never be used. I thought it had been removed from the documentation...

There is no onReceive callback for a bridgetalk MESSAGE. This is an error in the documentation. There is an onReceived callback that it triggered when the target app received the message. Note that the bridgetalk message passed to this callback does not have a body property and really isn't useful. The only use (that I can think of) for an onReceived handler is so that your code will know that the target app has received your message for processing.

If you are looking to send multiple messages back and forth between target and app for a single script - take a look at AdobeLibrary1.jsx - Specifically the BridgeTalkLongProcess object. There's a support opbject, BTLPSupport, that provides some of the code to this class. It shows the SAFE way to modify a BridgeTalk.onReceive handler, and how to be able to send BT messages back and forth in something that would be analogous to a virtual "bridgetalk session".

I hope this helps. Please fill me in the details of exactly what you are trying to accomplish and I'll try to be more specific with whatever support I can provide.

Bob
Adobe WAS Scripting
_jxswm_Author
Known Participant
November 4, 2005
//continue:
//----------------
function runScriptAString(sStr, appName, isBringToFront){
if(!sStr || sStr == ""){return false;}
var bt = new BridgeTalk ();
with(bt){
target = appName;
//timeout = 0;//This Script running elapsed time: "timeout = 90*1000;" means been runned 90s.
if(isBringToFront){BridgeTalk.bringToFront(target);}
body = sStr;
//type = "ExtendScript";//"String";//
//Static onReceive:
//The result of evaluating a script is the result of the last line of the script
/*
BridgeTalk.onReceive = function(bt){
//result = eval(bt.body);
sendResult(eval(bt.body));
return eval(bt.body);
};
//CallBacks:
onReceive = function(origBtObj){
//getReceive(origBtObj);
//alert(eval(origBtObj.body));
return eval(origBtObj.body);
};
//*/
onResult = function(returnBtObj){
//getResult(returnBtObj.body);
result = eval(returnBtObj.body);
alert(result);
};
/*
onError = function(errorBtObj) {//getError(errorBtObj);
var errCode = parseInt (errorBtObj.headers ["Error-Code"]);
throw new Error (errCode, errorBtObj.body);
};
//if(!sendResult(result)){return false;} //How to use the sendResult
//*/
if(!send()){return false;}
}
return true;
}

function load(fURI){
var c = '';
if(!fURI || fURI == ""){ return c;}
var f = new File(fURI);
if(!f){return c;}
f = new File(f.fsName);
with(f){
if(!exists){return c;}
var h = hidden;
if(h){hidden = false;}
if(open("r", "Text", "R*ch")){
c = read(); close();
if(h){hidden = true;}
}else{
if(h){hidden = true;}
return c;
}
}
return c;
}

//==================================