OnStartup event is incorrect

OnStartup event will not be run until DOpus is ready, other events will occur earlier than this event. In DOpus12 it is at startup, earlier than other events.

How it works hasn't changed since Opus 12.

It's called once Opus is up and running. There has never been any guarantee that it will be called before any other events. (Indeed, your script's OnInit will be called first.) The only guarantee is that it's called when Opus starts.

But it did change.

Opus 12
image

Opus 13
image

Is there any object that knows when DOpus is ready? Then I don't need this code:

// Called when Directory Opus starts up
function OnStartup(startupData)
{
    DOpus.Vars.Set("non-exec", 0);   // Tell other events not to execute at startup
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
	DOpus.Delay(15000);
	DOpus.Vars.Delete("non-exec");
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
}
Full script
// Go to Previous Location
// (c) 2023 Ken

// This is a script for Directory Opus.
// See https://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.



// Called by Directory Opus to initialize the script
function OnInit(initData)
{
	initData.name = "Go to Previous Location & Restore selection";
	initData.version = "v1.2.1(2023.10.20)";
	initData.copyright = "(c) 2023 Ken";
//	initData.url = "https://resource.dopus.com/c/buttons-scripts/16";
	initData.desc = "Jump to the previous location & Restore selection.";
	initData.default_enable = true;
	initData.min_version = "12.0";


}

// Called to add commands to Opus
function OnAddCommands(addCmdData)
{
	var cmd = addCmdData.AddCommand();
	cmd.name = "GotoPre";
	cmd.method = "OnGotoPre";
	cmd.desc = "";
	cmd.label = "GotoPre";
	cmd.template = "";
	cmd.hide = false;
	cmd.icon = "script";
}

// Called when Directory Opus starts up
function OnStartup(startupData)
{
    DOpus.Vars.Set("non-exec", 0);   // Tell other events not to execute at startup
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
	DOpus.Delay(15000);
	DOpus.Vars.Delete("non-exec");
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
}

// Called when a tab is activated
function OnActivateTab(activateTabData)
{
	if (DOpus.Vars.Exists("non-exec")) return
	DOpus.Output(1)
    var tab = activateTabData.oldtab;
	var Lister = tab.Lister;
    Lister.Vars.Set("preTab", tab);
	Lister.Vars.Set("prePath", tab.path);
	
	if (tab.all.count)
	    Lister.Vars.Set("preFocusItem", tab.GetFocusItem);
	else
	    Lister.Vars.Set("preFocusItem", false);
}

// Called before a new folder is read in a tab
function OnBeforeFolderChange(beforeFolderChange)
{
	if (DOpus.Vars.Exists("non-exec")) return
	DOpus.Output(2)
    var tab = beforeFolderChange.tab;
	var Lister = tab.Lister;
    Lister.Vars.Set("prePath", tab.path);
	Lister.Vars.Set("selected", tab.selected);
	if (tab.format && tab.all.count)
	    Lister.Vars.Set("preFocusItem", tab.GetFocusItem);
	else
	    Lister.Vars.Set("preFocusItem", false);
	
	if (Lister.Vars.Exists("preTab"))
	    Lister.Vars.Delete("preTab");
}

// Called after a new folder is read in a tab
function OnAfterFolderChange(afterFolderChangeData)
{
	if (DOpus.Vars.Exists("non-exec")) return
	DOpus.Output(3)
	var tab = afterFolderChangeData.tab;
	var Lister = tab.Lister;
	// Save subfolder selection
	var action = afterFolderChangeData.action;
    if (action != "forward" && action != "dblclk" && !Lister.Vars.Exists("bcbNav")) {   //if (action != "forward" && action != "dblclk" && action != "normal") {
		var subPath = Lister.Vars.Get("prePath") + "";
		DOpus.Output(4)
		if (action == "normal") {
			var sourcePath = tab.path + "";
			var match = subPath.replace(sourcePath, "");
			if (match == subPath) return
		}
		Lister.Vars.Set("subPath", subPath);
		var subSel = Lister.Vars.Get("selected");
		Lister.Vars.Set("subSel", subSel);
		var subFoc = Lister.Vars.Get("preFocusItem");
		Lister.Vars.Set("subFoc", subFoc);
		Lister.Vars.Set("bcbNav", "")
		if (action != "refresh") return
	}
	// Restore selection
	if (action != "parent") {
		if (Lister.Vars.Exists("subPath")) {
			var subPath = Lister.Vars.Get("subPath");
			if (tab.path + "" == subPath) {
			    var subSel = Lister.Vars.Get("subSel");
			    var subFoc = Lister.Vars.Get("subFoc");
				var cmd = DOpus.Create.Command;
				cmd.ClearFiles();
			    var focItemSel = 0, eItem;
	            if (subSel.count) {
					for (var e = new Enumerator(subSel); !e.atEnd(); e.moveNext())
					{
						eItem = e.item();
						cmd.AddFile(eItem);
						if (eItem + "" == subFoc) focItemSel = 1 
					}
	            }
			    if (cmd.filecount)
			        cmd.RunCommand('Select FROMSCRIPT');
			
			    if (subFoc) {
			        cmd.ClearFiles();
			        cmd.AddFile(subFoc);
			        cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
				    if (!focItemSel)
				        cmd.RunCommand('Select NONE');
			    }
		    }
			Lister.Vars.Delete("bcbNav")
		}
	}
}

// Implement the GotoPre command
function OnGotoPre(scriptCmdData)
{
	var tab = scriptCmdData.func.sourcetab;
	var Lister = tab.Lister;
	var cmd = scriptCmdData.func.command;
	cmd.ClearFiles();
	
	if (!Lister.Vars.Exists("preTab")) {
	    if (Lister.Vars.Exists("prePath")) {
			var prePath = Lister.Vars.Get('prePath');
			var selected = Lister.Vars.Get("selected");
			var preFocusItem = Lister.Vars.Get("preFocusItem");
			cmd.RunCommand('Go "' + prePath + '"');
			var focItemSel = 0, eItem;
	        if (selected.count) {
		        //cmd.SetFiles(selected);
		        for (var e = new Enumerator(selected); !e.atEnd(); e.moveNext())
		        {
					eItem = e.item();
		            cmd.AddFile(eItem);
					if (eItem + "" == preFocusItem) focItemSel = 1 
		        }
	        }
			if (cmd.filecount)
			    cmd.RunCommand('Select FROMSCRIPT');
			
			if (preFocusItem) {
			    cmd.ClearFiles();
			    cmd.AddFile(preFocusItem);
			    cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
				if (!focItemSel)
				    cmd.RunCommand('Select NONE');
			}
		}
		return
	}
	
	var preTab = Number(Lister.Vars.Get("preTab"));
	var tabs = tab.lister.tabs;
	for (var i = 0; i < tabs.count; i++)
	{
	    if (tabs(i) == preTab) {
            //cmd.RunCommand('Go TABSELECT=' + i);
			cmd.RunCommand("Go TABSELECT=$" + preTab);
			return
		}
	}
	cmd.RunCommand('Go TABUNDOCLOSE');
}

It hasn't changed. If listers are opening at startup, they run on their own threads and may (or may not) run their events before the OnStartup event runs.

Scripts need to deal with that if the order is important to them. For example, you could call a method in response to all of the events, and make a note of whether it's already been called; the OnStartup event may not even be needed in that case.

It's complicated for me, I removed the redundant code, the variables will be overwritten anyway, no need to do more.

May I suggest this simple change?

function OnStartup(startupData)
{
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
	DOpus.Delay(15000); //what is this delay for?
	DOpus.Vars.Delete("non-exec");
	DOpus.Output(DOpus.Vars.Exists("non-exec") + "------")
}
function OnShutdown(ShutdownData)
{
	DOpus.Vars.Set("non-exec", 0);   // Tell other events not to execute at startup
}

DOpus does not save the variable when it is closed, but I can create a file in place of the variable and delete the file after startup, thanks!

@WKen from a quick test, you could also skip the OnShutdown event completely and change only this:

function OnStartup(startupData)
{
	DOpus.Output(Script.Vars.Exists("non-exec") + "------")
	Script.Vars.Set("non-exec", 0);
	DOpus.Output(Script.Vars.Exists("non-exec") + "------")
}

And in your other functions, change this line:
if (DOpus.Vars.Exists("non-exec")) return
For this one:
if (!Script.Vars.Exists("non-exec")) return;

That way, the variable is lost when DOpus closes completely, and is only set again when the OnStartup event is executed.

I haven't modified the script yet. Set a variable to tell other events that Opus is ready, simple solution, thanks.

What are you trying to do with the script? Presumably running something before something else causes a problem, but what are those two things?

I don't need the script to run when Opus is not ready yet (when starting and restoring tabs).
A variable is created when Opus is ready and the other three events in the script run based on this variable.

Full script
// Go to Previous Location
// (c) 2023 Ken

// This is a script for Directory Opus.
// See https://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.



// Called by Directory Opus to initialize the script
function OnInit(initData)
{
	initData.name = "Go to Previous Location & Restore selection";
	initData.version = "v1.2.1(2023.10.20)";
	initData.copyright = "(c) 2023 Ken";
//	initData.url = "https://resource.dopus.com/c/buttons-scripts/16";
	initData.desc = "Jump to the previous location & Restore selection.";
	initData.default_enable = true;
	initData.min_version = "12.0";


}

// Called to add commands to Opus
function OnAddCommands(addCmdData)
{
	var cmd = addCmdData.AddCommand();
	cmd.name = "GotoPre";
	cmd.method = "OnGotoPre";
	cmd.desc = "";
	cmd.label = "GotoPre";
	cmd.template = "";
	cmd.hide = false;
	cmd.icon = "script";
}

// Called when Directory Opus starts up
function OnStartup(startupData)
{
	Script.Vars.Set("exec", 0);
}

// Called when a tab is activated
function OnActivateTab(activateTabData)
{
	if (!Script.Vars.Exists("exec")) return;
    var tab = activateTabData.oldtab;
	var Lister = tab.Lister;
    Lister.Vars.Set("preTab", tab);
	Lister.Vars.Set("prePath", tab.path);
	
	if (tab.all.count)
	    Lister.Vars.Set("preFocusItem", tab.GetFocusItem);
	else
	    Lister.Vars.Set("preFocusItem", false);
}

// Called before a new folder is read in a tab
function OnBeforeFolderChange(beforeFolderChange)
{
	if (!Script.Vars.Exists("exec")) return;
    var tab = beforeFolderChange.tab;
	var Lister = tab.Lister;
    Lister.Vars.Set("prePath", tab.path);
	Lister.Vars.Set("selected", tab.selected);
	if (tab.format && tab.all.count)
	    Lister.Vars.Set("preFocusItem", tab.GetFocusItem);
	else
	    Lister.Vars.Set("preFocusItem", false);
	
	if (Lister.Vars.Exists("preTab"))
	    Lister.Vars.Delete("preTab");
}

// Called after a new folder is read in a tab
function OnAfterFolderChange(afterFolderChangeData)
{
	if (!Script.Vars.Exists("exec")) return;
	var tab = afterFolderChangeData.tab;
	var sourcePath = tab.path + "";
	var Lister = tab.Lister;
	// Save subfolder selection
	var action = afterFolderChangeData.action;
    if (action != "forward" && action != "dblclk" && !Lister.Vars.Exists("bcbNav")) {   //if (action != "forward" && action != "dblclk" && action != "normal") {
		var subPath = Lister.Vars.Get("prePath") + "";
		if (action == "normal") {
			var match = subPath.replace(sourcePath, "");
			if (match == subPath) return
		}
		Lister.Vars.Set("subPath", subPath);
		var subSel = Lister.Vars.Get("selected");
		Lister.Vars.Set("subSel", subSel);
		var subFoc = Lister.Vars.Get("preFocusItem");
		Lister.Vars.Set("subFoc", subFoc);
		Lister.Vars.Set("bcbNav", "")
		if (action != "refresh") return
	}
	// Restore selection
	if (action != "parent") {
		if (Lister.Vars.Exists("subPath")) {
			var subPath = Lister.Vars.Get("subPath");
			if (sourcePath == subPath) {
			    var subSel = Lister.Vars.Get("subSel");
			    var subFoc = Lister.Vars.Get("subFoc");
				var cmd = DOpus.Create.Command;
				cmd.ClearFiles();
			    var focItemSel = 0, eItem;
	            if (subSel.count) {
					for (var e = new Enumerator(subSel); !e.atEnd(); e.moveNext())
					{
						eItem = e.item();
						cmd.AddFile(eItem);
						if (eItem + "" == subFoc) focItemSel = 1 
					}
	            }
			    if (cmd.filecount)
			        cmd.RunCommand('Select FROMSCRIPT');
			
			    if (subFoc) {
			        cmd.ClearFiles();
			        cmd.AddFile(subFoc);
			        cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
				    if (!focItemSel)
				        cmd.RunCommand('Select NONE');
			    }
		    }
			Lister.Vars.Delete("bcbNav")
		}
	}
}

// Implement the GotoPre command
function OnGotoPre(scriptCmdData)
{
	var tab = scriptCmdData.func.sourcetab;
	var Lister = tab.Lister;
	var cmd = scriptCmdData.func.command;
	cmd.ClearFiles();
	
	if (!Lister.Vars.Exists("preTab")) {
	    if (Lister.Vars.Exists("prePath")) {
			var prePath = Lister.Vars.Get('prePath');
			var selected = Lister.Vars.Get("selected");
			var preFocusItem = Lister.Vars.Get("preFocusItem");
			cmd.RunCommand('Go "' + prePath + '"');
			var focItemSel = 0, eItem;
	        if (selected.count) {
		        //cmd.SetFiles(selected);
		        for (var e = new Enumerator(selected); !e.atEnd(); e.moveNext())
		        {
					eItem = e.item();
		            cmd.AddFile(eItem);
					if (eItem + "" == preFocusItem) focItemSel = 1 
		        }
	        }
			if (cmd.filecount)
			    cmd.RunCommand('Select FROMSCRIPT');
			
			if (preFocusItem) {
			    cmd.ClearFiles();
			    cmd.AddFile(preFocusItem);
			    cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
				if (!focItemSel)
				    cmd.RunCommand('Select NONE');
			}
		}
		return
	}
	
	var preTab = Number(Lister.Vars.Get("preTab"));
	var tabs = tab.lister.tabs;
	for (var i = 0; i < tabs.count; i++)
	{
	    if (tabs(i) == preTab) {
            //cmd.RunCommand('Go TABSELECT=' + i);
			cmd.RunCommand("Go TABSELECT=$" + preTab);
			return
		}
	}
	cmd.RunCommand('Go TABUNDOCLOSE');
}