Environment Slots

Up to 16 separate pieces of information can be passed to a process on creation using Environment Slots. These include handles and binary data.

Handles and binary data can be passed to a process at process creation time using environment slots. This topic describes this concept, and explains how to use the process APIs for environment slots.

Overview

Handles and binary data, in the form of descriptors or integer values, can be passed to a process at process creation time, using what are called environment slots.

Up to 16 separate pieces of information can be passed to a process on creation. For this purpose, a process has 16 environment slots that can contain the information passed to it by the launching process.

Slot 0 is reserved and is never available for general purpose information passing.

The parent (launching) process can only pass information to the child (created) process after the child process has been created. However, it should be done before the child process is resumed; it is an error to try and set environment data in a child process that has been resumed.

A child process can only extract the information from its environment slots once. Extracting information from a slot causes that information to be deleted from the slot.

It is a matter of convention between the parent and child process as to the meaning to be applied to a slot, and the type of data that it is to contain.

The APIs

To pass, a handle, a client server subsession, or binary data to a child process, the parent process calls RProcess::SetParameter(), where the RProcess object represents the newly created child process. There are five overloaded variants of SetParameter() used for passing:

handle:

TInt RProcess::SetParameter(TInt aSlot, RHandleBase aHandle);

client server subsession:

TInt RProcess::SetParameter(TInt aSlot, const RSubSessionBase& aSession);

8-bit descriptor:

TInt RProcess::SetParameter(TInt aSlot, const TDesC8& aDes);

16-bit descriptor:

TInt RProcess::SetParameter(TInt aSlot, const TDesC16& aDes);

integer:

TInt RProcess::SetParameter(TInt aSlot, TInt aData);

To extract, a handle, or a client server subsession, a child process can use the Open() function called on the relevant RHandleBase derived type:

TInt RSemaphore ::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
TInt RBusLogicalChannel::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
TInt RMsgQueueBase::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
TInt RMutex::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
TInt RChunk::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
TInt RSessionBase::Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);
    

To extract descriptor data, or integer data, a child process can use the User class functions:

static TInt User::ParameterLength(TInt aSlot);
static TInt User::GetTIntParameter(TInt aSlot, TInt& aData);
static TInt User::GetDesParameter(TInt aSlot, TDes8& aDes);
static TInt User::GetDesParameter(TInt aSlot, TDes16& aDes);
    
Figure 1. Environment slots

Passing a file handle and a subsession

File server session handles and file handles can both be passed to a child process.

The child process adopts the file handle, and must not be closed by the parent. To use a file handle, the session handle must also be passed.

For security reasons, when sharing a file handle, the parent process should create a separate file server session for the specific purpose of sharing the file handle. If the parent process has other files open with this file server session, the child process can gain access to those files by iterating through all the possible values for the file handle and attempting to Adopt() each one. For the same reason, the child process should only use this session for sharing the file; it should not access other files through this session.

The following two code fragments show code in the parent process and corresponding code in the child process.

//Code in the parent (launching) process

    RProcess p;
    p.Create(KProcName, KNullDesC);    //create “child” process
    
    RFile file;
    RFs session;
    session.Connect();                //connect to file server
    session.ShareProtected();
    file.Create(iSession, KFileName, EFileStreamText|EFileWrite|EFileShareAny);
    file.Write(0, KTestData);
    
    p.SetParameter(5, session);        //session handle passed in slot 5
    p.SetParameter(6, file);        //file handle passed in slot 6
    Session.Close();
    p.Resume();
  

KProcName is the full path name of the executable associated with the child process, and KFilename is the file name.

//Code in the child (launched) process

    RFs session;
    session.Open(5);            //obtain session handle from slot 5
    
    RFile file;
    TInt handle;
    ret = User::GetTIntParameter(8, handle);//get file handle from slot 8
    file.Adopt(session, handle);            //adopt the handle
    TBuf8<100> rbuf;                         //use the file
    ret = file.Read(0, rbuf);
    file.Close();
    session.Close();
  

Passing a general handle, derived from RHandleBase

General handles derived from RHandleBase can be passed to a child process.

The handle is duplicated when it is stored in the child process’s environment. The parent can close the handle immediately after calling SetParameter(), or continue to use the handle and close it later.

The following two code fragments show code in the parent process and corresponding code in the child process.

//Code in the parent (launching) process,
//passing handles to a mutex and a semaphore.

    RMutex mutex;
    RSemaphore sem; 
    
    RProcess p;
    p.Create(KProcName, KNullDesC);
    mutex.CreateGlobal(KMutexName);    //create the mutex
    sem.CreateGlobal(KSemName,0);    //create the semaphore
    p.SetParameter(3, mutex);    //put mutex handle into child process env' slot 3
    p.SetParameter(4, sem);        //put semaphore handle into child process env' slot 4
    mutex.Close();
    Sem.Close();
    p.Resume();            //resume the child process
    
//Code in the child (launched) process retrieving the handles.
    
    RMutex mutex;
    mutex.Open(3, EOwnerThread);    //get mutex handle
    RSemaphore sem;
    sem.Open(4, EOwnerThread);        //get semaphore handle
    
    //use the semaphore and mutex
    mutex.Close();
    sem.Close();
    

Passing descriptor data

Both 8-bit and 16-bit descriptor data can be passed from a parent to a child process.

Internally, an HBuf descriptor is created containing the passed descriptor data, and a pointer to this descriptor is passed in the relevant slot.

The child process retrieves the descriptor data by calling User::GetDesParameter(). It can get the length of the data by calling User::ParameterLength().

The following two code fragments show code in the parent process and corresponding code in the child process.

//Code in the parent (launching) process, passing 8 and sixteen bit data

    RProcess p;
    p.Create(KProcName, KNullDesC);
    p.SetParameter(2, KSixteenBitDes);
    p.SetParameter(3, KEightBitDes);
    p.Resume();
    

where KSixteenBitDes is a 16-descriptor, and KEightBitDes is an 8-bit descriptor.

//Code in the child (launched) process retrieving 8 and sixteen bit data
    
    TInt len;
    TInt ret;

    TBuf16<40> buf;
    len = User::ParameterLength(2);        //parameter length is the size in bytes
    ret = User::GetDesParameter(2, buf);
    
    //buf.Length() should have the value of len/2;


    TBuf8<40> buf8;
    len = User::ParameterLength(3);
    ret = User::GetDesParameter(3, buf8);
    //buf.Length() should be the same as len
    

Note that the descriptors, buf, and buf8 used in the child process must have sufficiently large maximum lengths to accomodate the data.

Passing an integer

An integer can be passed from a parent to a child process.

The following two code fragments show code in the parent process and corresponding code in the child process.

//Code in the parent (launching) process

    RProcess p;
    TInt ret;
 
    ret = p.Create(KProcName, KNullDesC);
    p.SetParameter(12, 1234);  // Using slot 12
    p.Resume();
    
//Code in the child (launched) process, retrieving the integer.

    TInt val;
    TInt ret;

    ret = User::GetTIntParameter(12, val);

    

Error handling issues

The parent process is panicked when calling SetParameter() with a handle if:

  • the parent process is not the creator of the child process

  • the slot number is out of range, i.e. is not in the range 0 to 15

  • the slot is in use

  • the handle is local.

The parent process is panicked when calling SetParameter() with a descriptor or integer if:

  • the parent process is not the creator of the child process

  • the slot number is out of range, i.e. is not in the range 0 to 15

  • the slot is in use

  • the length of the data is negative.

The child process is panicked if the slot number is out of range.

The API functions that extract data from the process environment return KErrArgument if a slot contains the incorrect data type, or the length is incorrect. They return KErrNotFound if a slot is empty.