Tag Archives: FILESYSTEM

Directory Management in OpenInsight 10

Over the years there have been several different and disparate ways of managing directories in OpenInsight, and not all of them fully documented. In this post we’re going to take look at the “official” preferred methods, along with a mention of the deprecated ones too.

Preferred methods

  • The FILESYSTEM object (for Event Context)
  • RTI_OS_Dir stored procedure (for non-Event Context)

Deprecated methods

  • Utility stored procedure
  • RTI_OS_Directory stored procedure
  • DirExists stored procedure
  • MkDir stored procedure
  • UtilityMakeDir stored procedure
  • UtilityRemoveDir stored procedure
  • UtilityRename stored procedure

A note on directory management and context

As you may be aware, an OpenInsight application runs in one of the following contexts:

  • Event Context – This applies when your Basic+ programs are called in response to an event from a standard OpenInsight application form or control (i.e. an application managed by the Presentation Server).
  • Non-Event Context – This applies to applications that run Basic+ programs outside of the Presentation Server using the RevCAPI interface to manage an instance of RevEngine. These are usually “Inet” or O4W web applications, but also include other methods like the RevRun.exe program too.

Therefore, one of the most fundamental considerations when choosing which directory management method to use is the context in which it is called: As a rule, when running in Event Context, you should always prefer to use the FILESYSTEM object for directory management, otherwise you should choose the RTI_OS_Dir stored procedure instead.

Note that if there is a possibility that your Basic+ programs will be executed in different contexts at runtime (i.e. you share them between contexts) then you should invoke the IsEventContext stored procedure to determine which method to use.

For example, here is a simple context-aware code snippet that removes a directory:

   Declare Function IsEventContext, RTI_OS_Dir, Exec_Method
   $Insert PS_FileSystem_Equates
   $Insert RTI_SSP_Equates
   
   ErrText = ""

   If IsEventContext() Then
      // Use the FILESYSTEM object
      If Exec_Method( "FILESYSTEM", "REMOVEDIR", DirName ) Else
         ErrInfo = Get_Property( "FILESYSTEM", "FILEOPRESULT" )
         ErrCode = ErrInfo<PS_FOR_ERRORCODE$>
         ErrText = ErrInfo<PS_FOR_ERRORTEXT$>
      End
   End Else
      // Use RTI_OS_DIR
      Call Set_Status( SETSTAT_OK$ )
      If RTI_OS_Dir( "REMOVEDIR", DirName ) Else
         Call Get_Status( ErrText )
      End
   End

Using the FILESYSTEM object

The FILESYSTEM object supports the following methods to manage directories. It integrates fully with the Windows Shell and provide the best user experience in Event Context:

  • COPYDIR
  • DIREXISTS
  • GETSPECIALDIR
  • MAKEDIR
  • MOVEDIR
  • REMOVEDIR
  • RENAMEDIR

The FILESYSTEM object is fully documented here.

Using the RTI_OS_Dir stored procedure

This stored procedure was added to OpenInsight 10 to provide a non-Event Context version of the functionality exposed by the FILESYSTEM object. It supports the following methods:

  • COPYDIR
  • DIREXISTS
  • GETTEMPDIR
  • MAKEDIR
  • MOVEDIR
  • REMOVEDIR
  • RENAMEDIR

The RTI_OS_Dir stored procedure is fully documented here.

(Note that there is no direct equivalent of the FILESYSTEM GETSPECIALDIR method, due to the fact that it is very Windows-specific – the GET_SPECIAL_FOLDER stored procedure should be used instead.)

The Utility stored procedure (Deprecated)

As long-time readers of this blog will know, this stored procedure was deprecated some years ago at the outset of the OpenInsight 10 project, and it is now basically a thin wrapper around several SYSTEM and FILESYSTEM object methods. It supports the following directory management methods:

  • MAKEDIR
  • REMOVEDIR
  • RENAMEDIR

When called in Event Context each of these methods forwards the request to the FILESYSTEM object. When called outside of Event Context these methods call the following stored procedures instead:

  • UtilityMakeDir
  • UtilityRemoveDir
  • UtilityRename

See below for more details on these.

The RTI_OS_Directory stored procedure (Deprecated)

This stored procedure was deprecated in favor of RTI_OS_Dir as it is very platform specific and makes use internally of RTI_OS_Dir, Utility, and an OLE interface to the Windows Shell, making it less performant than calling those procedures directly. Like Utility it is still supported but will not be updated further with any new functionality.

DirExists stored procedure (Deprecated)

This stored procedure is a simple wrapper around the RTI_OS_Dir DIREXISTS method and so has been deprecated, but can still be used by existing code.

MkDir stored procedure (Deprecated)

This venerable stored procedure is a DLL function that calls the Windows API CreateDirectory function. It has been deprecated in favor of the RTI_OS_Dir MAKEDIR method but can still be used by existing code.

UtilityMakeDir, UtilityRemoveDir and UtilityRename stored procedures (Deprecated)

These three functions form part of the original internals of the Utility stored procedure, and use a “raw” C interface that requires explicit null-terminated strings. They are all still available to use, but are deprecated in favor of the RTI_OS_Dir MAKEDIR, REMOVEDIR and RENAMEDIR methods.

Conclusion

As you can see, version 10 has pulled together the many different historical methods of directory management and consolidated them into two entities that can be used dependent on the execution context. These should be the preferred methods of directory management in your OpenInsight applications.

(As of the time of writing the full documentation for RTI_OS_DIR and GET_SPECIAL_FOLDER is in preparation and will be available shortly. All methods described here apply to version 10.2.3 and later.)

(EDIT: Full documentation for RTI_OS_DIR and GET_SPECIAL_FOLDER is now live on the Revelation Wiki.)

The CHOOSEDIR and CHOOSEFILE methods

In light of the Utility function being deprecated (as mentioned in this post) I was recently asked where the CHOOSEFILE and CHOOSEDIR methods had ended up.  There was some discussion about this as the aforementioned article cited that they were moved to the SYSTEM object, and a case was made for moving them to the FILESYSTEM object instead.

In the end it was decided to move them to the FILESYSTEM object (as feedback indicated that was where they were expected to be), but to expose them from the SYSTEM object as well, meaning that we wouldn’t have to alter any existing code.

For future reference here are the official details of both methods:

FILESYSTEM CHOOSEDIR method

This method displays the common “Choose Folder” dialog box to allow a user to select a folder.  It takes two arguments:

  1. The name of an owner window
  2. A @fm-delimited array of initialization data
<1> Dialog text
<2> Initial folder to select
<3> HideNewFolder flag: If TRUE$ then hide the "New Folder" button
<4> ShowFiles flag: If TRUE$ then show files in the dialog as well as folders

The CHOOSEDIR method is basically a wrapper around the Windows SHBrowseForFolder function.

Example:

dlgOptions    = ""
dlgOptions<1> = "Please select the destination RDK folder"
dlgOptions<2> = "c:\RevSoft\RDK"
dlgOptions<3> = FALSE$ ; * // allow new folders
dlgOptions<4> = FALSE$ ; * // don't show files

folderName = Exec_Method( "FILESYSTEM", "CHOOSEDIR", @window, dlgOptions )

// This works too...
folderName = Exec_Method( "SYSTEM", "CHOOSEDIR", @window, dlgOptions )

 

FILESYSTEM CHOOSEDIR method

This method displays the common “Choose File” dialog box to allow a user to open a folder.  It takes two arguments:

  1. The name of an owner window
  2. A @fm-delimited array of initialization data
<1> Mode: If FALSE$ then show an "Open File" dialog, if TRUE$ then show 
    a "Save As" dialog instead.
<2> Filters: contains an "/" delimited list of filter items in the format:
    
       <displayText> "/" <filter> "/"

    Where <displayText> is the string to show in the filter dropdown list
    and <filter> is the string to apply to the selected folder.

<3> Filter Index: Specifies the index of the filters in <2> to be displayed.
<4> Default file name
<5> OFN (OpenFileName) flags. This is a bitmask number specifying the flags 
    to apply to the dialog. They are defined in the following insert record:
    
        MsWin_GetOpenFileName_Equates

<6> Initial folder to select
<7> Default extension: This is appended to the file name if the user fails 
    to type an extension. This string can be any length, but only the first 
    three characters are appended. The string should not contain a 
    period (.). 
<8> Dialog title

The CHOOSEFILE method is a basically wrapper around the Windows GetOpenFileName function.

Example:

$insert msWin_GetOpenFileName_Equates

* // Create a filter string for common image files
filters = "Bitmap Files (*.bmp;*.rle;*.dib)/*.bmp;*.rle;*.dib/" |
        : "GIF Files (*.gif)/*.gif/"                            |
        : "JPeg Files (*.jpg,*jpeg,*.jpe)/*.jpg;*jpeg;*.jpe/"   |
        : "PNG Files (*.png)/*.png/"                            |  
        : "All Files (*.*)/*.*/"

* // Create a bitmask of flags
ofnFlags   = OFN_READONLY$
ofnFlags   = bitOr( ofnFlags, OFN_HIDEREADONLY$ )
ofnFlags   = bitor( ofnFlags, OFN_FILEMUSTEXIST$ )

dlgOptions    = ""
dlgOptions<1> = FALSE$  ;* // "Open"
dlgOptions<2> = filters
dlgOptions<3> = 4       ; * // Pre-select the PNG filter
dlgOptions<4> = "example.png"
dlgOptions<5> = ofnFlags
dlgOptions<6> = ".\images"
dlgoptions<7> = ""
dlgOptions<8> = "Please select an Image"

imageName = Exec_Method( "FILESYSTEM", "CHOOSEFILE", @window, dlgOptions )

* // This works too ...
imageName = Exec_Method( "SYSTEM", "CHOOSEFILE", @window, dlgOptions )

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).

The FILESYSTEM WATCHDIR method

We’ve already taken a look at the new FILESYSTEM object in a previous post, but this time we’re going to focus on a new method we’ve added called WATCHDIR.

This method allows you to monitor the contents of one or more directories on the system and be notified of any changes occurring within them.  It’s API is quite simple and takes up-to three arguments:

  1. The name of the directory to watch (required).
  2. A optional boolean flag denoting if you wish to include sub-directories. (defaults to FALSE$).
  3. An optional set of bit-flags detailing the kind of changes you are interested in.  By default WATCHDIR notifies you of file creation, changes to the name, and changes to the “Last-Write” time.

Example:

$insert msWin_FileNotify_Equates

// Only watch for files being created in the specified dir ...
watchFlags      = FILE_NOTIFY_CHANGE_CREATION$
bIncludeSubDirs = FALSE$
call exec_Method( "FILESYSTEM", "WATCHDIR", "c:\temp\incoming", |
                  bIncludeSubDirs, watchFlags )

When a change occurs the FILESYSTEM object raises a CHANGED event to notify you of the fact,  As with any other OI window or control you can write your own FILESYSTEM CHANGED event handler to respond to this – note that this event is per application, not per window.

Like the standard CHANGED event the relevant change information is passed in the “NewData” argument – in this case “NewData” contains a dynamic array with two fields:

<1> The name and path of the file being changed
<2> A code specifying the type of change

Example FILESYSTEM CHANGED event:

$insert msWin_FileNotify_Equates

changeFile = newData<1>
changeCode = newData<2>

info = ""

begin case
   case ( changeCode = FILE_ACTION_ADDED$ )
      info = "Added"
   case ( changeCode = FILE_ACTION_REMOVED$ )
      info = "Deleted"
   case ( changeCode = FILE_ACTION_MODIFIED$ )
      info = "Modified"
   case ( changeCode = FILE_ACTION_RENAMED_OLD_NAME$ )
      info = "Renamed From"
   case ( changeCode = FILE_ACTION_RENAMED_NEW_NAME$ )
      info = "Renamed To"
end case

call send_Info( info : " " : changeFile )

Technical note: The WATCHDIR method is based on the underlying ReadDirectoryChangesW Windows API function, details of which can be found here.

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).

The new FILESYSTEM object

As we mentioned earlier the decision was taken to deprecate the Utility function, but we still needed to provide the equivalent functionality by some other means. The obvious candidate to update here was the existing SYSTEM object, but rather than overloading it with a whole raft of new members, all of which were filing-system related, we took the decision to create a new object instead, and thus the FILESYSTEM object was born.

The FILESYSTEM object, like the SYSTEM one, is managed internally by the Presentation Server and simply exposes some common Windows Shell directory and file-based functionality to Basic+. As you’ll see below there are some new properties and methods that were not part of the old Utility function, but we’ve also taken the opportunity to enhance some of the existing methods as well – they now hook into the Windows API SHFileOperation function thereby offering better system integration, such as using standard Windows copy/move dialogs and exposing “Undo” functionality.

Here’s a summary of the FILESYSTEM object interface that you’ll find in the new version:

Properties

Property Dev Run Get Set Description
CURRENTDIR X X X Provides access to the current working directory.
DRIVELIST X X Returns a dynamic array of attached drive letters.
FILEOPRESULT X X Returns the most recent result code from a FILESYSTEM object method call.
SYSTEMDIR X X Returns the OS System directory.
TEMPDIR X X Returns the user’s Temp directory.
WINDOWSDIR X X Returns the Windows directory.

Methods

Method Description
COPYDIR Copies an entire directory and sub-directories to a new location.
COPYFILES Copies one or more files to a new location.
DELETEFILES Deletes one or more files.
DIREXISTS Checks to see if a directory exists.
FILEEXISTS Checks to see if a file exists.
GETABSOLUTEPATH Returns an absolute path from a relative path
GETLONGPATH Converts a short path to its long path form
GETRELATIVEPATH Returns a relative path from an absolute path
GETSHORTPATH Converts a long path to its short path (i.e. MS-DOS “8.3”) form
GETSPECIALDIR Returns the path to a “special” OS folder such as “My Documents”, AppData and so on.
MAKEDIR Creates a directory or nested directory path.
MOVEDIR Moves an entire directory and sub-directories to a new location.
MOVEFILES Moves one or more files to a new location.
REMOVEDIR Removes a directory.
RENAMEDIR Renames a directory.
RENAMEFILE Renames a file.

Of course this is probably not a final list, so please feel free to leave us a comment if you think of anything that would make a good addition here.