<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License
"Eclipse Public License v1.0" which accompanies this distribution,
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
Nokia Corporation - initial contribution.
Contributors:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052" xml:lang="en"><title>Migrating
to V2 client-server APIs</title><shortdesc>Describes how to modify client-server implementations to use the
new Version 2 client-server APIs instead of the deprecated Version 1 APIs.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>The new APIs have been introduced as part of the effort to provide a more
secure interface for client-server communications, and form an essential component
of Platform Security in Symbian platform. </p>
<ul>
<li id="GUID-C53A38E9-A821-577A-930A-F478954FF806"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-35D3BD7A-8C16-50C3-80AD-2422E3B92AAB">General points</xref> </p> </li>
<li id="GUID-FD82A424-BDB5-5DE7-8904-C579C7683CA1"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-0FA5EC5C-8F7B-5E95-BE28-CD0DB6BDCBEE">The Version 1 client-server APIs</xref> </p> </li>
<li id="GUID-63746CDF-E64B-5BA0-A133-8DFD0FA9FCF5"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-8BDFF94E-80E6-5CAF-8CC0-04D7F74FAF43">The Version 2 client-server APIs</xref> </p> </li>
<li id="GUID-87719C35-00EB-51BE-8D01-6955535C6B4A"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-C5A1C9BA-7637-53EB-9898-A58336F87389">Changes to the client interface</xref> </p> </li>
<li id="GUID-CFDDD4B4-DD54-5F9C-B60D-D361EA621670"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-450BE510-C3C9-5988-853B-1A03A84F0875">Changes to the server interface</xref> </p> </li>
<li id="GUID-30E36FBF-25EA-5347-810E-D2C85F853CCD"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-07F7FFA6-D421-54E2-90F7-69F002702C46">Using RMessagePtr2</xref> </p> </li>
<li id="GUID-A2E1CEF3-BD6F-594D-B4DC-098FBABBC6F4"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-1ABF5DC6-A957-5623-93AB-CD7631A36A33">Migration quick reference</xref> </p> </li>
</ul>
<section id="GUID-35D3BD7A-8C16-50C3-80AD-2422E3B92AAB"><title>General points</title> <p>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 <codeph>__HIDE_IPC_V1__</codeph>. </p> <p>For
example, by adding the following line to a component's MMP file: </p> <codeblock id="GUID-048E20E3-1E8C-5F08-9E40-CE0A43849AD5" xml:space="preserve">macro __HIDE_IPC_V1__</codeblock> <p>This
can also be done globally for all components in Symbian platform by defining
the macro in the platform's HRH file: </p> <codeblock id="GUID-30C6F786-CB13-5962-80E5-5ACBB5879B8C" xml:space="preserve">#define __HIDE_IPC_V1__</codeblock> <p>In
addition, the EUSER header files define the macro <codeph>__IPC_V2_PRESENT__</codeph>,
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. </p> </section>
<section id="GUID-0FA5EC5C-8F7B-5E95-BE28-CD0DB6BDCBEE"><title>The Version
1 client-server APIs</title> <p>The following classes and functions are defined
as constituting the Version 1 client-server APIs: </p> <codeblock id="GUID-339D79DC-B401-5F09-B5A2-3D3EE10B3D63" xml:space="preserve">class CSharableSession
class CSession
class CServer
class RMessagePtr
class RMessage
class RServer
RSessionBase::Share(TAttachMode aAttachMode=EExplicitAttach)
RSessionBase::Attach()
RSessionBase::Send(TInt aFunction,TAny* aPtr)
RSessionBase::SendReceive(TInt aFunction,TAny* aPtr,TRequestStatus& aStatus)
RSessionBase::SendReceive(TInt aFunction,TAny* aPtr)
RSubSessionBase::CreateSubSession(RSessionBase&,TInt aFunction,const TAny* aPtr)
RSubSessionBase::Send(TInt aFunction,const TAny* aPtr)
RSubSessionBase::SendReceive(TInt aFunction,const TAny* aPtr,TRequestStatus&)
RSubSessionBase::SendReceive(TInt aFunction,const TAny* aPtr)
RThread::GetDesLength(const TAny* aPtr)
RThread::GetDesMaxLength(const TAny* aPtr)
RThread::ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset)
RThread::ReadL(const TAny* aPtr,TDes16 &aDes,TInt anOffset)
RThread::WriteL(const TAny* aPtr,const TDesC8& aDes,TInt anOffset)
RThread::WriteL(const TAny* aPtr,const TDesC16& aDes,TInt anOffset)</codeblock> <p>The
following functions are considered part of the client-server Version 1 APIs,
when the target thread is in another process. Note that these APIs are <i>not</i> hidden
by the <codeph>__HIDE_IPC_V1__</codeph> macro. </p> <codeblock id="GUID-BDAF69BC-F736-5E2F-9E7C-37B9AAC75A0E" xml:space="preserve">RThread::RequestComplete(TRequestStatus*& aStatus,TInt aReason)
RThread::Kill(TInt aReason)
RThread::Terminate(TInt aReason)
RThread::Panic(const TDesC& aCategory,TInt aReason)
</codeblock> </section>
<section id="GUID-8BDFF94E-80E6-5CAF-8CC0-04D7F74FAF43"><title>The Version
2 client-server APIs</title> <p>The following classes and functions are defined
as constituting the Version 2 client-server APIs. </p> <codeblock id="GUID-E2EDBA7A-5668-52F4-BCF1-18F53A2DD1E9" xml:space="preserve">class CSession2
class CServer2
class RMessagePtr2
class RMessage2
class RServer2
class TIpcArgs
RSessionBase::Send(TInt aFunction,const TIpcArgs& aArgs)
RSessionBase::SendReceive(TInt aFunction,const TIpcArgs& aArgs, TRequestStatus&)
RSessionBase::SendReceive(TInt aFunction, const TIpcArgs& aArgs)
RSessionBase::ShareAuto()
RSubSessionBase::CreateSubSession(RSessionBase&,TInt aFunction,const TIpcArgs&)
RSubSessionBase::Send(TInt aFunction,const TIpcArgs& aArgs)
RSubSessionBase::SendReceive(TInt aFunction,const TIpcArgs& aArgs, TRequestStatus&)
RSubSessionBase::SendReceive(TInt aFunction,const TIpcArgs& aArgs)</codeblock> </section>
<section id="GUID-C5A1C9BA-7637-53EB-9898-A58336F87389"><title>Changes to
the client interface</title> <p>The client interface to a server consists
of a class derived either from <codeph>RSessionBase</codeph> or <codeph>RSubSessionBase</codeph>.
This section lists the changes required to the use of these classes. </p> <ul>
<li id="GUID-65CF4ED6-3133-5452-800C-F1EDA040B7C2"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-F5FB0FB3-6868-5B26-99A5-62082BFA87FD">RSessionBase::Share()</xref> </p> </li>
<li id="GUID-93211175-EBE0-5C2E-9F67-3BFF6E50E5DD"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-68B92D5D-7786-51CD-9A3D-7C835FD64496">RSessionBase::Attach()</xref> </p> </li>
<li id="GUID-596E1B2A-E1FF-553B-A257-A4091DD15F1A"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-8AF1B8B3-F598-5318-B9F9-5C74EEE8FCC9">RSessionBase::Send() & RSessionBase::SendReceive()</xref> </p> </li>
<li id="GUID-E88F13D3-C4C9-5624-A90B-2CC3EA841D5D"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-449D6257-772B-5E08-8E4B-40C11EAF8FBA">RSubSessionBase::CreateSubSession()</xref> </p> </li>
<li id="GUID-B28619D3-BDE6-5434-AB33-3016BA200633"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-858A58D1-A539-55FB-855E-50B997BA9A41">RSubSessionBase::Send() & RSubSessionBase::SendReceive()</xref> </p> </li>
</ul> <p id="GUID-F5FB0FB3-6868-5B26-99A5-62082BFA87FD"><b>RSessionBase::Share()</b> </p> <table id="GUID-175135E8-8583-53E4-8829-88738EEFA357">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 functions: </p> </entry>
<entry><codeblock id="GUID-3A5C2CAB-646B-5C1F-BA30-9808202B61E5" xml:space="preserve">Share()
Share(EExplicitAttach)
Share(EAutoAttach)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-D946029A-A553-5BB3-B868-5348D06CF11E" xml:space="preserve">ShareAuto()</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>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 <i>auto attach</i> sessions; there is no <i>explicit attach</i> sharing
mode. The new <codeph>ShareAuto()</codeph> function should be used to replace
all occurrences of <codeph>Share()</codeph>. </p> <p id="GUID-68B92D5D-7786-51CD-9A3D-7C835FD64496"><b>RSessionBase::Attach()</b> </p> <table id="GUID-43575561-41F7-5F61-ADF2-06892D06941B">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-4E94517B-AAD4-5A7C-8B67-19E2DABF99BF" xml:space="preserve">Attach()</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><p>NONE </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>There is no explicit attach mode in the Version 2 API, (see <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-F5FB0FB3-6868-5B26-99A5-62082BFA87FD">RSessionBase::Share()</xref>).
This means that all occurrences of <codeph>Attach()</codeph> must be removed
from your code when migrating. </p> <p id="GUID-8AF1B8B3-F598-5318-B9F9-5C74EEE8FCC9"><b>RSessionBase::Send() &
RSessionBase::SendReceive()</b> </p> <table id="GUID-BA09FDB1-4DF3-5D73-B314-1333E479FF35">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 functions: </p> </entry>
<entry><codeblock id="GUID-7117993F-8620-598F-818B-769B91A94E02" xml:space="preserve">Send(TInt aFunction,TAny* aPtr)
SendReceive(TInt aFunction,TAny* aPtr,TRequestStatus& aStatus)
SendReceive(TInt aFunction,TAny* aPtr)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 functions: </p> </entry>
<entry><codeblock id="GUID-0A9B8E34-708E-531F-B6C3-2AD2EF9A831B" xml:space="preserve">Send(TInt aFunction,const TIpcArgs& aArgs)
SendReceive(TInt aFunction,const TIpcArgs& aArgs, TRequestStatus& aStatus)
SendReceive(TInt aFunction, const TIpcArgs& aArgs)</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>These are functions for sending request messages to a server.
Each of these messages can take up to <codeph>KMaxMessageArguments</codeph> arbitrary
arguments (i.e. 4 arguments), and it is the packaging of these arguments which
has been changed in the Version 2 APIs. </p> <p>The Version 1 APIs take a <codeph>TAny*</codeph>,
which points to a C array containing a <codeph>KMaxMessageArguments</codeph> number
of 32-bit quantities, usually <codeph>TAny</codeph> * or <codeph>TInt</codeph> types.
This is an example Version 1 client function: </p> <codeblock id="GUID-5FF9D271-11EC-5144-A3ED-8D0B65DD43E1" xml:space="preserve">TInt RMySession::Write(TDes8C& aDes, TInt aLength, TInt aMode)
{
TAny* args[KMaxMessageArguments];
args[0]=&aDes;
args[1]=(TAny*)aLength;
args[2]=(TAny*)aMode;
return SendReceive(ERequestWrite, &args[0]);
}</codeblock> <p>The Version 2 APIs package all of the arguments into
a <codeph>TIpcArgs</codeph> 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: </p> <codeblock id="GUID-3AD69C4D-B00D-5384-9455-4529235ADC0B" xml:space="preserve">TInt RMySession::Write(TDes8& aDes, TInt aLength, TInt aMode)
{
TIpcArgs args(&aDes, aLength, aMode);
return SendReceive(ERequestWrite, args);
}</codeblock> <p>This could also be written in a shorter way: </p> <codeblock id="GUID-9F904E6F-C2BE-57C9-B287-F25D4C743B54" xml:space="preserve">TInt RMySession::Write(TDes8C& aDes, TInt aLength, TInt aMode)
{
return SendReceive(ERequestWrite, TIpcArgs(&aDes, aLength, aMode) );
}</codeblock> <p>The <codeph>TIpcArgs</codeph> object stores additional
type information for each argument, and this is used to validate a server's
usage of the arguments with the various <codeph>RMessagePtr2::Read()</codeph> and <codeph>RMessagePtr2::Write()</codeph> functions. </p> <p>If
you need to explicitly send an empty or unused argument to a server, then
use the <codeph>ENothing</codeph> enumeration. For example: </p> <codeblock id="GUID-1AFAE8D7-6EF1-531C-9605-249952DD3414" xml:space="preserve">TIpcArgs args(arg1, TIpcArgs::ENothing, arg3);</codeblock> <p>The
second argument will have an undefined value when the server receives the
message. </p> <p id="GUID-449D6257-772B-5E08-8E4B-40C11EAF8FBA"><b>RSubSessionBase::CreateSubSession()</b> </p> <table id="GUID-D11D839A-A6DC-56F6-A375-715C3C20DB58">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-C10014FE-A269-55B4-8D7C-AFA726A7468D" xml:space="preserve">CreateSubSession(RSessionBase& aSession,TInt aFunction,const TAny* aPtr)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-4EDF33FA-B99D-5089-AB2E-F6DD29814FA7" xml:space="preserve">CreateSubSession(RSessionBase, TInt aFunction, const TIpcArgs& aArgs)</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>The message arguments supplied to this function use a <codeph>TIpcArgs</codeph> object
in Version 2. This is for the same reason as described in <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-8AF1B8B3-F598-5318-B9F9-5C74EEE8FCC9">RSessionBase::Send() & RSessionBase::SendReceive()</xref>. </p> <p id="GUID-858A58D1-A539-55FB-855E-50B997BA9A41"><b>RSubSessionBase::Send()
& RSubSessionBase::SendReceive()</b> </p> <table id="GUID-3357BA2C-42CF-5590-94EE-0AC5C46C463B">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 functions: </p> </entry>
<entry><codeblock id="GUID-4CCEAB86-160A-50DD-B2AD-63BAD6E865C7" xml:space="preserve">Send(TInt aFunction,const TAny* aPtr)
SendReceive(TInt aFunction,const TAny* aPtr,TRequestStatus&)
SendReceive(TInt aFunction,const TAny* aPtr)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 functions: </p> </entry>
<entry><codeblock id="GUID-0E7FE44C-19E2-5F5C-98A7-04F9F7129C70" xml:space="preserve">Send(TInt aFunction,const TIpcArgs& aArgs)
SendReceive(TInt aFunction,const TIpcArgs& aArgs, TRequestStatus&)
SendReceive(TInt aFunction,const TIpcArgs& aArgs)</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>The message arguments supplied to this function use a <codeph>TIpcArgs</codeph> object
in Version 2. This is for the same reason as described in <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-8AF1B8B3-F598-5318-B9F9-5C74EEE8FCC9">RSessionBase::Send() & RSessionBase::SendReceive()</xref>. </p> </section>
<section id="GUID-450BE510-C3C9-5988-853B-1A03A84F0875"><title>Changes to
the server interface</title> <p>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, <codeph>CServer2</codeph> implements
the Version 2 APIs corresponding to the Version 1 functionality provided by <codeph>CServer</codeph>. </p> <ul>
<li id="GUID-F2E4AB18-F24A-5EEF-B5CC-F8FBF947DE4E"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-43CF1E50-8E60-5633-97B7-B030D1DEC182">CServer</xref> </p> </li>
<li id="GUID-7A262AF7-DBBD-5765-8179-F72E288304B2"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-B05AFD51-FF98-5972-9F40-107D8F8FEA5A">CServer::NewSessionL()</xref> </p> </li>
<li id="GUID-1E1E1D8C-5BA5-5116-99B0-41453000DEE5"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-77592C37-AF3E-59DE-981E-AF23B442163B">CSharableSession</xref> </p> </li>
<li id="GUID-C02F715E-6DF6-5AB0-A607-D740F32ADCEF"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-1616B87E-A4C3-509B-AF79-D4A964032BF1">CSharableSession::CreateL()</xref> </p> </li>
<li id="GUID-3D09C142-DCF5-5FC6-99CC-A54D2FBECFBF"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-868E4703-DD82-5145-809D-91908237266C">CSharableSession::ResourceCountMarkEnd()</xref> </p> </li>
<li id="GUID-38A6E9AB-4804-5852-907D-264F0CDA6D0B"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-54BF8797-7AE5-57E0-B5FD-C36C45D8CFFB">CSharableSession::RMessage()</xref> </p> </li>
<li id="GUID-69440B22-6333-5783-A129-AFFFF7639068"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-F62D83DD-2A1C-5745-9813-E6646FF167BB">CSession</xref> </p> </li>
<li id="GUID-12DC701E-E313-5CFA-9113-077423AE1CFE"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-F0C1B0F6-BF72-5A52-84D1-E7E748D3E1A5">CSession::CSession()</xref> </p> </li>
<li id="GUID-D1DE193D-A5E7-5A80-B317-2E657008B174"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-F2BB351E-73DA-522A-96ED-361F2EB1A379">RMessage</xref> </p> </li>
<li id="GUID-606187D7-226C-5919-86D9-7881540D30D6"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-B0431DFE-C0E5-5767-A299-564EC502B01E">RMessage::Client()</xref> </p> </li>
<li id="GUID-06E2F69F-ABEE-5AB8-9751-45E285C3B494"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-4EEFEF47-D875-5C16-8836-98DD03C0A91D">RMessage::MessagePtr()</xref> </p> </li>
<li id="GUID-73BB6C0D-FEE3-5C9A-B2E6-7BFCD2C59C1B"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-8754F52F-371C-546B-9290-B5369E915318">RMessage::descriptor access methods</xref> </p> </li>
<li id="GUID-CE72E73D-4BA9-566B-ABA0-6FC52F1E17EC"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-49869449-4440-5D20-97ED-32C14C5D1DAF">RMessagePtr</xref> </p> </li>
<li id="GUID-F91895A2-E211-56AF-9DA8-372D312E5E1B"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-A94A9960-319C-51B5-B693-2538D3985004">RThread</xref> </p> </li>
<li id="GUID-4C8AF2A5-72D9-5367-9A7E-3721CC94401F"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-9DA5C542-44B6-5277-837D-1D9150F43B10">RThread::RequestComplete()</xref> </p> </li>
</ul> <p id="GUID-43CF1E50-8E60-5633-97B7-B030D1DEC182"><b>CServer</b> </p> <table id="GUID-BD8385C6-AEAA-5379-87F3-F3B3A9CA5397">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 class: </p> </entry>
<entry><codeblock id="GUID-48ECE79F-22EA-5DE5-A52F-1F6689969E3C" xml:space="preserve">CServer</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 class: </p> </entry>
<entry><codeblock id="GUID-F213E0FA-2708-5365-92F5-551D0A3B15FB" xml:space="preserve">CServer2</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>Simply replace <codeph>CServer</codeph> with <codeph>CServer2</codeph>. </p> <p id="GUID-B05AFD51-FF98-5972-9F40-107D8F8FEA5A"><b>CServer::NewSessionL()</b> </p> <table id="GUID-1755D610-F3C5-50A8-9CE4-BE357883373B">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-0E800CBB-6A25-5338-940C-93FD1D5EAB12" xml:space="preserve">CSharableSession* CServer::NewSessionL(const TVersion& aVersion) const</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-515A05BB-AB3C-5231-B32A-C8812A55B414" xml:space="preserve">CSession2* CServer2::NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>In Version 1, <codeph>CServer::NewSessionL()</codeph> is implemented
by a class derived from <codeph>CServer</codeph>. In Version 2, your derived
class uses <codeph>CServer2</codeph> as the base class. </p> <p>The <codeph>RMessage2</codeph> 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. </p> <p>This message argument can be ignored when migrating code
from the Version 1 APIs. </p> <p id="GUID-77592C37-AF3E-59DE-981E-AF23B442163B"><b>CSharableSession</b> </p> <table id="GUID-3FE15D11-51FA-5B24-B153-47EF5B20C925">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 class: </p> </entry>
<entry><codeblock id="GUID-067FF488-35CE-585F-94FE-BF350B0DA2E1" xml:space="preserve">CSharableSession</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 class: </p> </entry>
<entry><codeblock id="GUID-241A9E7D-2FC5-5202-A9F1-FC17D5CA8F38" xml:space="preserve">CSession2</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>Simply replace <codeph>CSharableSession</codeph> with <codeph>CSession2</codeph>. </p> <p id="GUID-1616B87E-A4C3-509B-AF79-D4A964032BF1"><b>CSharableSession::CreateL()</b> </p> <table id="GUID-7805C54A-7534-5C20-BE26-09575363F9C2">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-D484349C-7B49-5DFE-8B0E-92AD511CC615" xml:space="preserve">void CSharableSession::CreateL(const CServer& aServer)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-7B9C9D6D-A20C-571A-A533-3A4359067B84" xml:space="preserve">void CSession2::CreateL()</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>In Version 1, <codeph>CSharableSession::CreateL()</codeph> can
be re-implemented by a class derived from <codeph>CSharableSession</codeph>.
In Version 2, your derived class uses <codeph>CSession2</codeph> as the base
class. </p> <p>The Version 2 <codeph>CreateL()</codeph> function has no arguments.
If a derived session object overrides this function, then it will need modifying. </p> <p id="GUID-868E4703-DD82-5145-809D-91908237266C"><b>CSharableSession::ResourceCountMarkEnd()</b> </p> <table id="GUID-0E84FAD2-8007-5EA6-BCBB-659E67B0E94D">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-52CC1805-86C8-5B3F-8AC2-D53020B93DDF" xml:space="preserve">void CSharableSession::ResourceCountMarkEnd()</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-037656C1-A71D-52BA-80BE-9647B12D2E6E" xml:space="preserve">void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>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. </p> <p id="GUID-54BF8797-7AE5-57E0-B5FD-C36C45D8CFFB"><b>CSharableSession::RMessage()</b> </p> <table id="GUID-342A2BD3-8446-5437-B785-47BD8071B307">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-86D3741D-F30E-5A9A-A211-5A1C008B70B2" xml:space="preserve">const RMessage& CSharableSession::Message() const</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><p>No equivalent function. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>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 <i>the current message being processed by the session</i>. </p> <p>This
function is not available in Version 2. When a session needs to manipulate
a message delivered to it, it should use the <codeph>RMessage2</codeph> argument
passed to <codeph>ServiceL()</codeph>, 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. </p> <p id="GUID-F62D83DD-2A1C-5745-9813-E6646FF167BB"><b>CSession</b> </p> <table id="GUID-DB57B8A0-66D6-59CF-8DF6-15DBF0EDE488">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 class: </p> </entry>
<entry><codeblock id="GUID-44314564-FEE3-57B5-8878-A989125074EB" xml:space="preserve">CSession</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 class: </p> </entry>
<entry><codeblock id="GUID-18D7BC87-81E7-54D0-A4E0-E4BDAB172FD8" xml:space="preserve">CSession2</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>Replace <codeph>CSession</codeph> with <codeph>CSession2</codeph>. </p> <p>The
changes applicable to <codeph>CSharableSession</codeph> derived classes also
apply to <codeph>CSession</codeph> derived classes. See: </p> <ul>
<li id="GUID-5C5C37DF-5D39-571C-8998-43A3ECB48DA2"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-1616B87E-A4C3-509B-AF79-D4A964032BF1">CSharableSession::CreateL()</xref> </p> </li>
<li id="GUID-F40EFC23-D7A3-5814-8660-DEE9E9CE7762"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-868E4703-DD82-5145-809D-91908237266C">CSharableSession::ResourceCountMarkEnd()</xref> </p> </li>
<li id="GUID-74ED0DB9-10A1-5616-9CFE-3FE2A37F1905"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-54BF8797-7AE5-57E0-B5FD-C36C45D8CFFB">CSharableSession::RMessage()</xref> </p> </li>
</ul> <p>In addition, if you use the following <codeph>CSession</codeph> functions,
then you will need to change your code to use the equivalent functions in
the <codeph>RMessage2</codeph> and/or <codeph>RMessagePtr2</codeph> classes.
See <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-07F7FFA6-D421-54E2-90F7-69F002702C46">Using
RMessagePtr2</xref>. </p> <codeblock id="GUID-97AE07E6-AA05-59D2-9F6E-4D063C40BAD2" xml:space="preserve">void ReadL(const TAny* aPtr,TDes8& aDes) const;
void ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset) const;
void ReadL(const TAny* aPtr,TDes16& aDes) const;
void ReadL(const TAny* aPtr,TDes16& aDes,TInt anOffset) const;
void WriteL(const TAny* aPtr,const TDesC8& aDes) const;
void WriteL(const TAny* aPtr,const TDesC8& aDes,TInt anOffset) const;
void WriteL(const TAny* aPtr,const TDesC16& aDes) const;
void WriteL(const TAny* aPtr,const TDesC16& aDes,TInt anOffset) const;
void Panic(const TDesC& aCategory,TInt aReason) const;
void Kill(TInt aReason) const;
void Terminate(TInt aReason) const;</codeblock> <p id="GUID-F0C1B0F6-BF72-5A52-84D1-E7E748D3E1A5"><b>CSession::CSession()</b> </p> <table id="GUID-8EE0CBE3-B5C4-54A4-9027-0DD37C00EDBD">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-E445EA4B-C26A-5F19-BD11-8C420C005C9E" xml:space="preserve">CSession::CSession(RThread aClient)</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><p>No equivalent constructor. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>The Version 1 <codeph>CSession</codeph> 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. </p> <p id="GUID-F2BB351E-73DA-522A-96ED-361F2EB1A379"><b>RMessage</b> </p> <table id="GUID-AE303124-F8E6-5814-ABF3-86CE010AEB0D">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 class: </p> </entry>
<entry><codeblock id="GUID-97B0E175-06DD-56D5-B72D-F248AA327E28" xml:space="preserve">RMessage</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 class: </p> </entry>
<entry><codeblock id="GUID-F4DEABFB-9B23-5CA1-B8B4-2A83FA36F787" xml:space="preserve">RMessage2</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>Replace <codeph>RMessage</codeph> with <codeph>RMessage2</codeph>. </p> <p>Note
that <codeph>RMessage2</codeph> derives from <codeph>RMessagePtr2</codeph> and
that most of the functions that were members of the Version 1 class <codeph>RMessage</codeph> are
now implemented in the Version 2 class <codeph>RMessagePtr2</codeph>. </p> <p id="GUID-B0431DFE-C0E5-5767-A299-564EC502B01E"><b>RMessage::Client()</b> </p> <table id="GUID-D8B43D00-689F-5A63-B2D8-89D74E2D5ACE">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-2E080CC6-801E-5E91-9146-BE08338C7F2E" xml:space="preserve">const RThread& RMessage::Client() const</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-6FC3BD1F-11BC-5309-AFE3-EC3043B162E6" xml:space="preserve">TInt RMessage2::Client(RThread& aClient, TOwnerType aOwnerType=EOwnerProcess) const</codeblock> <p>(Note that the function is implemented by the <codeph>RMessagePtr2</codeph> base
class.) </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>In Version 1, the kernel maintains a handle to the client thread
which can be extracted from a message by calling <codeph>RMessage::Client()</codeph>. </p> <p>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. <codeph>Close()</codeph> should be
called on the handle when it is no longer needed. </p> <p>Here's an example
of its usage: </p> <codeblock id="GUID-60EB6ACF-4A2D-5EEA-9008-265DDEF3E332" xml:space="preserve">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();
...
}</codeblock> <p> <b>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.</b> See <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-A94A9960-319C-51B5-B693-2538D3985004">RThread</xref> for
more information. </p> <p id="GUID-4EEFEF47-D875-5C16-8836-98DD03C0A91D"><b>RMessage::MessagePtr()</b> </p> <table id="GUID-C4466017-A740-505D-BFF2-90CCE1014878">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-D771DA22-E50F-532E-AE35-16FCFD1194B9" xml:space="preserve">const RMessagePtr RMessage::MessagePtr() const</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><p>No equivalent function. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p> <codeph>RMessage2</codeph> derives from <codeph>RMessagePtr2</codeph>,
therefore an <codeph>RMessagePtr2</codeph> can be simply constructed or assigned
directly from an <codeph>RMessage2</codeph>. There is no need for an explicit
method of construction as was the case in the Version 1 APIs. </p> <p id="GUID-8754F52F-371C-546B-9290-B5369E915318"><b>RMessage::descriptor access
methods</b> </p> <table id="GUID-E584453B-6BC7-56C1-9FDB-E531A3BC0A8C">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 functions: </p> </entry>
<entry><codeblock id="GUID-9C3A91D8-FABE-5D70-91F0-0103FAD39E63" xml:space="preserve">void RMessage::ReadL(const TAny* aPtr,TDes8& aDes) const;
void RMessage::ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset) const;
void RMessage::ReadL(const TAny* aPtr,TDes16& aDes) const;
void RMessage::ReadL(const TAny* aPtr,TDes16& aDes,TInt anOffset) const;
void RMessage::WriteL(const TAny* aPtr,const TDesC8& aDes) const;
void RMessage::WriteL(const TAny* aPtr,const TDesC8& aDes,TInt anOffset) const;
void RMessage::WriteL(const TAny* aPtr,const TDesC16& aDes) const;
void RMessage::WriteL(const TAny* aPtr,const TDesC16& aDes,TInt anOffset) const;</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 functions: </p> </entry>
<entry><p>These functions are replaced by functions that take a message argument
index instead of a <codeph>TAny*</codeph>. See <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-07F7FFA6-D421-54E2-90F7-69F002702C46">Using
RMessagePtr2</xref>. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p id="GUID-49869449-4440-5D20-97ED-32C14C5D1DAF"><b>RMessagePtr</b> </p> <table id="GUID-D7F81784-48AD-5896-8DFF-F71CCE379E1D">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 class: </p> </entry>
<entry><codeblock id="GUID-BF9BEDE9-DB54-5CEB-B66E-4ACA8D97AA92" xml:space="preserve">RMessagePtr</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 class: </p> </entry>
<entry><codeblock id="GUID-AD8BAE63-C125-5912-8B97-FAEE0F41CB58" xml:space="preserve">RMessagePtr2</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>Replace <codeph>RMessagePtr</codeph> with <codeph>RMessagePtr2</codeph>. </p> <p>See <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-07F7FFA6-D421-54E2-90F7-69F002702C46">Using
RMessagePtr2</xref>. </p> <p id="GUID-A94A9960-319C-51B5-B693-2538D3985004"><b>RThread</b> </p> <p>Calls
to the following functions need to be changed to use the equivalent functions
in a <codeph>RMessage2</codeph> /<codeph>RMessagePtr2</codeph> class. See <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-07F7FFA6-D421-54E2-90F7-69F002702C46">Using
RMessagePtr2</xref>. </p> <codeblock id="GUID-589B9378-3AF1-5AFF-99A1-ADF44D7AB575" xml:space="preserve">TInt RThread::GetDesLength(const TAny* aPtr) const
TInt RThread::GetDesMaxLength(const TAny* aPtr)
void RThread::ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset) const
void RThread::ReadL(const TAny* aPtr,TDes16 &aDes,TInt anOffset) const
void RThread::WriteL(const TAny* aPtr,const TDesC8& aDes,TInt anOffset) const
void RThread::WriteL(const TAny* aPtr,const TDesC16& aDes,TInt anOffset) const
void RThread::Kill(TInt aReason)
void RThread::Terminate(TInt aReason)
void RThread::Panic(const TDesC& aCategory,TInt aReason)</codeblock> <p id="GUID-9DA5C542-44B6-5277-837D-1D9150F43B10"><b>RThread::RequestComplete()</b> </p> <table id="GUID-CB602E73-0C6F-51DC-88BB-CC2D334008DD">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p>Version 1 function: </p> </entry>
<entry><codeblock id="GUID-0338C808-E3B3-567E-95AE-EA577E286A7B" xml:space="preserve">void RThread::RequestComplete(TRequestStatus*& aStatus,TInt aReason) const</codeblock> </entry>
</row>
<row>
<entry><p>Version 2 function: </p> </entry>
<entry><codeblock id="GUID-6201C836-1533-5252-B68A-2AEE7CFA59D9" xml:space="preserve">void RMessagePtr2::Complete(TInt aReason) const</codeblock> </entry>
</row>
</tbody>
</tgroup>
</table> <p>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 <codeph>RThread::RequestComplete()</codeph> should
be replaced by a call to <codeph>RMessagePtr2::Complete()</codeph>. This requires
some minor changes to the internal architecture of the server. </p> <p>An
example of a call to <codeph>RThread::RequestComplete()</codeph> 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. </p> <p><b>A
version 1 server implementation</b> </p> <p>In a Version 1 server implementation,
the notification scheme is often implemented with code similar to this: </p> <p>Client
function: </p> <codeblock id="GUID-97208CAC-12F1-5871-A7FE-C9CD465B2C5E" xml:space="preserve">TInt RMySession::NotifyChanges(TRequestStatus& aStatus)
{
TAny* args[KMaxMessageArguments];
args[0]=&aStatus;
return SendReceive(ERequestNotifyChanges, &args[0]);
}</codeblock> <p>The server processes the request like this: </p> <codeblock id="GUID-34777BB5-E58B-5EA2-BF62-6CF96CBECA94" xml:space="preserve">void CMySession::ServiceL(const RMessage& aMessage)
{
...
// Get arguments needed to signal client
RThread clientThread = aMessage.Client();
TRequestStatus* clientStatus = (TRequestStatus*)aMessage.Ptr0();
// Make notify object
TMyNotifyChanges notifyObject(clientThread,clientStatus);
// Add notify object to list of all requests
TInt result=AddNotification(notifyObject);
// Complete request message
aMessage.Complete(result);
...
}</codeblock> <p>When the event happens, clients are notified: </p> <codeblock id="GUID-E45B2795-EA7D-51EF-8892-0516E0BF53DB" xml:space="preserve">void CMySession::SignalNotifications(TInt aResult)
{
TMyNotifyChanges* notifyObject;
while(notifyObject=RemoveNotifyObject())
{
// Complete each NotifyChanges object
RThread clientThread = notifyObject->ClientThread();
TRequestStatus* clientStatus = notifyObject->ClientStatus();
clientThread.RequestComplete(clientStatus,aResult);
}
}</codeblock> <p><b>A
version 2 server implementation</b> </p> <p>In a Version 2 server implementation,
the notification scheme could be implemented using the Version 2 APIs like
this: </p> <p>Client function: </p> <codeblock id="GUID-0FC0A82A-1C12-5455-BD31-1439C1BC89E2" xml:space="preserve">void RMySession::NotifyChanges(TRequestStatus& aStatus)
{
TIpcArgs args(); // No arguments
// Use asynchronous SendReceive for request
SendReceive(ERequestNotifyChanges, args, aStatus);
// void return type because errors will be signalled through aStatus
}</codeblock> <p>The server processes the request like this: </p> <codeblock id="GUID-A27E21CB-C83E-5FA5-B06C-C7326B219314" xml:space="preserve">void CMySession::ServiceL(const RMessage2& aMessage)
{
...
RMessagePtr2 messagePtr = aMessage;
// Make notify object
TMyNotifyChanges notifyObject(messagePtr);
// Add notify object to list of all requests
TInt result=AddNotification(notifyObject);
// Complete request message (only if error)
if(result!=KErrNone)
{
aMessage.Complete(result);
}
...
}</codeblock> <p>When the event happens, clients will be notified: </p> <codeblock id="GUID-3CFBE6E0-226F-5893-BB8B-978D739A2379" xml:space="preserve">void CMySession::SignalNotifications(TInt aResult)
{
TMyNotifyChanges* notifyObject;
while(notifyObject=RemoveNotifyObject())
{
// Complete each NotifyChanges object
RMessagePtr2 messagePtr = notifyObject->MessagePtr();
messagePtr.Complete(aResult)
}
}</codeblock> </section>
<section id="GUID-07F7FFA6-D421-54E2-90F7-69F002702C46"><title>Using RMessagePtr2</title> <p>In
Version 2, a server's interaction with its clients is channelled through <codeph>RMessagePtr2</codeph>,
from which <codeph>RMessage2</codeph> is derived. An <codeph>RMessagePtr2</codeph> 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 <codeph>RMessagePtr2</codeph> functions. </p> <p>The <codeph>RThread</codeph> and <codeph>RSession</codeph> functions
for accessing descriptors, panicking the client and completing requests are
not available in Version 2. Instead, this functionality is provided by <codeph>RMessagePtr2</codeph>.
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. </p> <ul>
<li id="GUID-522FC7B3-A4BA-5507-9BD3-05CBAE0DDED8"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-5D18833F-55D6-50C1-94DB-569F5CA30ECB">Descriptor access functions</xref> </p> </li>
<li id="GUID-D78F8B64-0E73-56EC-A40D-FC7E8FB1D722"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-4BCF7E62-3ACA-535C-B201-84E570F95DE1">RMessagePtr2::Complete()</xref> </p> </li>
<li id="GUID-5DFDDBFB-41AE-5EBC-943A-528C1C42312F"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-460A24B8-6BA3-5059-BE3B-FF9287ACF965">RMessagePtr2::Kill()</xref> </p> </li>
<li id="GUID-A21E615F-A19C-5673-A7A0-372309AC944F"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-FD417FCA-8EC2-568F-A848-1F5712828E7D">RMessagePtr2::Terminate()</xref> </p> </li>
<li id="GUID-CC7E6514-B7C0-507D-902C-2FE3F8EE1D36"><p> <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-3005E91E-1930-5092-B89D-60772D5BD9CA">RMessagePtr2::Panic()</xref> </p> </li>
</ul> <p id="GUID-5D18833F-55D6-50C1-94DB-569F5CA30ECB"><b>Descriptor access functions</b> </p> <codeblock id="GUID-959C66E7-9219-54F7-A104-374CCF8B9D5A" xml:space="preserve">TInt RMessagePtr2::GetDesLength(TInt aParam) const;
TInt RMessagePtr2::GetDesMaxLength(TInt aParam) const;
void RMessagePtr2::ReadL(TInt aParam,TDes8& aDes,TInt aOffset=0) const;
void RMessagePtr2::ReadL(TInt aParam,TDes16 &aDes,TInt aOffset=0) const;
void RMessagePtr2::WriteL(TInt aParam,const TDesC8& aDes,TInt aOffset=0) const;
void RMessagePtr2::WriteL(TInt aParam,const TDesC16& aDes,TInt aOffset=0) const;
TInt RMessagePtr2::Read(TInt aParam,TDes8& aDes,TInt aOffset=0) const;
TInt RMessagePtr2::Read(TInt aParam,TDes16 &aDes,TInt aOffset=0) const;
TInt RMessagePtr2::Write(TInt aParam,const TDesC8& aDes,TInt aOffset=0) const;
TInt RMessagePtr2::Write(TInt aParam,const TDesC16& aDes,TInt aOffset=0) const</codeblock> <p>These
are used in the same way as the equivalent <codeph>RThread</codeph> functions
in the Version 1 APIs, except that instead of referring to the descriptor
by an address in the client, the <codeph>aParam</codeph> 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. </p> <p>For
example, if a client sends a message using code like this </p> <codeblock id="GUID-CF62ABBF-824D-5E84-A39B-58068C85C38F" xml:space="preserve">TInt RMySession::Write(TDes8C& aDes, TInt aLength)
{
return SendReceive(ERequestWrite, TIpcArgs(&aDes, aLength) );
}</codeblock> <p>then the server would access <codeph>aDes</codeph> using
an <codeph>aParam</codeph> value of 0. </p> <codeblock id="GUID-B608F856-8443-58DC-BBAE-D3253E911EA5" xml:space="preserve">void CMySession::ServiceL(const RMessage2& aMessage)
{
...
TInt length=aMessage.Int1(); // Get length from message param 1
TPtr8 buffer=MyNewBufferL(length); // Make a new buffer for the data
aMessage.ReadL(0,buffer); // Read data from client descriptor (param 0)
...</codeblock> <p>Because <codeph>TIpcArgs</codeph> 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 <codeph>aDes</codeph>,
or treating it as a 16-bit descriptor would fail with <codeph>KErrBadDescriptor</codeph>.
(The latter case would have allowed access to data beyond the length of the
8- bit descriptor. </p> <p>Note, both leaving and non-leaving versions of
the <codeph>Read()</codeph> and <codeph>Write()</codeph> functions are provided.
This allows the removal of some TRAP statements in code after migration to
the Version 2 APIs. </p> <p id="GUID-4BCF7E62-3ACA-535C-B201-84E570F95DE1"><b>RMessagePtr2::Complete()</b> </p> <codeblock id="GUID-D0231B69-B33C-5EF5-89D3-0D332C840518" xml:space="preserve">void RMessagePtr2::Complete(TInt aReason) const;</codeblock> <p>This
function signals completion of the client request, in the same way that <codeph>RMessage::Complete()</codeph> does
in Version 1. After completion, the <codeph>iHandle</codeph> member is set
to zero, and this means that <codeph>RMessagePtr2::Handle()</codeph> returns
zero, and <codeph>RMessagePtr2::IsNull()</codeph> returns True. </p> <p>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 <codeph>RMessagePtr2::IsNull()</codeph>,
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 <codeph>RMessage2</codeph> or <codeph>RMessagePtr2</codeph> objects,
this includes passing them as arguments to other functions 'by value'. Use
references instead. </p> <p id="GUID-460A24B8-6BA3-5059-BE3B-FF9287ACF965"><b>RMessagePtr2::Kill()</b> </p> <codeblock id="GUID-E3A4E634-BCA5-5680-96F8-8D83429BB832" xml:space="preserve">void RMessagePtr2::Kill(TInt aReason) const;</codeblock> <p>This
function is used in the same way as the equivalent <codeph>RMessage</codeph> or <codeph>RThread</codeph> functions
in Version 1. Note that this function also performs the action of <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-4BCF7E62-3ACA-535C-B201-84E570F95DE1">RMessagePtr2::Complete()</xref>, so care must be taken that the message is
not used again. </p> <p id="GUID-FD417FCA-8EC2-568F-A848-1F5712828E7D"><b>RMessagePtr2::Terminate()</b> </p> <codeblock id="GUID-69309A0B-36C9-5F5F-9C9B-DD0C318B35DB" xml:space="preserve">void RMessagePtr2::Terminate(TInt aReason) const;</codeblock> <p>This
function is used in the same way as the equivalent <codeph>RMessage</codeph> or <codeph>RThread</codeph> functions
in Version 1. Note that this function also performs the action of <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-4BCF7E62-3ACA-535C-B201-84E570F95DE1">RMessagePtr2::Complete()</xref>, so care must be taken that the message is
not used again. </p> <p id="GUID-3005E91E-1930-5092-B89D-60772D5BD9CA"><b>RMessagePtr2::Panic()</b> </p> <codeblock id="GUID-F31F59D2-D286-57F6-A685-C255225B45C8" xml:space="preserve">void RMessagePtr2::Panic(const TDesC& aCategory,TInt aReason) const;</codeblock> <p>This
function is used in the same way as the equivalent <codeph>RMessage</codeph> or <codeph>RThread</codeph> functions
in Version 1. Note that this function also performs the action of <xref href="GUID-0A332D6E-E712-5186-8CD0-D5022FA54052.dita#GUID-0A332D6E-E712-5186-8CD0-D5022FA54052/GUID-4BCF7E62-3ACA-535C-B201-84E570F95DE1">RMessagePtr2::Complete()</xref>, so care must be taken that the message is
not used again. </p> </section>
<section id="GUID-1ABF5DC6-A957-5623-93AB-CD7631A36A33"><title>Migration quick
reference</title> <p>This is a quick reference to show you which Version 2
APIs you should use to replace the Version 1 APIs. </p> <table id="GUID-0DAF9004-8A70-5F88-899D-996CC96090CC">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p> <b>Version 1 (where used)</b> </p> </entry>
<entry><p> <b>Version 2 (replace with...)</b> </p> </entry>
</row>
<row>
<entry><p> <codeph>CSharableSession</codeph> </p> </entry>
<entry><p> <codeph>CSession2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>CSession</codeph> </p> </entry>
<entry><p> <codeph>CSession2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>CServer</codeph> </p> </entry>
<entry><p> <codeph>CServer2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RMessagePtr</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RMessage</codeph> </p> </entry>
<entry><p> <codeph>RMessage2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RServer</codeph> </p> </entry>
<entry><p> <codeph>RServer2</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::GetDesLength(const TAny* aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::GetDesLength(TInt aParam)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::GetDesMaxLength(const TAny* aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::GetDesMaxLength(TInt aParam)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::ReadL(const TAny* aPtr,TDes8& aDes,TInt
anOffset)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::ReadL(TInt aParam,TDes8& aDes,TInt
aOffset=0)</codeph> </p> <p>Note: use of <codeph>RThread::ReadL()</codeph> enclosed
in a TRAP statement can be replaced by the non-leaving <codeph>RMessagePtr2::Read()</codeph>. </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::ReadL(const TAny* aPtr,TDes16& aDes,TInt
anOffset) </codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::ReadL(TInt aParam,TDes16& aDes,TInt
aOffset=0)</codeph> </p> <p>Note: use of <codeph>RThread::ReadL()</codeph> enclosed
in a TRAP statement can be replaced by the non-leaving <codeph>RMessagePtr2::Read()</codeph>. </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::WriteL(const TAny* aPtr,const TDesC8&
aDes,TInt anOffset) </codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::WriteL(TInt aParam,const TDesC8&
aDes,TInt aOffset=0)</codeph> </p> <p>Note: use of <codeph>RThread::WriteL()</codeph> enclosed
in a TRAP statement can be replaced by the non-leaving <codeph>RMessagePtr2::Write()</codeph>. </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::WriteL(const TAny* aPtr,const TDesC16&
aDes,TInt anOffset)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::WriteL(TInt aParam,const TDesC16&
aDes,TInt aOffset=0)</codeph> </p> <p>Note: use of <codeph>RThread::WriteL()</codeph> enclosed
in a TRAP statement can be replaced by the non-leaving <codeph>RMessagePtr2::Write()</codeph>. </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::RequestComplete(TRequestStatus*& aStatus,TInt
aReason)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::Complete(TInt aReason)</codeph> </p> <p>Note:
the only way of signalling the client thread is by completing a message which
the client sent to the session. </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::Kill(TInt aReason)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::Kill(TInt aReason)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::Terminate(TInt aReason)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::Terminate(TInt aReason)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RThread::Panic(const TDesC& aCategory,TInt
aReason)</codeph> </p> </entry>
<entry><p> <codeph>RMessagePtr2::Panic(const TDesC& aCategory,TInt
aReason)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSessionBase::Share()</codeph> </p> <p>or </p> <p> <codeph>RSessionBase::Share(EExplicitAttach)</codeph> </p> <p>or </p> <p> <codeph>RSessionBase::Share(EAutoAttach)</codeph> </p> </entry>
<entry><p> <codeph>RSessionBase::ShareAuto()</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSessionBase::Attach()</codeph> </p> </entry>
<entry><p>Not required in Version 2. </p> </entry>
</row>
<row>
<entry><p> <codeph>RSessionBase::Send(TInt aFunction,TAny* aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RSessionBase::Send(TInt aFunction,const TIpcArgs&
aArgs)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSessionBase::SendReceive(TInt aFunction,TAny*
aPtr,TRequestStatus& aStatus)</codeph> </p> </entry>
<entry><p> <codeph>RSessionBase::SendReceive(TInt aFunction,const
TIpcArgs& aArgs, TRequestStatus& aStatus)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSessionBase::SendReceive(TInt aFunction,TAny* aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RSessionBase::SendReceive(TInt aFunction, const
TIpcArgs& aArgs)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSubSessionBase::CreateSubSession(RSessionBase&
aSession,TInt aFunction,const TAny* aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RSubSessionBase::CreateSubSession(RSessionBase, TInt
aFunction, const TIpcArgs& aArgs);</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSubSessionBase::Send(TInt aFunction,const TAny*
aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RSubSessionBase::Send(TInt aFunction,const TIpcArgs&
aArgs)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSubSessionBase::SendReceive(TInt aFunction,const TAny*
aPtr,TRequestStatus&)</codeph> </p> </entry>
<entry><p> <codeph>RSubSessionBase::SendReceive(TInt aFunction,const
TIpcArgs& aArgs, TRequestStatus&)</codeph> </p> </entry>
</row>
<row>
<entry><p> <codeph>RSubSessionBase::SendReceive(TInt aFunction,const TAny*
aPtr)</codeph> </p> </entry>
<entry><p> <codeph>RSubSessionBase::SendReceive(TInt aFunction,const
TIpcArgs& aArgs)</codeph> </p> </entry>
</row>
</tbody>
</tgroup>
</table> </section>
</conbody></concept>