ZFileUtils

ZFileUtils is a DLL (dynamic link library) that provides useful utilities to ZScript. This page describes these utilities. A sample zscript showing how to use all the functions is included in the zip (see below).

The latest version, for ZBrush 2021, includes a DLL file for Windows and a LIB file for MacOSX. Note that these are 64 bit – as ZBrush 2021 is only 64 bit, 32 bit is no longer supported.

Important!

NOTE: for custom zscript plugins, the ZFileUtils files should be placed in a data folder unique to the plugin (and installed with it in the ZStartup\ZPlugs64 folder). This is so that users who download plugins with older versions of the dll will not inadvertently overwrite a newer version.

Download the latest ZFileUtils DLL (with example zscript) for ZBrush 2021 here

Latest version ZFileUtils 2021 01A updated November 17 2020. Still works in ZBrush 2022!

Functions and Examples

In the code examples below, comments are shown in blue and strings are shown in green.

 


Setting the path to the DLL

Before calling a function from the ZFileUtils DLL, ZBrush must know where to find it. The DLL file is different for Windows and Mac, so the simplest way to set the path correctly is to call a CheckSystem routine before trying to access the DLL. Here is an example:

[RoutineDef, CheckSystem,	
  //check ZBrush version
  [VarSet,Zvers,[ZBrushInfo,0]]
  [If,[Val,Zvers] >= 2021.0,,		
    [Note,"\Cff9923This zscript\Cffffff is not designed for this version of 
\Cff9923ZBrush\Cffffff.",,3,4737096,,300]
    [Exit]
  ]	
 [VarSet,isMac, [ZBrushInfo,6]]	//check Mac or PC
 // Make sure we have the dll and set its path
[If,[ZBrushInfo,16]==64,//64 bit
   [If,isMac,
   //use the path below for testing only   
   [VarSet,dllPath,"MyPluginData/ZFileUtils.lib"]	
   //use the path below for installed plugins
   //[VarSet,dllPath,"ZBRUSH_ZSTARTUP/ZPlugs64/MyPluginData/ZFileUtils.lib"]						
  ,	
   //use the path below for testing only	
   [VarSet,dllPath,"MyPluginData\ZFileUtils64.dll"]
   //use the path below for installed plugins
   //[VarSet,dllPath,"ZBRUSH_ZSTARTUP\ZPlugs64\MyPluginData\ZFileUtils64.dll"]		
  ]
,//else 32 bit - no longer supported
   [Note,"\Cff9923This zscript\Cffffff is not designed for this version of 
\Cff9923ZBrush\Cffffff.",,3,4737096,,300]
   [Exit]
]
[If, [FileExists, [Var,dllPath]],
  //check that correct version
  [VarSet, dllVersion, [FileExecute, [Var,dllPath], Version]]
  [If, [Val,dllVersion] >= 8.0,//dll version
  //OK
,//else earlier version			
  [Note,"\Cff9923Note :\Cc0c0c0 The \Cff9923 ZFileUtils plugin \CffffffDLL\Cc0c0c0 is 
an earlier version which does not support this plugin.  Please install correct version."]
  [Exit]
]			
, // else no DLL.
  [Note,"\Cff9923Note :\Cc0c0c0 The \Cff9923 ZFileUtils plugin \CffffffDLL\Cc0c0c0 could
 not be found at the correct location.  Please re-install the plugin, making sure the 
relevant files and folders are in the \CffffffZStartup/ZPlugs\Cc0c0c0 folder."]
  [Exit]
]
]//end routine

Important!

NOTE: for simplicity the calls to the CheckSystem routine have been omitted in the code examples below.

Checking If a Folder Exists

The FolderExists function will return 1 if a folder exists and 0 if it does not.

Example:

 //the full path to the folder
 [VarSet,folderName,"C:/Test Folder"]]
 //check to see if folder exists
 [VarSet,folderExists,[FileExecute,[Var,dllPath],"FolderExists",#folderName]]
 [If,folderExists,
  [Note,"Folder exists.",,3]
 ,//else
  [Note,"Folder does not exist.",,3]
 ]

Making a new Folder

The MakeFolder function will create a new folder. First check that the folder does not already exist.

Example:

//the full path to the new folder
 [VarSet,folderName,"C:/Test Folder"]]
 [VarSet,folderExists,[FileExecute,[Var,dllPath],"FolderExists",#folderName]]
 [If,folderExists,
  [Note,"Folder exists. Operation cancelled.",,3]
  [Exit]
 ,//else no folder
  [VarSet,err,[FileExecute,[Var,dllPath],"MakeFolder",#folderName]]
  [If,err,[Note,"An error occurred.",,2],[Note,"Folder created",,2]]
 ]

Copying a File

The FileCopyTo function will copy a file. When passing two file paths to the ZFileUtils DLL, a memory block must be used for the second path.

Example:

//the file to be copied
 [VarSet,fileName,"MyPluginData\FromThis.txt"]
 //we need the full path
 [VarSet,fileName,[FileNameResolvePath,fileName]]
 //the destination - any existing file will be overwritten!
 [VarSet,copyFileName,"Test Folder\ToThis.txt"]
 //we need the full path
 [VarSet,copyFileName,[FileNameResolvePath,copyFileName]]
 //copy the file
 [MemCreate, ZFileUtils_CopyFile, 256, 0]
 [MemWriteString,ZFileUtils_CopyFile,copyFileName,0]
 [If,[FileExists,fileName],
 [VarSet,err,[FileExecute,[Var,dllPath],"FileCopyTo",fileName,,ZFileUtils_CopyFile]]
 ]
 [MemDelete,ZFileUtils_CopyFile]
 [If,err,[Note,"An error occurred.",,2],[Note,"File copied",,2]]

Renaming a File

The FileRename function renames a file.

Example:

 //the file to be renamed
 [VarSet,fileName,"Test Folder\ToThis.txt"]
 //we need the full path
 [VarSet,fileName,[FileNameResolvePath,fileName]]
 //the new name
 [VarSet,copyFileName,"Test Folder\NewName.txt"]
 //we need the full path
 [VarSet,copyFileName,[FileNameResolvePath,copyFileName]]
 //copy the file
 //create a memblock to take the copy file name
 [MemCreate, ZFileUtils_CopyFile, 256, 0]
 //write the file name to the memblock
 [MemWriteString,ZFileUtils_CopyFile,copyFileName,0]
 //if the file exists, rename it
 [If,[FileExists,fileName],
 [VarSet,err,[FileExecute,[Var,dllPath],"FileRename",fileName,,ZFileUtils_CopyFile]]
 ]
 //delete the memblock as we've finished with it
 [MemDelete,ZFileUtils_CopyFile]
 [If,err,[Note,"An error occurred.",,2],[Note,"File renamed",,2]]

Emptying a Folder

The EmptyFolder function will delete all the files in a folder. (Subfolders will not be deleted or emptied.)

Example:

//the full path to the folder
[VarSet,folderName,"C:\Test Folder"]
//empty the folder of files
[VarSet,err,[FileExecute,[Var,dllPath],"EmptyFolder",#folderName]]
[If,err,[Note,"An error occurred.",,2],[Note,"Folder emptied",,2]]

Deleting a File

The FileDelete function will delete a file.

Example:

//the file to be deleted
 [VarSet,fileName,"Test Folder\ToThis.txt"]
 //we need the full path
 [VarSet,fileName,[FileNameResolvePath,fileName]]
 //if the file exists, delete it
 [If,[FileExists,fileName],
  [VarSet, err, [FileExecute, [Var,dllPath],"FileDelete",#fileName]] // Delete this file...
  [If,err,
   [Note,"An error occurred.",,2]
  ,//else OK
   [Note,"File deleted",,2]
  ]
 ,//else no file
  [Note,"No file to delete!",,2]
 ]

Deleting a Folder

The DeleteFolder function will delete a folder. It must already be empty of all files and subfolders.

Example:

//the full path to the folder
 [VarSet,folderName,"C:\Test Folder"]
 //delete the folder
 [VarSet,err,[FileExecute,[Var,dllPath],"DeleteFolder",#folderName]]
 //an error may mean the folder has files in it
 [If,err,[Note,"An error occurred.",,2],[Note,"Folder deleted",,2]]

Launching an Open Files Dialog

A combination of functions will launch an Open File dialog box and return the number of files selected. The file names can then be retrieved.

The SetDefaultFolder function is optional and is not implemented on Mac OSX. It will set the ‘starting’ folder for the dialog.

Example:

//***this code just for setting the default folder for open dialog
 //get the full path to this script file
 [VarSet,folderName,[FileNameResolvePath,"ZFileUtils_TestZScript.txt"]]
 //use this to create the full path to the folder
 [VarSet,folderName,[FileNameExtract,folderName,1]]
 //(optional) set the default folder (not implemented on Mac OSX)
 [FileExecute, [Var,dllPath], SetDefaultFolder, folderName]

The GetFilesDialog function launches the Open file dialog so that the user can select some files. You can set the Title for the dialog and the File extensions (separated by commas). If no file extensions are specified then all file types can be selected by the user.

The function returns the number of files selected.

Example:

//text for the dialog title (optional)
 [VarDef,dialogTitle, "Please select some files"]
 //string containing file extensions separated by commas(,)
 //if not used then all files will be used
 [VarSet,fileExt,"obj,GoZ,ma"]
 //create memblock for file extensions
 [MemCreate,ZFileUTils_FileExt, 256, 0]
 //copy file extensions to memblock
 [MemWriteString,ZFileUTils_FileExt,fileExt,0]
 //create and launch Open File dialog
 //returns the number of files selected
 [VarSet,fileCount,[FileExecute,[Var,dllPath],"GetFilesDialog",#dialogTitle,,ZFileUTils_FileExt]]
 //***alternative GetFilesDialog function call with no title text or file extensions:
 //[VarSet, fileCount, [FileExecute, [Var,dllPath], "GetFilesDialog"]]
 //delete the memblock as we've finished with it
 [MemDelete,ZFileUTils_FileExt]
 //display the number of files selected
 [Note,[StrMerge,fileCount," files selected"],,2]

The GetFilePath function is used to get the full path for the file at the index specified.
Note that a memory block is used to get the path.

Example:

//now get the full file path to each file selected
 [If,fileCount > 0,
 //Create a memblock to get the file path
 [MemCreate,Test_ZFileUTils, 256, 0]
 //get each of the file paths
 [VarSet,index,1]
 [Loop,fileCount,
  [VarSet,err,[FileExecute, [Var,dllPath],GetFilePath,,index,Test_ZFileUTils]]
  [VarInc,index]
  //if all is OK copy from memblock to variable
  [If,err == 0,
   [MemReadString, Test_ZFileUTils, fileName]
   //do stuff
   //display the file name and path
   [Note,fileName,,1]
  ,//else
   [LoopContinue]
  ]//end if
 ]//end loop
 [MemDelete,Test_ZFileUTils]
 ]//end if fileCount

Listing the Contents of a Folder

A combination of functions for examining the contents of a folder.

The GetFileNumber function returns the number of files and/or subfolders in a folder.

Example:

[VarSet,folderName,[FileNameResolvePath,folderName]]
//get the number of files/folders
 [VarSet,fileCount,[FileExecute,[Var,dllPath],"GetFileNumber",folderName]]
 [If,fileCount < 0,[Note,"Error getting number of files in folder"]]

If the file count is greater than zero then we can proceed to examine the contents.

The OpenFolder function opens the folder so that the contents can be read.

Example:

//open the folder
 [VarSet,err,[FileExecute,[Var,dllPath],"OpenFolder",folderName]]
 //if we can't open the folder exit the zscript
 [If,err,[Note,"Error opening folder."][Exit]]

The GetFile function is used to get the file or folder names. Note that a memory block is used to get each name.

Example:

//create a memblock to get the file name
 [MemCreate,ZFileUtils_list, 256, 0]
 [Loop,fileCount,//loop through the files
 //get the filename
 [VarSet,err,[FileExecute,[Var,dllPath],"GetFile",,,ZFileUtils_list]]
 //an error means we've reached the end of the list, so exit the loop
 [If,err,[LoopExit]]
 //otherwise write the file name from the memblock to a variable
 [MemReadString, ZFileUtils_list,fileName]
 [Note,#fileName]//display each file or folder name
 ]//end loop
 //delete the memblock as we've done with it
 [MemDelete,ZFileUtils_list]

(See the zscript included in the zip file for a more extensive example.)

The CloseFolder function closes the folder after it has been examined. This function must be called after the above functions, so that the folder is not left open.

Example:

//***must close the folder***
 [VarSet,err,[FileExecute,[Var,dllPath],"CloseFolder",folderName]]
 [If,err,[Note,"Error closing folder."]]

Launching an Application with a File

The LaunchAppWithFile function will open a file using a specified application. If no application is specified then the default application will be used.

Example:

//the full path to the app to launch
 [If,isMac,//if we're on Mac OSX
 [VarSet,appPath,"/Applications/TextEdit.app"]
 ,//else we're on Windows
 [VarSet,appPath,"C:\Windows\System32\notepad.exe"]
 ]
 //full path to the file to open
 [VarSet,fullFilePath,[FileNameResolvePath,"MyPluginData\FromThis.txt"]]
 //create memblock for app path
 [MemCreate,ZFileUTils_AppPath, 256, 0]
 //write app path to memblock
 [MemWriteString,ZFileUTils_AppPath,appPath,0]
 [VarSet,err,[FileExecute,[Var,dllPath],"LaunchAppWithFile",#fullFilePath,,ZFileUTils_AppPath]]
 //delete the memblock as we've done with it
 [MemDelete,ZFileUTils_AppPath]
 //an error
 [If,err,[Note,"An error occurred.",,2]]

Getting the Public/Shared folder

Important!

Note: there is now a zscript method for getting the Public/Shared folder, using the special form ZPUBLIC_ which on Windows will resolve to
C:\Users\Public\Documents\ZBrushData2020
and on MacOS to
/Users/Shared/ZBrushData2020 .

The GetPublicFolder function provides a way of getting the path to the Public/Shared folder on the user’s system. ZBrush and its plugins now write any temporary files to folders within the ZBrushData folder at this location. Writing to the Public/Shared folder avoids issues with file read/write permissions. If your plugin is going to use the Public/Shared folder in this way then it should be able to create its own data folder as needed. Follow the method Creating a Public/Shared plugin Data folder outlined below.
//create memblock to get the path
  [If,[MemGetSize,MC_SharedPath],,
    [MemCreate,MC_SharedPath,256,0]
    [FileExecute, [Var,dllPath],GetPublicFolder,,,MC_SharedPath]
  ]
  //copy path from memblock tpo variable
  [MemReadString,MC_SharedPath,gSharedPath,0,1]
  //add ZBrushData to path
  [If,isMac,
    [VarSet,gSharedPath,[StrMerge,gSharedPath,"/Shared/ZBrushData/"]]
  ,//else Windows
    [VarSet,gSharedPath,[StrMerge,gSharedPath,"/ZBrushData/"]]
  ]
  //display result
  [Note,gSharedPath]

Creating a Public/Shared plugin Data folder

The routine below can be used to check for a custom plugin folder MyPluginData and create it if necessary inside the ZBrushData/ZPluginData folder. The variable gSharedPath is then set to the path to MyPluginData and can be used when working with temp files.

[RoutineDef,CheckSharedFolder,  
  [VarSet,gSharedFolder,"ZPluginData/"]//all plugins use same folder
  [VarSet,gPluginFolder,"MyPluginData/"]//unique folder for your plugin
  //create memblock to get public/shared folder
  [If,[MemGetSize,MC_SharedPath],
  //memblock exists - do nothing
  ,//else create memblock
    [MemCreate,MC_SharedPath,256,0]
    [FileExecute, [Var,dllPath],GetPublicFolder,,,MC_SharedPath]
  ]
  //copy path to variable
  [MemReadString,MC_SharedPath,gSharedPath,0,1]
  //check for folders and create as necessary
   [If,isMac,
    [VarSet,gSharedPath,[StrMerge,gSharedPath,"/Shared/ZBrushData/",gSharedFolder]]
    [If,[FileExists,[StrMerge,"!:",gSharedPath,gPluginFolder,"folder.txt"]],,
      [FileExecute, [Var,dllPath],MakeFolder,gSharedPath]
      [FileExecute, [Var,dllPath],MakeFolder,[StrMerge,gSharedPath,gPluginFolder]]
      [MemSaveToFile,MC_SharedPath,[StrMerge,"!:",gSharedPath,gPluginFolder,"folder.txt"]]      
    ]
    [VarSet,gSharedPath,[StrMerge,"!:",gSharedPath,gPluginFolder]] 
   ,//else Windows
    [VarSet,gSharedPath,[StrMerge,gSharedPath,"/ZBrushData/",gSharedFolder]]
    [If,[FileExists,[StrMerge,gSharedPath,gPluginFolder,"folder.txt"]],
    //file exists - do nothing
    ,//else create folders and file
      [FileExecute, [Var,dllPath],MakeFolder,gSharedPath]      
      [FileExecute, [Var,dllPath],MakeFolder,[StrMerge,gSharedPath,gPluginFolder]]
      [MemSaveToFile,MC_SharedPath,[StrMerge,gSharedPath,gPluginFolder,"folder.txt"]]
    ]
    //set variable so can be used when saving temp files
    [VarSet,gSharedPath,[StrMerge,gSharedPath,gPluginFolder]] 
   ]
]//end routine

Launching a Select Folder dialog

The ChooseFolder function will launch a dialog so the user can select a folder. Creation of a new folder is supported.

[IButton,SelectFolder,"Launch a Select Folder dialog",
  [RoutineCall, CheckSystem]
  [VarDef,folderPath,""]
  //create memblock to get the path
  [If,[MemGetSize,MC_FolderPath],,
    [MemCreate,MC_FolderPath,256,0]
  ]
  [VarSet,err,[FileExecute, [Var,dllPath],ChooseFolder,,,MC_FolderPath]]
  [If,err,
    [Note,err]//function will return -1 if no folder chosen
  ,
    //copy path from memblock to variable
    [MemReadString,MC_FolderPath,folderPath,0,1]
    //show the selected folder path
    [Note,folderPath]//Notes do not display backslashes
    //*** when using the path remember to append a slash before the file name!***
    //*** for example:
    //[VarSet,fileName,"My_Model.ztl"]
    //[FileNameSetNext,[StrMerge,folderPath,"/",fileName]]
  ]
  [MemDelete,MC_FolderPath]
]//end button

Renaming a SubTool

The RenameSetNext function can be used to rename a SubTool, 3D Layer or the Transpose Units. The function is called just before the relevant button is pressed. Layer names are limited to 15 characters but the example below does not check for this.

[IButton,SubtoolRename,"Rename selected subtool",
  [RoutineCall, CheckSystem]
  [VarSet,newName,"My New Name"]
  [VarSet,buttonPath,"Tool:SubTool:Rename"]
  //set buttonPath to the button you want
  //"Tool:SubTool:Rename" - for SubTool
  //"Tool:Layers:Rename" - for Layers
  //"Preferences:Transpose Units:Set Units" - for Transpose Units 
  [If, (([IExists, buttonPath]) && ([IsEnabled, buttonPath])),
	[FileExecute, [Var, dllPath], RenameSetNext, newName]
	[IPress, buttonPath]
  ]	
]//end button

Append a blank SubTool

The AppendNewSubTool function can be used to add a new Polymesh3D star at the end of the subtool list. This simplifies operations such as importing files as the imported file will replace the newly appended polymesh.

[VarSet,name,"My Name"]
[VarSet, resIndex, [FileExecute, [Var, dllPath], AppendNewSubTool, name]]
//value of resIndex will be the index of the new subtool