[Closed] getFilenamePath on load problem?
Hi,
I have a problem with following piece of code:
global Scriptname = getThisScriptFilename()
global Scriptpath = (getFilenamePath Scriptname)
Listener:
– Error occurred in anonymous codeblock; filename: R:\Sergio\Workshop\3D Max Projects\Scripting\Brick Generator\Brick Generator v3.ms; position: 1889; line: 48
– Unable to convert: undefined to type: FileName
Thing is that it happens only on fresh Max start. After 3 tries (loading script) it starts to work.
On the second try, script gives an error in one of the functions
Loadcfg (configfilepath)
And on 3rd run everything works absolutely ok.
So what can be causing this error?
Hard to say what causes this, could you give more information about your script? For example why Scriptname and Scriptpath are defined as global and what the relevance of Loadcfg() is. Also, are you loading Brick Generator v3.ms manually? Or as (part of) a startup script?
Martijn
At this stage, I’m loading it manually, later it will be just called by button.
Scriptname and Scriptpath are defined as global as they will be used in most of functions and different parts of script. (In here I might be wrong, but I thought local works only within a function or dialog).
Loadcfg() is a function that loads the file. And it uses Scriptpath to find this file (as the file stored with script).
So structure is following:
Scriptname – gives full path and name of script (exmpl. C:\SCRIPT\myscript.ms)
Scriptpath – extracts path from above (exmpl. C:\SCRIPT)
Then there’s another global (gives a filename and path of config file):
global configfilepath = Scriptpath as string+"config.cfg"
(exmpl. C:\SCRIPT\config.cfg)
Loadcfg(configfilepath) – is a call for function (on load).
fn loadcfg cfgfile=
(
cfgpath= cfgfile
ConfigFile = openFile cfgpath mode:"rt"
Print ConfigFile -- Just as example
)
The fact that it runs after several tries shows that you have a collision of implicitly local variables with explicitly global variables. This is usually caused by incorrect order of file loading.
What happens is that if one script is referencing the variable Scriptpath but the line ‘global Scriptpath = …’ has not been executed yet, a LOCAL variable Scriptpath with value of undefined will be created if the line happens to be inside any form of local scope (inside top-level brackets, in a function, in a loop body etc.). As result, even if the Scriptpath and Scriptname global variables get defined later, the previously created local versions in the other script will still be there and contain undefined, causing the error you saw.
Then if you run the scripts again and again, at some point the global variables will exist and the other script will “see” them and stop creating local variables with the same names, and the problem would go away.
There are several major approaches to fixing this:
- You can pre-define the global variables Scriptpath and Scriptname without giving them a value in the beginning of any script that will use them;
- You can prefix the variables Scriptpath and Scriptname with :: wherever you use them in other scripts to force MAXScript to look directly in the global scope;
- You can enforce the loading order of your scripts by having a “launcher” script that performs fileIn() of all your files in the CORRECT order (first the script that defines the Scriptpath and Scriptname globals, then all scripts that use them).
I suggest using approaches 1 or 2. They will ensure that any scripts accessing your global variables “know” at compile time that they will be global at run time.
Simply adding the line
global Scriptpath, Scriptname
to the top of all your scripts should solve this issue…
If I can make one more suggestion, make sure you use longer and more unique names for global variables, for example prefix them with the name of your current script project so next time you write a similar script, you won’t get conflicting variable names…
I completely second this – it’s saved me so much messing about since I eventually started to do this!
Probably I understand what you mean.
It’s like in C++, first you have to allocate memory: int x = 0;
and only the modify it.
Ok I’ve added folowing even before Rollout:
global Scriptpath, Scriptname
looks like it solved one step.
Now script works from 2 tries. Firs one still give following error:
In rollout itself I define configpath:
global configfilepath = Scriptpath as string+"config.skcfg"
Listener:
-- Error occurred in anonymous codeblock; filename: R:\Sergio\Workshop\3D Max Projects\Scripting\Brick Generator\Brick Generator v3.ms; position: 1920; line: 49
-- Unable to convert: undefined to type: FileName
Just tried to make completely new script with just this:
global Scriptname1 = getThisScriptFilename()
global Scriptpath1 = (getFilenamePath Scriptname1)
global configfilepath1 = Scriptpath1 as string+"config.skcfg"
Works absolutely fine even without predefining them.
It looks like it tries to read functions before he stores globals.
UPD: I switched off all Rollout. LEft only those 3 globals, and all functions (which not called by anything). All works – Listener gives all names, paths correctly.
So there is some problem with converting them to filename at first start.
I’m absolutely agree with Bobo. The reason of error messages is the specific order of loaded scripts. But sometimes more important the stage of variables at the moment of script ‘compilation’.
lets see:
global thePathName
macroscript <...>
(
format "%
" thePathName
)
we declare thePathName as globals both in macroscript and startup script for example. but we define the variable in startup script, means after the macroscript was compiled and loaded.
execution of the macroscript will print undefined value.
why? because at the moment of macroscript compiling(loading) the compiler sets in place of thePathName the value (!) at the moment of compiling. which is undefined.
but if we change the code to:
global thePathName
macroscript <...>
(
if thePathName != undefined do format "%
" thePathName
)
in this case the compiler sets in place of thePathName a pointer to this value instead of the value itself.
so the macroscript will print the value of thePathName at the moment of execution, which was defined in the startup script.
If I understood you correctly
Maybe I’m wrong but it looks like it hates to send path as function parameter.
Will to few tests and will post them here – (for now if I don’t use a functions – but load file in script (in Rollout) it works fine.
So will try to do 2 scripts with/without function and see where the error begins.
Right got the core of the error. And it is due to function.
However still don’t know how to fix it.
Here are both scripts –
http://depositfiles.com/files/4u2tadg8y
In this file I’ve included two scripts and bitmap:
- Test.ms – bitmap gets loaded straight from Rollout “open”.
- Test (with function).ms – the Rollout “open” calls for a function that loads the bitmap.
First one works ok. The second one does the same error on first load, but runs ok on second load. As I’ve mentioned previously the path is passed to function via function parameter.
we are not following my logic. you have exactly the same issue. Now Loadcfg functions is not defined at the moment of the script compiling.
so if there is no any other place that overrides the Loadcfg function and the function is declared as global, the code has to look like:
if thePathName != undefined and iskindof theFunction Primitive do theFunction thePathName