|
|
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.
|
|
|