Using nsIDirectoryService

  • Revision slug: Using_nsIDirectoryService
  • Revision title: Using nsIDirectoryService
  • Revision id: 7425
  • Created:
  • Creator: LJR
  • Is current revision? No
  • Comment 5 words added, 4 words removed

Revision Content

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

General nsDirectoryService Information:

nsDirectoryService implements the {{ Interface("nsIProperties") }} interface. This implementation will allow you to Get(), Set(), Define(), and Undefine() {{ Interface("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 {{ Interface("nsIFile") }} with any property string using the {{ Interface("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 {{ Interface("nsIDirectoryService") }} interface. Apart from this interface there is a function, registerProvider which will allow you to register a {{ Interface("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 {{ Interface("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 {{ Interface("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 {{ Interface("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 {{ Interface("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 {{ Interface("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 {{ Interface("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, {{ Interface("nsIDirectoryService") }} uses "providers" of type {{ Interface("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 {{ Interface("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 which are linked against. This aspect of file location is not related to {{ Interface("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.

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 {{ Interface("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 {{ Interface("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 {{ Interface("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 {{ Interface("nsIProperties") }} interface of nsDirectoryService, you can also install your own {{ Interface("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 {{ Interface("nsISupports") }} and {{ Interface("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 {{ Interface-method("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.

Related Pages

Original Document Information

  • Authors: Conrad Carlen, Doug Turner
  • Last Updated Date: September 26, 2000
  • Copyright Information: Portions of this content are © 1998–2007 by individual mozilla.org contributors; content available under a Creative Commons license | Details.

Revision Source

<h2 name="Content_formerly_at">Content formerly at <a class=" external" href="http://www.mozilla.org/projects/xpcom/nsDirectoryService.html" rel="freelink">http://www.mozilla.org/projects/xpco...ryService.html</a></h2>
<h4 name="General_nsDirectoryService_Information:">General nsDirectoryService Information:</h4>
<p>nsDirectoryService implements the {{ Interface("nsIProperties") }} interface. This implementation will allow you to <code>Get()</code>, <code>Set()</code>, <code>Define()</code>, and <code>Undefine()</code> {{ Interface("nsIFile") }}.</p><h4 name="Getting_a_location:">Getting a location:</h4>
<p>Most developers need to find where a file or directory is located. With nsDirectoryService, there are two steps involved.</p>
<p>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 <a href="#Known_Locations">Known Locations</a> section of this document. Bear in mind, that this list is not static. Components can add and remove locations at their will.</p>
<p>Second, you must acquire the implementation and call <code>Get()</code> passing the known string key. In the example below, <code>prop</code> is a string that references your requested file locations.</p>
<p>C++</p>
<pre class="eval">    nsCOMPtr&lt;nsIFile&gt; dir;
    NS_GetSpecialDirectory(prop, getter_AddRefs(dir));

    if (!dir)
        return NS_ERROR_FAILURE;
</pre>
<p>Javascript:</p>
<pre class="eval"> var file = Components.classes["@mozilla.org/file/directory_service;1"]
                    .getService(Components.interfaces.nsIProperties)
                    .get("ProfD", Components.interfaces.nsIFile);
</pre>
<p>(The example is taken from the <a href="/en/Code_snippets/File_I//O#Getting_special_files" title="en/Code_snippets/File_I//O#Getting_special_files">Code snippets</a> section of this site.)</p><h4 name="Adding_a_location:">Adding a location:</h4>
<p>There are currently two ways to add a file location to the directory service: directly and delayed.</p>
<p>You can directly add a new {{ Interface("nsIFile") }} with any property string using the {{ Interface("nsIProperties") }} interface:</p>
<pre class="eval"> Components.classes["@mozilla.org/file/directory_service;1"]
                    .getService(Components.interfaces.nsIProperties)
                    .set("MyFileName", file);
</pre>
<p>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, <a href="/en/nsISupports/QueryInterface" title="en/nsISupports/QueryInterface">QueryInterface</a> for the {{ Interface("nsIDirectoryService") }} interface. Apart from this interface there is a function, <code>registerProvider</code> which will allow you to register a {{ Interface("nsIDirectoryServiceProvider") }}, which implements the <code>getFile</code> callback function:</p>
<pre>var provider = {
  getFile : function(prop, persistant) { // return an nsIFile },
}

Components.classes["@mozilla.org/file/directory_service;1"]
    .getService(Components.interfaces.nsIDirectoryService).registerProvider(provider);</pre>
<p>When the callback is called, it will be passed the string key, and should return an {{ Interface("nsIFile") }}. The <code>persistant</code> flag allows you to specify if you want the <code>nsDirectoryService</code> to cache this value. In most cases you would set this to be true.</p>
<p>The interfaces for this can be found <a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsIDirectoryService.idl">here</a>.</p><h4 name="Known_Locations">Known Locations</h4>
<p>The {{ Interface("nsIProperties") }} strings for currently defined locations can be found in:</p>
<ul> <li><a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h">nsDirectoryServiceDefs.h</a></li> <li><a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h">nsAppDirectoryServiceDefs.h</a></li> <li><a class="external" href="http://lxr.mozilla.org/seamonkey/source/toolkit/xre/nsXULAppAPI.h#184">nsXULAppAPI.h</a></li>
</ul>
<h2 name="Content_formerly_at_2">Content formerly at <a class=" external" href="http://www.mozilla.org/projects/xpcom/file_locations.html" rel="freelink">http://www.mozilla.org/projects/xpco...locations.html</a></h2>
<h4 name="Background">Background</h4>
<p>The way in which Mozilla components locate special files and directories has changed. In the past, this was done using {{ Interface("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 {{ Interface("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 {{ Interface("nsIFileLocator") }} and then, after auto-registering components, manually register your own and replace the existing one -- all in all, a big pain.</p>
<h4 name="The_New_Method">The New Method</h4>
<p>The new method uses {{ Interface("nsIDirectoryService") }} to locate files and directories. Be sure to see the <a href="/en/nsDirectoryService" title="en/nsDirectoryService">documentation</a> on the service itself. This document will focus on how the service is used and how to customize it. Briefly, {{ Interface("nsIDirectoryService") }} uses "providers" of type {{ Interface("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.</p>
<p>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.</p>
<h4 name="Defined_Locations">Defined Locations</h4>
<p>The {{ Interface("nsIProperties") }} keywords that you will use to get locations are defined in two places.</p>
<h5 name="OS_and_XPCOM_Level">OS and XPCOM Level</h5>
<p><a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h">nsDirectoryServiceDefs.h</a></p>
<p>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 <a class="external" href="http://lxr.mozilla.org/seamonkey/ident?i=NS_InitXPCOM">NS_InitXPCOM</a> or, for embedding, as the first parameter to <a class="external" href="http://lxr.mozilla.org/seamonkey/ident?i=NS_InitEmbedding">NS_InitEmbedding</a>. The location of the Components folder and the Components registry, among other things, are relative to the /bin directory.</p>
<p>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 {{ Interface("nsIDirectoryService") }}, but needs mention here.</p>
<p>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.</p>
<p>On platforms which use PATH environment variables, you will need to set one of these paths to the /bin directory.</p>
<h5 name="Application_Level">Application Level</h5>
<p><a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h">nsAppDirectoryServiceDefs.h</a></p>
<p>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 {{ Interface("nsIDirectoryServiceProvider") }} which normally provides these locations is at <a class="external" href="http://lxr.mozilla.org/seamonkey/source/xpcom/io/">mozilla/xpcom/io/</a>. This provider is installed by SeaMonkey after initializing XPCOM. It is also installed by default by NS_InitEmbedding.</p>
<p>The second group listed is for locations which are relative to the current user profile. In SeaMonkey, the profile service is an {{ Interface("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 {{ Interface("nsIDirectoryServiceProvider") }} implementation at <a class="external" href="http://lxr.mozilla.org/seamonkey/source/profile/dirserviceprovider/">mozilla/profile/dirserviceprovider/</a> can be used. If it is used, it is used <em>instead</em> of the profile service, thus saving some footprint.</p>
<h4 name="Customizing_Locations">Customizing Locations</h4>
<p>Although you can change locations one at a time by using the {{ Interface("nsIProperties") }} interface of nsDirectoryService, you can also install your own {{ Interface("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 {{ Interface("nsISupports") }} and {{ Interface("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 {{ Interface-method("nsIDirectoryService", "registerProvider") }}. If you are registering it yourself it is very important to register it <strong>immediately</strong> after calling NS_InitXPCOM. There are things in the startup process that need these locations at a very early point - even before registering components.</p>
<p>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.</p>
<h3 name="Related_Pages">Related Pages</h3>
<ul> <li><a href="/en/Code_snippets/File_I//O" title="en/Code_snippets/File_I//O">Code_snippets:File_I/O</a></li>
</ul>
<div class="originaldocinfo">
<h2 name="Original_Document_Information">Original Document Information</h2>
<ul> <li>Authors: <a class="link-mailto" href="mailto:ccarlen@netscape.com">Conrad Carlen</a>, <a class="link-mailto" href="mailto:dougt@netscape.com">Doug Turner</a></li> <li>Last Updated Date: September 26, 2000</li> <li>Copyright Information: Portions of this content are © 1998–2007 by individual mozilla.org contributors; content available under a Creative Commons license | <a class="external" href="http://www.mozilla.org/foundation/licensing/website-content.html">Details</a>.</li>
</ul>
</div>
Revert to this revision