General points

The
user library, EUSER.DLL, makes both the Version 1 and Version 2 client-server
APIs available. However, it is possible to 'hide' the Version 1 APIs during
compilation by defining the C pre-processor macro __HIDE_IPC_V1__.

For
example, by adding the following line to a component's MMP file:

macro __HIDE_IPC_V1__

This
can also be done globally for all components in Symbian platform by defining
the macro in the platform's HRH file:

#define __HIDE_IPC_V1__

In
addition, the EUSER header files define the macro __IPC_V2_PRESENT__,
which allows source code that still needs to compile with older Symbian platform
releases, to detect the presence of the new APIs, and use conditional compilation
as appropriate.

The Version
1 client-server APIs

The following classes and functions are defined
as constituting the Version 1 client-server APIs:

In Version 1, the two different share modes existed for historical
reasons. All sessions created with new Version 2 servers behave like the Version
1 auto attach sessions; there is no explicit attach sharing
mode. The new ShareAuto() function should be used to replace
all occurrences of Share().

RSessionBase::Attach()

Version 1 function:

Attach()

Version 2 function:

NONE

There is no explicit attach mode in the Version 2 API, (see RSessionBase::Share()).
This means that all occurrences of Attach() must be removed
from your code when migrating.

These are functions for sending request messages to a server.
Each of these messages can take up to KMaxMessageArguments arbitrary
arguments (i.e. 4 arguments), and it is the packaging of these arguments which
has been changed in the Version 2 APIs.

The Version 1 APIs take a TAny*,
which points to a C array containing a KMaxMessageArguments number
of 32-bit quantities, usually TAny * or TInt types.
This is an example Version 1 client function:

The Version 2 APIs package all of the arguments into
a TIpcArgs object. This has templated constructors that take
between 0 and 4 objects. The above example would be implemented like this
using the Version 2 APIs:

The TIpcArgs object stores additional
type information for each argument, and this is used to validate a server's
usage of the arguments with the various RMessagePtr2::Read() and RMessagePtr2::Write() functions.

If
you need to explicitly send an empty or unused argument to a server, then
use the ENothing enumeration. For example:

TIpcArgs args(arg1, TIpcArgs::ENothing, arg3);

The
second argument will have an undefined value when the server receives the
message.

Changes to
the server interface

This section details the changes required
to migrate a server implementation to the Version 2 APIs. These APIs have,
in nearly all cases, been implemented using the same class names as in Version
1, but with the addition of the suffix '2'. For example, CServer2 implements
the Version 2 APIs corresponding to the Version 1 functionality provided by CServer.

In Version 1, CServer::NewSessionL() is implemented
by a class derived from CServer. In Version 2, your derived
class uses CServer2 as the base class.

The RMessage2 argument
in Version 2 is the 'connect' message from the client. It has been added to
allow implementations to check identity and security information about the
new client.

This message argument can be ignored when migrating code
from the Version 1 APIs.

CSharableSession

Version 1 class:

CSharableSession

Version 2 class:

CSession2

Simply replace CSharableSession with CSession2.

CSharableSession::CreateL()

Version 1 function:

void CSharableSession::CreateL(const CServer& aServer)

Version 2 function:

void CSession2::CreateL()

In Version 1, CSharableSession::CreateL() can
be re-implemented by a class derived from CSharableSession.
In Version 2, your derived class uses CSession2 as the base
class.

The Version 2 CreateL() function has no arguments.
If a derived session object overrides this function, then it will need modifying.

CSharableSession::ResourceCountMarkEnd()

Version 1 function:

void CSharableSession::ResourceCountMarkEnd()

Version 2 function:

void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)

In Version 2, the function requires a reference to the client
message that requested the resource check. This message is used to panic the
client if the check fails.

CSharableSession::RMessage()

Version 1 function:

const RMessage& CSharableSession::Message() const

Version 2 function:

No equivalent function.

In Version 1. this function returns a reference to the last message
delivered to the server. It is usually used by a session implementation to
mean the current message being processed by the session.

This
function is not available in Version 2. When a session needs to manipulate
a message delivered to it, it should use the RMessage2 argument
passed to ServiceL(), instead. Achieving this may require
passing this reference as an argument between function calls, or if that is
complex, then storing a reference to the message in the session object.

The Version 1 CSession object stores a handle
for the client thread. This should no longer be required after moving over
to Version 2, and indeed, a constructor taking a thread handle as an argument
is not supplied.

RMessage

Version 1 class:

RMessage

Version 2 class:

RMessage2

Replace RMessage with RMessage2.

Note
that RMessage2 derives from RMessagePtr2 and
that most of the functions that were members of the Version 1 class RMessage are
now implemented in the Version 2 class RMessagePtr2.

(Note that the function is implemented by the RMessagePtr2 base
class.)

In Version 1, the kernel maintains a handle to the client thread
which can be extracted from a message by calling RMessage::Client().

In
Version 2, this special handle is not present; instead, a function is provided
that explicitly opens a handle on the client thread. This should be treated
just like any other thread handle, i.e. Close() should be
called on the handle when it is no longer needed.

Here's an example
of its usage:

void CMySession::ServiceL(const RMessage2& aMessage)
{
...
RThread clientThread;
// Open a handle on the client thread. Leaving if there is an error.
User::LeaveIfError(aMessage.Client(clientThread));
// Do something with the handle. (Print its ID in this example)
RDebug::Print(_L("Client Thread ID = %n"),clientThread.Id());
// Close handle
clientThread.Close();
...
}

You need to carefully examine all uses of RMessage::Client(),
as most servers should not need to use this function after migrating to the
Version 2 APIs. This is because the use of thread handles in a Version 1 server
is likely to involve those functions that have been removed from the Version
2 APIs. See RThread for
more information.

RMessage::MessagePtr()

Version 1 function:

const RMessagePtr RMessage::MessagePtr() const

Version 2 function:

No equivalent function.

RMessage2 derives from RMessagePtr2,
therefore an RMessagePtr2 can be simply constructed or assigned
directly from an RMessage2. There is no need for an explicit
method of construction as was the case in the Version 1 APIs.

With the Version 2 APIs, the only way of signalling a client's
request status in a different process is by completing a message sent by the
client to the session. This means that a call to RThread::RequestComplete() should
be replaced by a call to RMessagePtr2::Complete(). This requires
some minor changes to the internal architecture of the server.

An
example of a call to RThread::RequestComplete() is where
a server implements a kind of notification service, where a client asks to
be signalled when some event or change of state occurs.

A
version 1 server implementation

In a Version 1 server implementation,
the notification scheme is often implemented with code similar to this:

Using RMessagePtr2

In
Version 2, a server's interaction with its clients is channelled through RMessagePtr2,
from which RMessage2 is derived. An RMessagePtr2 object
acts as a handle to the message that the client has sent. The details of the
original message are maintained within the kernel so that it can enforce correct
use of the RMessagePtr2 functions.

The RThread and RSession functions
for accessing descriptors, panicking the client and completing requests are
not available in Version 2. Instead, this functionality is provided by RMessagePtr2.
Because of this, server implementations may need to have a reference to the
message available in many places. This may be done by passing such references
as arguments between functions or by storing a reference in the session object
processing the request.

These
are used in the same way as the equivalent RThread functions
in the Version 1 APIs, except that instead of referring to the descriptor
by an address in the client, the aParam argument is used.
This is a value between 0 and 3 and indicates which of the four arguments
in the original client message contains the pointer to the descriptor.

Because TIpcArgs also stores type
information about arguments, the kernel knows that argument 0 in the above
message is an 8-bit constant descriptor. On Symbian platforms
using the EKA2 kernel, this information is used to enforce correct usage of
descriptor access methods; in this case, trying to write to aDes,
or treating it as a 16-bit descriptor would fail with KErrBadDescriptor.
(The latter case would have allowed access to data beyond the length of the
8- bit descriptor.

Note, both leaving and non-leaving versions of
the Read() and Write() functions are provided.
This allows the removal of some TRAP statements in code after migration to
the Version 2 APIs.

RMessagePtr2::Complete()

void RMessagePtr2::Complete(TInt aReason) const;

This
function signals completion of the client request, in the same way that RMessage::Complete() does
in Version 1. After completion, the iHandle member is set
to zero, and this means that RMessagePtr2::Handle() returns
zero, and RMessagePtr2::IsNull() returns True.

It
is important to note that once a message has been completed, it cannot be
used by the server, and any such attempt results in a KERN-EXEC 44 panic (Bad
Message Handle). To avoid this situation, implementations may need to check RMessagePtr2::IsNull(),
but be aware that any copies of the message made before completion will not
have had their handles nulled. For this reason, it is best to avoid making
copies of RMessage2 or RMessagePtr2 objects,
this includes passing them as arguments to other functions 'by value'. Use
references instead.

RMessagePtr2::Kill()

void RMessagePtr2::Kill(TInt aReason) const;

This
function is used in the same way as the equivalent RMessage or RThread functions
in Version 1. Note that this function also performs the action of RMessagePtr2::Complete(), so care must be taken that the message is
not used again.

RMessagePtr2::Terminate()

void RMessagePtr2::Terminate(TInt aReason) const;

This
function is used in the same way as the equivalent RMessage or RThread functions
in Version 1. Note that this function also performs the action of RMessagePtr2::Complete(), so care must be taken that the message is
not used again.

RMessagePtr2::Panic()

void RMessagePtr2::Panic(const TDesC& aCategory,TInt aReason) const;

This
function is used in the same way as the equivalent RMessage or RThread functions
in Version 1. Note that this function also performs the action of RMessagePtr2::Complete(), so care must be taken that the message is
not used again.

Migration quick
reference

This is a quick reference to show you which Version 2
APIs you should use to replace the Version 1 APIs.

Version 1 (where used)

Version 2 (replace with...)

CSharableSession

CSession2

CSession

CSession2

CServer

CServer2

RMessagePtr

RMessagePtr2

RMessage

RMessage2

RServer

RServer2

RThread::GetDesLength(const TAny* aPtr)

RMessagePtr2::GetDesLength(TInt aParam)

RThread::GetDesMaxLength(const TAny* aPtr)

RMessagePtr2::GetDesMaxLength(TInt aParam)

RThread::ReadL(const TAny* aPtr,TDes8& aDes,TInt
anOffset)

RMessagePtr2::ReadL(TInt aParam,TDes8& aDes,TInt
aOffset=0)

Note: use of RThread::ReadL() enclosed
in a TRAP statement can be replaced by the non-leaving RMessagePtr2::Read().

RThread::ReadL(const TAny* aPtr,TDes16& aDes,TInt
anOffset)

RMessagePtr2::ReadL(TInt aParam,TDes16& aDes,TInt
aOffset=0)

Note: use of RThread::ReadL() enclosed
in a TRAP statement can be replaced by the non-leaving RMessagePtr2::Read().

RThread::WriteL(const TAny* aPtr,const TDesC8&
aDes,TInt anOffset)

RMessagePtr2::WriteL(TInt aParam,const TDesC8&
aDes,TInt aOffset=0)

Note: use of RThread::WriteL() enclosed
in a TRAP statement can be replaced by the non-leaving RMessagePtr2::Write().

RThread::WriteL(const TAny* aPtr,const TDesC16&
aDes,TInt anOffset)

RMessagePtr2::WriteL(TInt aParam,const TDesC16&
aDes,TInt aOffset=0)

Note: use of RThread::WriteL() enclosed
in a TRAP statement can be replaced by the non-leaving RMessagePtr2::Write().

RThread::RequestComplete(TRequestStatus*& aStatus,TInt
aReason)

RMessagePtr2::Complete(TInt aReason)

Note:
the only way of signalling the client thread is by completing a message which
the client sent to the session.