Multi-Experiment Process, ask if I want to save change to experiment "Untitled" all the time.

Hello,
I have done a batch function based on the explanation to sequentially open experiment file find in: Choose File->Example Experiments->Programming->Multi-Experiment Process.

I manage to make a nice code using this example. Everything works well when I follow the tutorial but when I want to implement my own function I have a problem. It comes from a Hook function in my experiment:

static Function IgorStartOrNewHook(igorApplicationNameStr)
String igorApplicationNameStr

...

End

If I use this function, igor will ask before every new experiment:
Do you want to save change to experiment "Untitled"?

somebody have any idea why? Thanks again

Chris
Post the entire function, please.

Your function may be setting globals you don't expect (like V_Flag).
You can use the ExperimentModified operation to tell Igor you don't consider the current experiment in need of saving.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
JimProuty wrote: Post the entire function, please.

Your function may be setting globals you don't expect (like V_Flag).
You can use the ExperimentModified operation to tell Igor you don't consider the current experiment in need of saving.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.


Hello Jim,
Thank you for your reply, I already try ExperimentModified without success but maybe I called it at the wrong point, so I will try other combinations. The whole function is bellow, it is the function taken from Igor: Choose File->Example Experiments->Programming->Multi-Experiment Process. The modification is only a simple callback. It mimics the real modification that I have in my code but it may be easier for you to understand this code provided directly by Igor developers.

#pragma rtGlobals=1		// Use modern global access method.

#include "IgorTools"

// ABOUT MULTI-EXPERIMENT PROCESS

// This procedure file demonstrates a process that runs across multiple experiments.

// The challenge was to open a series of packed experiment files (with ".pxp" extensions) in a particular folder.
// Each experiment file contained waves named wave_lif1 and wave_lif2. We were asked to graph these waves
// and then export the graph as a PNG file and then to repeat the process for the next experiment.

// This file contains the procedures that cycle through experiments and execute a function for each experiment.

// When a file is opened, Igor calls the AfterFileOpenHook hook in this file. The hook checks to see if
// the file being opened is a packed experiment file and if it contains the expected waves. If so,
// the hook function calls a subroutine that graphs the waves and exports the graph as a PNG file.
// It then opens the next experiment file and repeats the process.

// This procedure file uses Igor's LoadPackagePreferences and SavePackagePreferences to store
// information used between invocations of AfterFileOpenHook. It uses Execute/P to post commands
// to Igor's operation queue for opening the next experiment.

// TO TRY THE DEMO

// Choose File->Example Experiments->Programming->Multi-Experiment Process to open
// the demo experiment and follow the instructions therein.

Menu "Macros"
	"Start Multi-Experiment Process", /Q, StartMultiExperimentProcess()
End

// NOTE: If you use these procedures for your own purposes, change the package name
// to a distinctive name so that you don't clash with other people's preferences.
static StrConstant kPackageName = "Multi-experiment Process"
static StrConstant kPreferencesFileName = "ProcessPrefs.bin"
static Constant kPrefsRecordID = 0		// The recordID is a unique number identifying a record within the preference file.
										// In this example we store only one record in the preference file.

// The structure stored in preferences to keep track of what experiment to load next.
// If you add, remove or change fields you must delete your old prefs file. See the help
// topic "Saving Package Preferences" for details.
Structure MultiExperimentProcessPrefs
	uint32 version						// Prefs version
	uint32 processRunning				// Truth that we are running the mult-experiment process
	char folderPath[256]				// Path to folder containing experiments
	uint32 index						// Zero-based index of next experiment in folder to load
	uint32 experimentsProcessed
	uint32 experimentsSkipped	
EndStructure

// In version 101 of the prefs structure we increased folderPath from 100 to 256 bytes
static Constant kPrefsVersionNumber = 101

//	Loads preferences into our structure.
static Function LoadPackagePrefs(prefs)
	STRUCT MultiExperimentProcessPrefs &prefs

	Variable currentPrefsVersion = kPrefsVersionNumber

	// This loads preferences from disk if they exist on disk.
	LoadPackagePreferences /MIS=1 kPackageName, kPreferencesFileName, kPrefsRecordID, prefs
	// Printf "%d byte loaded\r", V_bytesRead

	// If error or prefs not found or not valid, initialize them.
	if (V_flag!=0 || V_bytesRead==0 || prefs.version!=currentPrefsVersion)
		prefs.version = currentPrefsVersion

		prefs.processRunning = 0
		prefs.folderPath = ""
		prefs.index = 0
		prefs.experimentsProcessed = 0
		prefs.experimentsSkipped = 0

		SavePackagePrefs(prefs)		// Create default prefs file.
	endif
End

//	Saves our structure to preferences.
static Function SavePackagePrefs(prefs)
	STRUCT MultiExperimentProcessPrefs &prefs

	SavePackagePreferences kPackageName, kPreferencesFileName, kPrefsRecordID, prefs
End

//	This is the routine that you would need to change to use this procedure file for your own purposes.
//	See comments about labeled "TO USE FOR YOUR OWN PURPOSES".
static Function ProcessCurrentExperiment(prefs)
	STRUCT MultiExperimentProcessPrefs &prefs


	String folderPath = prefs.folderPath
	
	String experimentName = IgorInfo(1)
	String tmp = RemoveEnding(experimentName, ".pxp")
	String fullFilePath = folderPath + tmp + ".png"

	Display wave_lif1 wave_lif2
	ModifyGraph rgb(wave_lif1)=(0,0,65280),rgb(wave_lif2)=(0,52224,0)
	ModifyGraph mirror=2
	
	// Add annotation
	String text
	sprintf text, "Experiment %d, \"%s\"", prefs.index, experimentName
	TextBox/C/N=text0/M/H=36/A=LT/X=5.00/Y=0.00 text

	SavePICT/E=-5/RES=600/I/W=(0,0,4,3)/O as fullFilePath
End

static Function IsAppropriateExperiment()
	if (WaveExists(wave_lif1) && WaveExists(wave_lif2))
		print "We have found an experiment"
		return 1	// This looks like the kind of function we want to process.
	else
		print "Not appropriate experiment"
	
	endif
	
	return 0		// This does not appear to be the kind of experiment we want to process.
End

// Returns full path to the next experiment file to be loaded or "" if we are finished.
static Function/S FindNextExperiment(prefs)
	STRUCT MultiExperimentProcessPrefs &prefs
	
	String folderPath = prefs.folderPath
	NewPath/O/Q MultiExperimentPath, folderPath
	
	String nextExpName = IndexedFile(MultiExperimentPath, prefs.index, ".pxp")
	
	if (strlen(nextExpName) == 0)
		return ""
	endif
	
	String fullPath = prefs.folderPath + nextExpName
	return fullPath
End

// Posts commands to Igor's operation queue to close the current experiment and open the next one.
// Igor executes operation queue commands when it is idling - that is, when it is not running a
// function or operation.
static Function PostLoadNextExperiment(nextExperimentFullPath)
	String nextExperimentFullPath
	
	Execute/P "NEWEXPERIMENT "				// Post command to close this experiment.
	
	// Post command to open next experiment.
	String cmd
	sprintf cmd "Execute/P \"LOADFILE %s\"", nextExperimentFullPath
	Execute cmd
End


static Function IgorStartOrNewHook(igorApplicationNameStr)  //Christophe Nell: This is the new hook function that I need for my own experiment
	String igorApplicationNameStr
	
	print "IgorStartOrNewHook" //With a message or any other action, it always asks me 'Do you want to save "untitled" experiment?'
End
// This is the hook function that Igor calls whenever a file is opened. We use it to
// detect the opening of an experiment and to call our ProcessCurrentExperiment function.
static Function AfterFileOpenHook(refNum,file,pathName,type,creator,kind)

	Variable refNum,kind
	String file,pathName,type,creator

	
	STRUCT MultiExperimentProcessPrefs prefs
	
	LoadPackagePrefs(prefs)						// Load our prefs into our structure
	if (prefs.processRunning == 0)
		return 0									// Process not yet started.
	endif
	
	// Check file type
	if (CmpStr(type,"IGsU") != 0)
		return 0		// This is not a packed experiment file
	endif
	
	// Check for expected waves
	if (IsAppropriateExperiment())
		ProcessCurrentExperiment(prefs)
		prefs.index += 1							// Index tracks next experiment to be processed.
		prefs.experimentsProcessed += 1
	else
		DoAlert 0, "This experiment is not suitable. Skipping to next experiment."
		prefs.experimentsSkipped += 1
	endif
	
	// See if there are more experiments to process.
	String nextExperimentFullPath = FindNextExperiment(prefs)
	if (strlen(nextExperimentFullPath) == 0)
		// Process is finished
		prefs.processRunning = 0		// Flag process is finished.
		Execute/P "NEWEXPERIMENT "							// Post command to close this experiment.
		String message
		sprintf message, "Multi-experiment process is finished. %d experiments processed, %d skipped.", prefs.experimentsProcessed, prefs.experimentsSkipped
		DoAlert 0, message
	else
		// Load the next experiment in the designated folder, if any.
		PostLoadNextExperiment(nextExperimentFullPath)		// Post operation queue commands to load next experiment
	endif

	SavePackagePrefs(prefs)
	
	return 0	// Tell Igor to handle file in default fashion.
End

static Function PossiblySaveCurrentExperiment()
	DoIgorMenu/C "File", "Save Experiment"		// Check if current experiment can be saved.
	if (V_flag == 0)								// Experiment is not modified.
		return 0
	endif

	DoAlert 2, "Save current experiment before starting?"
	if (V_flag == 1)			// Yes
		SaveExperiment
	endif
	if (V_flag == 3)			// Cancel
		return -1
	endif

	return 0
End

// Allow user to choose the folder containing the experiment files and start the process.
Function StartMultiExperimentProcess()
print "StartMultiExperment"
	STRUCT MultiExperimentProcessPrefs prefs

	// First save current experiment if necessary.
	if (PossiblySaveCurrentExperiment())
		return -1		// User cancelled
	endif

	// Ask user to choose the folder containing experiment files to be processed.
	String message = "Choose folder containing experiment files"
	NewPath/O/Q/M=message MultiExperimentPath			// Display dialog asking for folder
	if (V_flag != 0)
		return -1											// User canceled from New Path dialog
	endif
	PathInfo MultiExperimentPath

	LoadPackagePrefs(prefs)								// This initializes prefs if they don't yet exist

	prefs.processRunning = 1								// Flag process is started.
	prefs.folderPath = S_path								// S_path is set by PathInfo
	prefs.index = 0
	prefs.experimentsProcessed = 0
	prefs.experimentsSkipped = 0

	// Start the process off by loading the first experiment.
	String nextExperimentFullPath = FindNextExperiment(prefs)
	print "PostLoadNextExp"
	PostLoadNextExperiment(nextExperimentFullPath)		// Start the process off

	SavePackagePrefs(prefs)
	
	return 0
End
Here is another version of my function, much shorter:

Function CN_BatchSelectedExperiment()

	getfilefolderinfo/D
	newpath/O cgms S_path	
	String dirList = IndexedDir(cgms, -1, 0), cmd
	Variable numDirs = ItemsInList(dirList)

	// Store directory list in a free text wave.
	// The free wave is automatically killed when the function returns.
	Make/N=(numDirs)/T/FREE dirs = StringFromList(p, dirList)

	Variable i
	for( i=0; i<numDirs; i+=1)

		NewPath/O myPath S_path + dirs[i]
	
		String ExperimentFile = IndexedFile(myPath,-1,".pxp")	
		if(cmpstr(ExperimentFile, "") == 1)
		string directory = S_path + dirs[i] +  ":" + StringFromList(0, ExperimentFile, ";") 
		Execute/P "NEWEXPERIMENT "
		sprintf cmd "Execute/P \"LOADFILE %s\"", directory
		Execute cmd
		Execute/P "CN_testExperiment()"

		endif
		
	endfor

End

Function CN_testExperiment()

		String experimentName = IgorInfo(1)
		PathInfo/s home
		String tmp = RemoveEnding(S_path, ".pxp")
		String fullFilePath = tmp + ".png"
		Display wave_lif1 wave_lif2
		ModifyGraph rgb(wave_lif1)=(0,0,65280),rgb(wave_lif2)=(0,52224,0)
		ModifyGraph mirror=2
	
		// Add annotation
		String text
		sprintf text, "Experiment \"%s\"", experimentName
		TextBox/C/N=text0/M/H=36/A=LT/X=5.00/Y=0.00 text
		SavePICT/E=-5/RES=600/I/W=(0,0,4,3)/O as fullFilePath
End

and if I had the following hook function, the batch function ask me all the time if I want to save the untitled experiment:

static Function IgorStartOrNewHook(igorApplicationNameStr)
	String igorApplicationNameStr
	
	Newdatafolder/o root:packages
	Newdatafolder/o/s root:packages:PatchModeOli
	Make/t/o/n=(4,3) GainDAC
	Make/t/o/n=(4,3) GainADC0
	Make/t/o/n=(4,3) GainADC1
        ...
End

Hello,
I have solved my problem by adding
"ExperimentModified 0"
at the end of the hook function that was responsible of my problem! Thanks a lot for your reply, best

Christophe