Content formerly at http://www.mozilla.org/projects/xpcom/nsDirectoryService.html
General nsDirectoryService Information:
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. At the bottom of this document are links to header files containing known keys. Bare 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 string that references your requested file locations.
NS_WITH_SERVICE( nsIProperties, directoryService, NS_DIRECTORY_SERVICE_PROGID, &rv); if (NS_FAILED(rv)) return rv; rv = directoryService->Get( prop, NS_GET_IID(nsIFile), getter_AddRefs(dir)); if (NS_FAILED(rv)) return rv;
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. I will not bore you with an example, but you simply pass the nsIFile as a nsISupports to the Set() method of the nsIProperties interface.
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. Off of this interface, there is a function which will allow you to register a |nsIDirectoryServiceProvider|. The callback
nsIFile getFile(in string prop, out PRBool persistant);
passes you the string key, and asks that you return a nsIFile. The |persistant| flag allow you to specify if you want the nsDirectoryService to cache this value. Most uses you would want this to be true.
The interfaces for this can be found here.
Content formerly at http://www.mozilla.org/projects/xpcom/file_locations.html
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.
The nsIProperties keywords that you will use to get locations are defined in two places.
OS and XPCOM Level
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 which 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 which 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.
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.
Although you can change locations one at a time by using the nsIProperties interface of nsDirectoryService, you can also install your own nsIDirectoryServiceProviders 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.