Symbian
Symbian OS Library

FAQ-0619 How do I use RHandleBase::Duplicate()?

[Index][spacer] [Previous] [Next]



 

Classification: C++ Category: Base
Created: 07/23/98 Modified: 09/11/2002
Number: FAQ-0619
Platform: Not Applicable

Question:
I don't understand the interface for the Duplicate() function. How does this function work and what is it used for?

Answer:
The declaration of RHandleBase::Duplicate is
    TInt RHandleBase::Duplicate(const RThread& aSrc,TOwnerType aType=EOwnerProcess);
    The short summary says "Duplicate the current handle from aSrc to this process", but what does that really mean? How is this function used in practice, and what are the pitfalls to be avoided?

    An Analogy

    Think of handles as being words, and threads as being languages.
    The RHandleBase::Duplicate function is about translating a word from one language to another, with the complication that words don't know which language they belong to, and the target language is implied.
      aword = "die";
      aword.Duplicate("German"); // think "TranslateFrom"...
      aword.Print(); // ===> "the"

      aword = "die";
      aword.Duplicate("Englisch");
      aword.Print(); // ===> "sterben"
      Notice that the language we are translating from is also specified in "the current language" - this isn't accidental, but reflects an important fact about the aSrc parameter to RHandleBase::Duplicate. You have to have a valid handle (= word in your language) for the thread (= language) to which the handle belongs.

      1. Making specific handles from generic handles

      The most common use of RHandleBase::Duplicate is to convert a generic handle into a specific one. Going back to the analogy, imagine that every language defined the word "#" to mean "the name of this language". You could then do:
        aword = "#"'
        aword.Duplicate("#");
        aword.Print(); // ==> "Deutsch"
        This has converted the generic handle "the name of this language", into the specific word which is our name for our language (in the example, the German word meaning "the German language").

        Symbian OS has two types of generic handle, both of which are created using the default constructor for the appropriate handle type.
          RThread thisThread; // generic handle meaning "the current thread"
          RProcess thisProcess; // generic handle meaning "the current process"
          An important fact about these generic handles is that they make no claim on the object that they refer to, so you don't need to call Close() when you get rid of them. This is not true of specific handles, which always add a reference to the object they refer to, and prevent the object being fully destroyed until all specific handles have been closed.

          The classic example of Duplicate is therefore:
            RThread thisThread; // generic handle
            TInt err=thisThread.Duplicate(thisThread); // ==> a specific handle
            ...
            thisThread.Close(); // Don't forget!
            What's the point of creating a specific handle for "the current thread"? One answer is in the default second parameter to Duplicate....

            2. Promoting thread-specific handles to process-wide handles

            The second parameter to Duplicate specifies whether the resulting handle is specific to the calling thread, or is valid for all threads in the same process. This stretches the languages analogy too far, but it could be the difference between words in a dialect (= thread-specific handles) and words which all speakers would understand regardless of dialect (= process-wide handles). The previous example uses the default value for the second parameter, EOwnerProcess, which means that the resulting handle can be used by any thread in the current process.

            There are some valid uses for this technique, but it doesn't in general work with handles that are created relative to a session: you can't use this technique to make a process-wide RFile object, for example. One Symbian OS class for which this does work is RLibrary, and it does often make sense to promote the RLibrary handle to a process-wide handle because that ensures that the library won't be automatcially unloaded when the original thread terminates. There are some tricks to this, however:
              RLibrary threadLibrary; // default constructor gives a closed handle
              err=threadLibrary.Load(_L("ESTLIB")); // load up a DLL, thread-specific handle
              err=threadLibrary.Duplicate(RThread()); // WRONG!!!
              This looks OK - we load the library, then promote the thread-specific handle to a process-wide handle. The error is not that this won't work (it will), but that we will accidentally overwrite a specific handle without closing it.

              IMPORTANT: RHandleBase::Duplicate() does not close the old handle.

              This is actually fairly sensible when you think about it for long enough: the generic handles shouldn't be closed anyway as they weren't opened, and the most general case of Duplicate would involve a handle that belongs to another process altogether. For the particular case we are describing here, the correct code would be:
                RLibrary threadLibrary;
                err=threadLibrary.Load(_L("ESTLIB"));
                RLibrary aDup=threadLibrary; // copies the handle without doing Open()
                err=threadLibrary.Duplicate(RThread()); // overwrite the original
                if (err==KErrNone)
                aDup.Close(); // close the original
                3. Receiving handles from other processes

                This is the most general case of Duplicate, and is the general mechanism used to pass handles between a client and a server, for example to implement a piece of shared memory in an RChunk. Here is the code for a client which receives an RChunk from a server:
                  RChunk sharedChunk = response().iChunk; // currently just a meaningless number
                  err=sharedChunk.Duplicate(iServer); // a valid handle for the server
                  ...
                  sharedChunk.Close(); // don't forget!
                  The example assumes that there is a TPckgBuf which encapsulates the server response, and that the server provides a copy of its RChunk handle. We further assume that there is an iServer member in the current object which is a handle to the server, perhaps obtained by [[details please]]. In this example, Symbian OS does something quite complicated to turn the server's handle into something meaningful for our thread, and at the same time it adds another reference to the shared object so that it can't suddenly vanish while we are using it.