Bootstrapping a Package Loader
jtigor
This works fine within an Igor session but does not work if Igor is shut down and an old experiment opened again. I thought that I had demonstrated to myself that this method of detecting whether the package was loaded or not worked when I devised it several months ago. The probem, as far as I can tell, is that the global symbol is not saved with the experiment. Is this the expected Igor behavior? Did I miss something in reading about symbols?
If the global symbol idea is not viable, what alternative methods are there? At the present time, the package does not require a package data folder and I wanted to avoid creating one just to remember the package load/unload state. This certainly could be done. A dummy procedure could be loaded as part of the package and that could be searched for to determine whether or not the package was loaded. Is it possible to determine whether user defined menus exist? I see there are several functions for working with built in menus, but haven't been able to find anything related to user defined menus. This might server as a means to detecte the package state. Any ideas or opinions?
System is Win7, Igor V6.22A
Thanks,
Jeff
#pragma rtGlobals=1 // Use modern global access method.
#pragma IndependentModule= AFM_PackageLoader
#ifndef AFM_PackageLoader
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Load AFM Package", /Q, LoadAFMPackage()
help = {"Loads the set of procedures related to Atomic Force Microscopy."}
End
End
#else
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Unload AFM Package", /Q, UnloadAFMPackage()
help = {"Removes the set of procedures related to Atomic Force Microscopy."}
End
End
#endif
//package loader
//"SetIgorOption poundDefine=AFM_PackageLoader" defines a global symbol
//that the force curve analysis package uses to add a "remove package" menu item
Function LoadAFMPackage()
Execute/P/Q/Z "INSERTINCLUDE \"AFM_ForceCurveAnalysis\""
Execute/P/Q/Z "INSERTINCLUDE \"AFM_MultiFileLoader\""
Execute "SetIgorOption poundDefine=AFM_PackageLoader"
Execute/P/Q/Z "COMPILEPROCEDURES "
End
//package unloader
//"SetIgorOption poundunDefine=AFM_PackageLoader" clears a global symbol
//that the force curve analysis package uses to add a remove package menu item
Function UnloadAFMPackage()
Execute/P/Q/Z "DELETEINCLUDE \"AFM_ForceCurveAnalysis\""
Execute/P/Q/Z "DELETEINCLUDE \"AFM_MultiFileLoader\""
Execute "SetIgorOption poundunDefine=AFM_PackageLoader"
Execute/P/Q/Z "COMPILEPROCEDURES "
End
#pragma IndependentModule= AFM_PackageLoader
#ifndef AFM_PackageLoader
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Load AFM Package", /Q, LoadAFMPackage()
help = {"Loads the set of procedures related to Atomic Force Microscopy."}
End
End
#else
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Unload AFM Package", /Q, UnloadAFMPackage()
help = {"Removes the set of procedures related to Atomic Force Microscopy."}
End
End
#endif
//package loader
//"SetIgorOption poundDefine=AFM_PackageLoader" defines a global symbol
//that the force curve analysis package uses to add a "remove package" menu item
Function LoadAFMPackage()
Execute/P/Q/Z "INSERTINCLUDE \"AFM_ForceCurveAnalysis\""
Execute/P/Q/Z "INSERTINCLUDE \"AFM_MultiFileLoader\""
Execute "SetIgorOption poundDefine=AFM_PackageLoader"
Execute/P/Q/Z "COMPILEPROCEDURES "
End
//package unloader
//"SetIgorOption poundunDefine=AFM_PackageLoader" clears a global symbol
//that the force curve analysis package uses to add a remove package menu item
Function UnloadAFMPackage()
Execute/P/Q/Z "DELETEINCLUDE \"AFM_ForceCurveAnalysis\""
Execute/P/Q/Z "DELETEINCLUDE \"AFM_MultiFileLoader\""
Execute "SetIgorOption poundunDefine=AFM_PackageLoader"
Execute/P/Q/Z "COMPILEPROCEDURES "
End
http://www.igorexchange.com/project/PackageTools
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
May 3, 2012 at 11:47 am - Permalink
You might be able to use Exists. Here is an example that tests if a particular function in an independent module exists:
String name = "WM_GrfBrowser#GetGrfBrowserGlobals"
Print Exists(name) // 6 means "function"
End
Or using a more modern function:
String functionName = "WM_GrfBrowser#GetGrfBrowserGlobals"
String info = FunctionInfo(functionName)
if (strlen(info) == 0)
Print "Function not found"
else
Print info
endif
End
May 3, 2012 at 12:09 pm - Permalink
Howard -- Will your method work in a conditional compilation framework? As in
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Load AFM Package", /Q, LoadAFMPackage()
help = {"Loads the set of procedures related to Atomic Force Microscopy."}
End
End
#else
Menu "jtgSpectroscopy"
SubMenu "Packages..."
"Unload AFM Package", /Q, UnloadAFMPackage()
help = {"Removes the set of procedures related to Atomic Force Microscopy."}
End
End
#endif
So far my testing suggests not, but today IgorLevel(jtigor) < 0 evaluates as true.
May 3, 2012 at 01:51 pm - Permalink
I think such compile conditionals will not work for what you want to do because they may or may not be tested when an experiment is re-loaded. I went 'round and 'round with these same issues for my developments on PackageTools. In the end, I used globals and the "AfterCompileHook" function.
I'd be glad to talk more off-line about whether PackageTools could work for you.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
May 3, 2012 at 02:34 pm - Permalink
I'm not sure. But you need to know some things about FunctionInfo. See the comments in the IsJTGSpectroscopyPackageLoaded function below for details. You can try it using the IsJTGSpectroscopyPackageLoaded function.
However, it can be done without conditional compilation. Here is an example that you can paste into the procedure window of a new experiment and try. It uses the GraphBrowser package as a guinea pig.
NOTE: To try this you must first manually unload the GraphBrowser independent module as follows:
1. SetIgorOption IndependentModuleDev=1
2. Manually close GraphBrowser.ipf via the Windows->Procedure Windows menu.
You can now try it both with IndependentModuleDev=0 and IndependentModuleDev=1.
// is loaded or not. It uses the GraphBrowser module as a guinea pig.
// NOTE: To use this test you must first manually kill the GraphBrowser procedure file.
Function IsJTGSpectroscopyPackageLoaded()
// If a runtime error has occurred, we can't procede because the code below
// requires clearing the runtime error and we don't want to clear an error created
// by other code.
Variable err = GetRTError(0)
if (err != 0)
return 0 // This may be incorrect
endif
// Use "YourModuleName#YourFunctionName".
String functionName = "WM_GrfBrowser#GetGrfBrowserGlobals"
String info = FunctionInfo(functionName)
// FunctionInfo throws an error if the function does not exist. We don't want that so
// here we suppress the error from FunctionInfo if the named function does not exist.
err = GetRTError(1)
if (err != 0)
return 0 // Module not loaded
endif
// Print info // For debugging only
// FunctionInfo returns "Procedures Not Compiled" if the independent module is not loaded, even if procedures are compiled.
// If the independent module IS loaded, it returns a long string.
if (strlen(info) > 100)
return 1
endif
return 0
End
Function/S GetJTGLoadOrUnloadMenuItem()
String menuItem
if (IsJTGSpectroscopyPackageLoaded())
menuItem = "Unload JTG Spectroscopy"
else
menuItem = "Load JTG Spectroscopy"
endif
return menuItem
End
Function LoadOrUnloadAFMPackage()
// This is for a main file in Igor Procedures. For a main file in User Procedures, remove ":Igor Procedures:".
String mainPackageFile = "\":Igor Procedures:GraphBrowser\""
// String mainPackageFile = "\"MyMainPackageFile\"" // If file were in User Procedures
if (IsJTGSpectroscopyPackageLoaded())
Execute /P /Q "DELETEINCLUDE "+mainPackageFile; Execute/P/Q/Z "COMPILEPROCEDURES "
Printf "The package %s was unloaded\r", mainPackageFile
else
Execute /P /Q "INSERTINCLUDE "+mainPackageFile; Execute/P/Q/Z "COMPILEPROCEDURES "
Printf "The package %s was loaded\r", mainPackageFile
endif
End
Menu "jtgSpectroscopy", dynamic
SubMenu "Packages..."
GetJTGLoadOrUnloadMenuItem(), /Q, LoadOrUnloadAFMPackage()
help = {"Loads or unloads the set of procedures related to Atomic Force Microscopy."}
End
End
May 3, 2012 at 05:13 pm - Permalink
Is the problem that you found with IndependentModuleList that module names aren't purged from the list after they are unloaded? That has beem my finding as I continue to work on this. This is probably not the intended behavior?
JJ -- Thanks for the offer. I'll keep it in mind, but I am looking for a stand-alone solution that doesn't depend on another procedure.
Jeff
May 4, 2012 at 12:59 pm - Permalink
Yes, that is what I found and no, it is not the intended behavior.
It should be fixed in the next nightly build. Look for a build dated 2012-05-05 which should be available Saturday morning, May 5, 2012.
With that version or later, this cleaner code should work:
// is loaded or not. It uses the GraphBrowser module as a guinea pig.
// NOTE: To use this test you must first manually kill the GraphBrowser procedure file.
Function IsJTGSpectroscopyPackageLoaded()
// This requires Igor Pro 6.23B04 from 2012-05-05 or later
String moduleName = "WM_GrfBrowser" // Your module name here
String moduleList = IndependentModuleList(";")
Variable whichItem = WhichListItem(moduleName, moduleList)
if (whichItem < 0)
return 0 // Module is not loaded
endif
return 1 // Module is loaded
End
Function/S GetJTGLoadOrUnloadMenuItem()
String menuItem
if (IsJTGSpectroscopyPackageLoaded())
menuItem = "Unload JTG Spectroscopy"
else
menuItem = "Load JTG Spectroscopy"
endif
return menuItem
End
Function LoadOrUnloadAFMPackage()
// This is for a main file in Igor Procedures. For a main file in User Procedures, remove ":Igor Procedures:".
String mainPackageFile = "\":Igor Procedures:GraphBrowser\""
// String mainPackageFile = "\"MyMainPackageFile\"" // If file were in User Procedures
if (IsJTGSpectroscopyPackageLoaded())
Execute /P /Q "DELETEINCLUDE "+mainPackageFile; Execute/P/Q/Z "COMPILEPROCEDURES "
Printf "The package %s was unloaded\r", mainPackageFile
else
Execute /P /Q "INSERTINCLUDE "+mainPackageFile; Execute/P/Q/Z "COMPILEPROCEDURES "
Printf "The package %s was loaded\r", mainPackageFile
endif
End
Menu "jtgSpectroscopy", dynamic
SubMenu "Packages..."
GetJTGLoadOrUnloadMenuItem(), /Q, LoadOrUnloadAFMPackage()
help = {"Loads or unloads the set of procedures related to Atomic Force Microscopy."}
End
End
May 4, 2012 at 08:13 pm - Permalink
The nightly builds actually now run just before midnight, so you're looking for a build dated 2012-05-04 or later. If any of you eager beavers want to try this out on Saturday, go right ahead.
May 5, 2012 at 07:20 am - Permalink
Thanks for fixing the IndependentModuleList funtion and posting the dynamic menu solution. This is a much simpler approach than my conditional compilation method.
By the way, while working on this, I was also looking at the WinList function using the WIN:IndependentModule=1 option string. (So that the list of procedures includes those in independent modules.) This setting only shows independent modules if SetIgorOption independentModuleDev=1. My thought was that the option string should override the current SetIgorOption setting. Maybe some technical problem prevents this or mayby my interpretation is faulty. Just a thought.
Jeff
May 8, 2012 at 02:11 pm - Permalink
I agree. We have changed it for the next minor release. The change is in the nightly build.
May 11, 2012 at 08:46 am - Permalink
May 11, 2012 at 11:26 am - Permalink