Features of an ECOM Interface
Let's start by considering the features of an ECOM interface As expected, the interface will define a set of pure virtual functions which a concrete instance will implement. In addition, the interface must also provide one or more factory functions that pass a cue to ECOM to enable it to instantiate an object of the correct implementation in the example below, the interface definition has two static NewL functions . The interface must also provide a means for its clients to release it, such as...
M Classes
Computing folklore relates that mix-ins originated from Symbolic's Flavors, an early object-oriented programming system. The designers were apparently inspired by Steve's Ice Cream Parlor, a favorite ice cream shop of MIT students, where customers selected a flavor of ice cream vanilla, strawberry, chocolate, etc and added any combination of mix-ins nuts, fudge, chocolate chips and so on . When referring to multiple inheritance, it implies inheriting from a main flavor base class with a...
Server Startup Code
Having considered the client-side code to start the server, I will now move on to discuss the server-side startup code The code to start a server is quite complex because it differs depending on whether the server will run on a phone or the emulator. This complexity has been removed from Symbian OS v8.0 because Symbian OS process emulation on Win32 has been improved see Chapter 10 for more details . static void RunTheServerL TServerStart amp aStart First create and install the active scheduler...
Symbian OS DLLs
Dynamic link libraries, DLLs, consist of a library of compiled C code that may be loaded into a running process in the context of an existing thread. On Symbian OS there are two main types of DLL shared library DLLs and polymorphic DLLs. A shared library DLL implements library code that may be used by multiple components of any type, that is, other libraries or EXEs. The filename extension of a shared library is .dll - examples of this type are the base user library EUser.dll and the filesystem...
Nesting the Active Scheduler
I've already noted that an event-handling thread has a single active scheduler. However, it is possible, if unusual, to nest other calls to CActiveScheduler Start , say within a RunL event-handling method. The use of nested active scheduler loops is generally discouraged but can be useful if a call should appear to be synchronous, while actually being asynchronous pseudo-synchronous . A good example is a RunL event handler that requires completion of an asynchronous request to another active...
Summary Omq
This chapter examined code for a typical client-server implementation, using a simplistic example to avoid introducing accidental complexity. It is intended for those wishing to implement a server and its client-side access code, and to illustrate how the Symbian OS client-server architecture works in practice, reinforcing the theory described in Chapter 11. The example is a transient server that runs in a separate process from its clients, with the client-side implementation in a separate DLL....
The targettype Specifier
The targettype specifier in the .mmp project file allows you to define the particular binary type of your component. The targettype is not necessarily the extension assigned to the component when it builds, although it may be, but categorizes it for the build tools. I describe below the most common binary types you'll encounter on Symbian OS. Various other plug-in targettypes, such as app, fep, mdl, prn and ecomiic, may be used for a polymorphic DLL. You would logically think that any component...
Starting the Server and Connecting to It from the Client
The RHerculesSession constructor zeroes its iHandle value so it is clear that the RHerculesSession object is invalid and must first connect to the server by calling RSessionBase CreateSession . The client-side implementation of server access code typically wraps this call in a method called Connect , e.g. RFs Connect , or occasionally an Open method. If an attempt is made to submit a request to a server using a client session that has not yet connected to the server, a panic occurs KERN-EXEC 0...
Stopping a Running Thread
A running thread can be removed from the scheduler's ready-to-run queue by a call to Suspend on its thread handle. It still exists, however, and can be scheduled to run again by a call to Resume . A thread can be ended permanently by a call to Kill or Terminate , both of which take an integer parameter representing the exit reason. You should call Kill or Terminate to stop a thread normally, reserving Panic for stopping the thread to highlight a programming error. If the main thread in a...
Example Code 1
Finally, here is an example of how a server may be accessed and used. It illustrates how a client thread creates a session with the Symbian OS file server. The file server session class, RFs, is defined in f32file.h, and to use the file server client-side implementation you must link against efsrv.lib. Having successfully created the session and made it leave-safe using the cleanup stack as described in Chapter 3 , the sample code submits a request to the file server, using RFs Delete . This...
Summary Xrh
This chapter stressed the importance of defining classes clearly and comprehensively so that code is re-used rather than re-written or duplicated. It discussed a number of issues, most of which are not just specific to Symbian OS, but relate generally to C best practice, including a comparison of the relative merits of passing and returning by value, reference or pointer the use of const where appropriate functional abstraction and how not to expose member data the use of enumerations to...
Using the Cleanup Stack with NonCBase Classes
If you've rejoined after skipping the detailed section on how the cleanup stack works, welcome back. Up to this point, we've only really considered one of the overloads of the CleanupStack PushL function PushL CBase aPtr , which takes a pointer to a CBase-derived object. When CleanupStack PopAndDestroy is called for that object, or if leave processing occurs, the object is destroyed by invoking delete on the pointer, which calls the virtual destructor of the CBase-derived object. As mandated by...
InterThread Data Transfer
On Symbian OS, you can't transfer data pointers directly between threads running in separate processes, because process address spaces are protected from each other, as I described in Chapter 8.5 On EKA1 versions of Symbian OS, RThread provides a set of functions that enable inter-thread data transfer regardless of whether the threads are in the same or different processes IMPORT_C TInt GetDesLength const TAny aPtr const IMPORT_C TInt GetDesMaxLength const TAny aPtr const IMPORT_C void ReadL...
The Overuse of TFileName
Another potential hazard when using descriptors occurs through the overuse of TFileName objects. TFileName is defined as follows in e32std.h const Tint KMaxFileName 0x100 256 decimal typedef TBuf lt KMaxFileName gt TFileName Since each wide character is equivalent to two bytes, each time you create and use a TFileName object on the stack you are setting aside 524 bytes 2 x 256 descriptor data bytes 12 for the descriptor object itself regardless of whether they are all actually required for the...
Implementing an ECOM Interface
Having discussed CCryptoInterface, let's move on to consider how it is implemented. Concrete classes must be defined in an ECOM plugin DLL, which is built with targettype ECOMIIC which stands for ECOM Interface Implementation Collection . Here's the .mmp file for the example plug-in DLL TARGET ECryptoExample.dll TARGETTYPE ECOMIIC UID2 ECOM plug-in DLL recognition, UID3 unique UID for this DLL UID 0x10009D8D 0x10009EE1 SOURCE Omitted for clarity USERINCLUDE Omitted for clarity SYSTEMINCLUDE...
Factory Methods
Let's look at the implementation of the two static factory methods in more detail. The overload of NewL that takes no parameters creates an object of the default implementation of CCryptoInterface. In the example An ECOM interface has the following characteristics It is an abstract class with a set of one or more pure virtual functions. It must provide one or more factory functions to allow clients to instantiate an interface implementation object. It must provide a means for its clients to...
TPtrC
TPtrC is the equivalent of using const char when handling strings in C. The data can be accessed but not modified that is, the data in the descriptor is constant. All the non-modifiable operations defined in the TDesC base class are accessible to objects of type TPtrC. The class also defines a range of constructors to allow TPtrC to be constructed from another descriptor, a pointer into memory or a zero-terminated C string. Literal descriptors are described later in this chapter _LIT...
Thread Priorities
3 You can also specify the minimum and maximum heap size for the main thread of a component that runs as a separate process in its .mmp file, using the following statement epocheapsize minSizeInBytes maxSizeInBytes or more threads with equal priority, they are time-sliced on a round-robin basis. The priority of a thread is a number the higher the value, the higher the priority. When writing multithreaded code, you should consider the relative priorities of your threads carefully. You should not...
Info Ifj
Here's one example of how to use the debug assertion macro void CTestClass TestValue TInt aValue _LIT KPanicDescriptor, TestValue Literal descriptor endif __ASSERT_DEBUG aValue gt 0 , User Panic KMyPanicDescriptor, Of course, this is somewhat awkward, especially if you expect to use a number of assertions to validate your code, so you'll probably define a panic utility function for your module, with its own panic category string and a set of panic enumerators specific to the class. So, for...
The Use of HBufC Heap Descriptors
Having discussed some of the features of the descriptor classes, I'll move on now to discuss some of the common mistakes made when using descriptors. First I'll cover the creation and use of HBufC heap descriptors. As I mentioned in Chapter 5, HBufC can be spawned from existing descriptors using the Alloc or AllocL overloads implemented by TDesC. Here is a contrived example which shows how to replace inefficient code with AllocL void CSampleClass UnnecessaryCodeL const TDesC amp aDes...
Override Virtual Functions that You Expect to Override Later
This will ensure that compatibility is not broken should you later need to override a virtual function which was originally inherited as described earlier in Section 18.4 . If you do not currently need to modify the functions beyond what the base class supplies, the overridden implementation should simply call the base-class function. This will allow the functions to be extended in future. Earlier, I gave the example of CSiamese, deriving from CCat, which inherited the default implementation of...
Using TCleanupItem for Customized Cleanup
As I've already mentioned, TCleanupItem can be used to perform customized cleanup when a leave occurs. The cleanup function TCleanup-Operation used by the TCleanupItem must be of the correct signature void Function TAny aParam and may perform any cleanup action appropriate in the event of a leave. It is especially useful for transaction support where a sequence of functions must either succeed or fail as a single atomic operation. If any of the functions leaves, the object must be returned to...
A common mistake is to call the Des method on the heap descriptor to return a
awkward stages. In fact, Symbian OS provides a templated stream operator operator lt lt for externalization, which compresses the length information to keep descriptor storage as efficient and compact as possible. Furthermore, descriptors externalized in this way may be re-created from the stream, as heap descriptors using the NewL overloads of HBufC, passing in the read stream and an additional parameter to indicate the maximum length of data to be read from the stream. This is a significantly...
Heap Allocation Using new ELeave
Let's take a closer look at the use of new ELeave to allocate an object on the heap. This overload leaves if the memory is unavailable, and thus allows the returned pointer to be used without a further test that the allocation was successful. We saw it used in the code fragment above CClanger clanger new ELeave CClanger The code above is preferable to the following code, which requires an additional check to verify that the clanger pointer has been initialized CleanupStack PushL clanger...