The following code fragments show a simple implementation of a polymorphic interface DLL. The DLL being implemented is the one whose interface is defined by the CMessenger
class.
This example implementation issues a greeting in French.
Declare a concrete class, called CFrenchMessenger
, as follows:
class CFrenchMessenger : public CMessenger
{
public:
virtual void ConstructL(CConsoleBase* aConsole, const TDesC& aName);
virtual ~CFrenchMessenger();
virtual void ShowMessage();
};
the class implements all of the functions which are declared as pure-virtual in the abstract base class CMessenger
.
no explicit C++ constructor is needed; a new CMessenger
derived object is allocated by the exported function NewMessenger()
which runs in the DLL. The default C++ constructor can, therefore, be safely used.
second-phase construction, implemented by ConstructL()
, completes construction.
Start the implementation code as follows:
GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
{
return(KErrNone);
}
EXPORT_C CMessenger* NewMessenger()
{
return new (ELeave) CFrenchMessenger;
}
The E32Dll()
function is required by all DLLs; it is defined as the main DLL entry point which implies that it is exported, even though there is no explicit EXPORT_C
in the C++ code. Its primary use is to allocate thread-local storage.
the NewMessenger()
function is exported, at ordinal 1 from the DLL; it allocates a CFrenchMessenger
object using the new (ELeave)
operator.
This pattern should be followed by all code packaged as a DLL intended for dynamic loading.
The rest of the C++ module is conventional, note that none of the functions are exported; they are available via the virtual function table which is made available to user code through construction of the CFrenchMessenger
object.
In the UID section, the .mmp
file defining the project must include the same UID values as used by the code that loads the DLL, i.e. the value of KMessengerUid
and the value that identifies the specific implementation.