GP SoftwareTwitter
Opus FAQsManualCommandsObjects

Inconsistent results with Dialog.WatchTab

This is inconsistently but fairly regularly reproduceable on my W10 system with DO 12.21.2. I have a test detached dialog using the WatchTab method to monitor tab activate/deactivate events. In the following example the current lister initially contains two tabs - C: and C:\Program Files. I use an inline >go /temp newtab command to create a new tab. The new tab is always created but the dialog sometimes recognises the new tab and sometimes crashes.

Trace output is either (success):

Current lister has changed
Watching 264854 (C:) Program Files
currLister.tabs.count (0) = 2
currLister.tabs.count (1) = 2
Prev = 264854 (C:) Program Files | Curr = 1051344 (C:) Temp
Watching 1051344 (C:) Temp

or (crash):

Current lister has changed
Watching 264854 (C:) Program Files
currLister.tabs.count (0) = 2
currLister.tabs.count (1) = 2
Prev = 264854 (C:) Program Files | Curr = 0 undefined
01/08/20 09:52 Error at line 57, position 2
01/08/20 09:52 Invalid procedure call or argument (0x800a0005)

I can't detect any particular pattern that causes it to work or fail. However, there is a currLister.Update() statement between the two tab count traces and I would expect the second trace to report 3 tabs, at least when it doesn't crash. Maybe a timing issue?

WTTest.dcf (5.1 KB)

var cmd = DOpus.create.command, dlg = DOpus.dlg, msg_obj;
var opus_ver = "12.21";
var me = "WTTest";
var me_ver = me+" - 1st August, 2020 - © AussieBoykie";
var watched = DOpus.Create.Map();
var prevTab, currTab, prevLister, currLister = DOpus.listers.lastactive;
function OnClick(clickData)
	if (!DOpus.version.AtLeast(opus_ver)){
		dlg.request("DOpus version "+opus_ver+" or later is required.","OK","Version Check");
		return false;
	dlg.template = me;
	dlg.window = DOpus.listers.lastactive;
	dlg.detach = true;
	dlg.title = me_ver;
		msg_obj = dlg.getmsg();
		if (msg_obj==false) break;
		if (msg_obj.event=="click"){
			DOpus.output(msg_obj.control+" : "+dlg.control(msg_obj.control).label);
			if (msg_obj.control=="button2") break;
		else if ((msg_obj.event=="tab") && (msg_obj.value=="activate")){
			if (!checkListerChange()) checkTabChange();
	while (msg_obj);
function checkListerChange()
	if (currLister==prevLister) return false; // Lister hasn't changed
	DOpus.output("Current lister has changed");
	watched = DOpus.Create.Map(); // Reset the map of watched tabs
	prevTab = currTab = currLister.activetab; // Reset previous and current tabs
	watchit(currTab); // Watch current tab
	prevLister = currLister // Reset previous lister
	return true;
function checkTabChange()
	DOpus.output("currLister.tabs.count (0) = "+currLister.tabs.count);
	DOpus.output("currLister.tabs.count (1) = "+currLister.tabs.count);
	prevTab = currTab;
	currTab = DOpus.listers.lastactive.activetab;
	if (String(currTab)!=String(prevTab)){ // Deactivate event triggered by prevTab
		DOpus.output("Prev = "+String(prevTab)+" "+prevTab.displayed_label+" | Curr = "+String(currTab)+" "+currTab.displayed_label);
		if (!watched.exists(currTab)) watchit(currTab);
function watchit(someTab)
	DOpus.output("Watching "+someTab+" "+someTab.displayed_label);
	watched(someTab) = someTab.displayed_label;

That shows currTab is null just before you call code which tries to use it.

Yes. The issue is that sometimes it works and sometimes it fails. Plus, when it works the total tab count after a lister update is one less than it should be.

Possibly the new tab isn't set up yet the first time you ask. Check for null, maybe delay for a short time, and ask again.

Based on many tests it appears that if adding one new tab works adding further new tabs always succeeds. I understand your suggestion and had already planned to try checking for failure and retrying after a delay.