Content formerly at http://www.mozilla.org/projects/xpcom/nsDirectoryService.html

General nsDirectoryService Information:

nsDirectoryService implements the nsIProperties interface. This implementation will allow you to Get(), Set(), Define(), and Undefine() nsIFile.

Getting a location:

Most developers need to find where a file or directory is located. With nsDirectoryService, there are two steps involved.

First, you must know what the string key (or property) is that refers to this locations. Header files containing known keys are listed in the Known Locations section of this document. Bear in mind that this list is not static. Components can add and remove locations at their will.

Second, you must acquire the implementation and call Get() passing the known string key. In the example below, prop is a string that references your requested file locations.

C++

    nsCOMPtr<nsIFile> dir;
    NS_GetSpecialDirectory(prop, getter_AddRefs(dir));

    if (!dir)
        return NS_ERROR_FAILURE;

Javascript:

 var file = Components.classes["@mozilla.org/file/directory_service;1"]
                    .getService(Components.interfaces.nsIProperties)
                    .get("ProfD", Components.interfaces.nsIFile);

(The example is taken from the Code snippets section of this site.)

Adding a location:

There are currently two ways to add a file location to the directory service: directly and delayed.

You can directly add a new nsIFile with any property string using the nsIProperties interface:

 Components.classes["@mozilla.org/file/directory_service;1"]
                    .getService(Components.interfaces.nsIProperties)
                    .set("MyFileName", file);

Now, if your cost is too high to set all of these properties at once, you can register to be a callback that can provide an nsIFile. To do this, you must get the implementation again like above. When you have it, QueryInterface for the nsIDirectoryService interface. Apart from this interface there is a function, registerProvider which will allow you to register a nsIDirectoryServiceProvider, which implements the getFile callback function:

var provider = {
  getFile : function(prop, persistant) { // return an nsIFile },
}

Components.classes["@mozilla.org/file/directory_service;1"]
    .getService(Components.interfaces.nsIDirectoryService).registerProvider(provider);

When the callback is called, it will be passed the string key, and should return an nsIFile. The persistant flag allows you to specify if you want the nsDirectoryService to cache this value. In most cases you would set this to be true.

The interfaces for this can be found here.

Known Locations

The nsIProperties strings for currently defined locations can be found in:

Content formerly at http://www.mozilla.org/projects/xpco...locations.html

Background

The way in which Mozilla components locate special files and directories has changed. In the past, this was done using nsIFileLocator. This component was a problem for embedding applications. Since it was a component and was loaded implicitly by many other components, it was difficult to customize. Customizing the locations is important if, for example, your application already has a profile directory or other resource directories. You may wish that you could have Mozilla use these locations rather than requiring the same disk layout as SeaMonkey. In order to change these locations using nsIFileLocator and still be able to use the same components directory as an existing Mozilla installation, you had to make a component with the same ID as nsIFileLocator and then, after auto-registering components, manually register your own and replace the existing one -- all in all, a big pain.

The New Method

The new method uses nsIDirectoryService to locate files and directories. Be sure to see the documentation on the service itself. This document will focus on how the service is used and how to customize it. Briefly, nsIDirectoryService uses "providers" of type nsIDirectoryServiceProvider to provide file locations. When the service is asked for a file location, it goes through its list of providers asking each if it knows the requested location until it finds one that does. Once the service finds a location, if the provider says that the location is persistent, the service will cache that location so it is very quick on subsequent calls. Different providers can provide certain locations that are relevant to them. For example, in SeaMonkey, the profile service is a provider for locations that are relative to the current profile.

The caller asking for the file location, of course, doesn't need to know who the providers are. As a caller of the service, you never deal with the providers, only the service.

Defined Locations

The nsIProperties keywords that you will use to get locations are defined in two places.

OS and XPCOM Level

nsDirectoryServiceDefs.h

These locations are provided by XPCOM, are constant with the system, and and should not need customization. Although you will not customize these locations, you may need to tell XPCOM where its /bin directory is. This is done by passing a directory to NS_InitXPCOM or, for embedding, as the first parameter to NS_InitEmbedding. The location of the Components folder and the Components registry, among other things, are relative to the /bin directory.

If Mozilla's Components directory is not in the same directory as your process, you will need to set the /bin directory as described above. In this case you will also need to tell the system of the location of DLLs that are linked against. This aspect of file location is not related to nsIDirectoryService, but needs mention here.

On the Macintosh, these DLLs are the shared libs in the "Essential Files" directory. You need to include an alias in your application that points to this directory and the resource ID of this alias goes into your 'cfrg' resource.

On platforms which use PATH environment variables, you will need to set one of these paths to the /bin directory.

Application Level

nsAppDirectoryServiceDefs.h

The first group listed is for locations that are relative to the application: for instance, the name and location of the chrome folder, or the default location of user profiles. The nsIDirectoryServiceProvider which normally provides these locations is at mozilla/xpcom/io/. This provider is installed by SeaMonkey after initializing XPCOM. It is also installed by default by NS_InitEmbedding.

The second group listed is for locations which are relative to the current user profile. In SeaMonkey, the profile service is an nsIDirectoryServiceProvider and it provides these locations. There are some cases in embedding in which distinct user profiles are not needed; however, prefs and history and such are needed. In this case, the nsIDirectoryServiceProvider implementation at mozilla/profile/dirserviceprovider/ can be used. If it is used, it is used instead of the profile service, thus saving some footprint.

Customizing Locations

Although you can change locations one at a time by using the nsIProperties interface of nsDirectoryService, you can also install your own nsIDirectoryServiceProvider to control them en masse. To do this for application-level locations, create a provider based on appfilelocprovider. This object has to implement the nsISupports and nsIDirectoryServiceProvider interfaces. It does not need to be a component - it can be a static lib, a source file in your project - whatever. Just construct it, pass it to NS_InitEmbedding, and it will be installed. If you are not using NS_InitEmbedding, you will have to construct it and register it yourself using nsIDirectoryService.registerProvider(). If you are registering it yourself it is very important to register it immediately after calling NS_InitXPCOM. There are things in the startup process that need these locations at a very early point - even before registering components.

If you want to use mpfilelocprovider, or something like it, to provide one fixed profile, just construct it and call its Initialize method - it will register itself. Again, if you do this, do not initialize the profile service - it's either one or the other.

Original Document Information