williamr@2: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). williamr@2: // All rights reserved. williamr@2: // This component and the accompanying materials are made available williamr@2: // under the terms of the License "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members williamr@2: // which accompanies this distribution, and is available williamr@2: // at the URL "http://www.symbianfoundation.org/legal/licencesv10.html". williamr@2: // williamr@2: // Initial Contributors: williamr@2: // Nokia Corporation - initial contribution. williamr@2: // williamr@2: // Contributors: williamr@2: // williamr@2: // Description: williamr@2: // williamr@2: williamr@2: #ifndef __MTSR_H__ williamr@2: #define __MTSR_H__ williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: // forward declarations williamr@2: class RWriteStream; williamr@2: class RReadStream; williamr@2: class RFs; williamr@2: class CDictionaryFileStore; williamr@2: class CInstalledMtmGroup; williamr@2: class CMsvServerEntry; williamr@2: class TMsvSystemProgress; williamr@2: williamr@2: class CBaseServerMtm : public CActive williamr@2: /** Base class for Server-side MTM components. Server-side MTMs provide all message williamr@2: transport functionality for a particular messaging protocol. williamr@2: williamr@2: MTM implementers implement a derived class to provide such functionality for williamr@2: their message protocol. Writers of message client applications are never concerned williamr@2: with this class and its sub-classes, as these are only accessed by the Message williamr@2: Server. williamr@2: williamr@2: Each MTM interprets the generic commands in different ways. For example, a williamr@2: Fax MTM would transmit a fax when asked to copy a fax from a local folder williamr@2: to a fax service. For the same function, an IMAP MTM would create a copy of williamr@2: the message on the remote server and update the message index to show the williamr@2: copy of the message on the remote server. An important initial design task williamr@2: is to the map the functions to the functionality provided by the protocol. williamr@2: williamr@2: Server-side MTM functions are called by the Message Server as a result of williamr@2: a client request that requires some remote operation with the MTM's protocol. williamr@2: The following steps give a simplified view of the usual sequence of events: williamr@2: williamr@2: 1. the Message Server instantiates a Server-side MTM object through the factory williamr@2: function williamr@2: williamr@2: 2. the Message Server calls the appropriate asynchronous function on the Server-side williamr@2: MTM interface, passing a TRequestStatus argument williamr@2: williamr@2: 3. the Server-side MTM function typically starts whatever asynchronous communications williamr@2: it requires and returns williamr@2: williamr@2: 4. the Server-side MTM is signalled when the asynchronous communications complete, williamr@2: and handles the result williamr@2: williamr@2: 5. the Server-side MTM signals the Message Server, through the TRequestStatus williamr@2: passed earlier williamr@2: williamr@2: 6. the Message Server deletes the Server-side MTM object williamr@2: williamr@2: To qualify this somewhat: williamr@2: williamr@2: 1. it is up to the Server-side MTM implementation to decide how to translate williamr@2: data back and forth between the formats used by Message Server (index entry, williamr@2: message store, binary files), and that required by the protocol; this is another williamr@2: important design task williamr@2: williamr@2: 2. depending on the protocol being used, the communications sequence can be of williamr@2: considerable complexity; typically it requires division into a number of asynchronous williamr@2: steps williamr@2: williamr@2: 3. for greater efficiency where further commands are shortly expected, deletion williamr@2: of the Server-side MTM object can be prevented williamr@2: williamr@2: For asynchronous requests, a Server-side MTM should always complete the TRequestStatus williamr@2: with KErrNone. Any errors should be returned in the progress information. williamr@2: williamr@2: Note the following significant groups of functions: williamr@2: williamr@2: 1. Copy and move from remote functions: CopyToLocalL() and MoveToLocalL() are williamr@2: called by the Message Server to get a selection of entries from a remote location. williamr@2: For many protocols, this should be interpreted as message retrieval. For protocols williamr@2: where messages exist on a remote server, this function is typically used to williamr@2: download specific messages, after an initial connection has downloaded message williamr@2: headers. williamr@2: williamr@2: 2. Copy and move to remote functions: CopyFromLocalL() and MoveFromLocalL() are williamr@2: called by the Message Server to copy/move a selection of entries to a remote williamr@2: location. For many protocols, this should be interpreted as message sending. williamr@2: williamr@2: 3. Copy and move within remote functions: CopyWithinServiceL() and MoveWithinServiceL() williamr@2: are called by the Message Server to copy a selection of entries within a remote williamr@2: service. An example of their use might be for a user rearranging messages williamr@2: within remote folders. williamr@2: @publishedAll williamr@2: @released williamr@2: */ williamr@2: { williamr@2: public: williamr@2: IMPORT_C ~CBaseServerMtm(); williamr@2: // williamr@2: /** Copies a selection of entries from a remote location to a local location. This williamr@2: will only be meaningful for some protocols. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: retrieval of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: Implementations of this function have three fundamental steps: williamr@2: williamr@2: 1. doing the transfer operation using the appropriate communications protocols williamr@2: williamr@2: 2. converting protocol-specific data into the three-part storage format (index williamr@2: entry, message store, binary files) required by the Message Server williamr@2: williamr@2: 3. updating entries in the Message Server williamr@2: williamr@2: @param aSelection The collection of message index entries for which the copy/moving williamr@2: is required. williamr@2: @param aDestination The entry ID to which the selection is to be copied williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void CopyToLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: /** Copies a selection of entries from a local location to a remote location. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: retrieval of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: Implementations of this function have three fundamental steps: williamr@2: williamr@2: 1. reading entry data williamr@2: williamr@2: 2. converting entry data from the Message Server format into that required by williamr@2: the protocol williamr@2: williamr@2: 3. doing the transfer operation using the appropriate communications protocols williamr@2: williamr@2: @param aSelection The collection of message index entries for which the copy williamr@2: is required williamr@2: @param aDestination The entry ID of the service by which the entries should williamr@2: be transferred williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void CopyFromLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: /** Copies a selection of entries within a remote location. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: the ability to copy entries within a remote service. If this is not supported, williamr@2: implementations should leave with KErrNotSupported. williamr@2: williamr@2: @param aSelection The collection of message index entries for which the copy williamr@2: is required williamr@2: @param aDestination The server entry ID to which the selection is to be copied williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void CopyWithinServiceL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: /** Deletes each entry in the supplied selection when called by the message Server. williamr@2: If any of the entries in the selection is a parent entry, then all its children williamr@2: should also be deleted, recursively to the bottom of the ownership tree. williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: deletion of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: @param aSelection The collection of entries that are to be deleted. williamr@2: @param aStatus Asynchronous completion object. williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void DeleteAllL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)=0; williamr@2: /** Creates a new remote entry with relevant data when called by the Message Server. williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: creation of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: As with ChangeL(), the Server-side MTM implementation must decide what information williamr@2: in the TMsvEntry is relevant to the remote entry, and translate it appropriately williamr@2: for the specific protocol. Most of the data contained in the TMsvEntry is williamr@2: specific to the Message Server, and would probably have no direct correlation williamr@2: with the protocol's own storage format. For example, for a folder, probably williamr@2: only the name and parent are needed, so if the protocol supports creation williamr@2: of remote folders, the implementation could: williamr@2: williamr@2: 1. check for a folder type entry williamr@2: williamr@2: 2. get the folder name and parent details from aNewEntry williamr@2: williamr@2: 3. initiate a protocol-specific action to create the remote folder williamr@2: williamr@2: @param aNewEntry Data by which to create entry williamr@2: @param aStatus Asynchronous completion word for the operation. williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void CreateL(TMsvEntry aNewEntry, TRequestStatus& aStatus)=0; williamr@2: /** Updates a remote entry with relevant data when called by the Message Server. williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: updating of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: The Server-side MTM implementation must decide what information in the TMsvEntry williamr@2: is relevant to the remote entry, and translate it appropriately for the specific williamr@2: protocol. Most of the data contained in the TMsvEntry is specific to the Symbian williamr@2: OS Message Server, and would probably have no direct correlation with the williamr@2: protocol's own storage format. Some entry data may however be useful. For williamr@2: example, if the protocol supports remote renaming of folders, the implementation williamr@2: could: williamr@2: williamr@2: 1. check for a folder type entry williamr@2: williamr@2: 2. extract the folder name from aNewEntry.iDetails williamr@2: williamr@2: 3. check if the folder name has changed by comparing the new name with iDetails williamr@2: in the index entry currently; if not, complete with KErrNone williamr@2: williamr@2: 4. initiate a protocol-specific action to rename the remote folder williamr@2: williamr@2: The implementation should also always update the local Message Server index williamr@2: through CMsvServerEntry::ChangeL(). williamr@2: williamr@2: @param aNewEntry Data by which to update entry williamr@2: @param aStatus Asynchronous completion word for the operation. williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void ChangeL(TMsvEntry aNewEntry, TRequestStatus& aStatus)=0; williamr@2: // williamr@2: /** Executes an MTM-specific operation on a selection of entries when called by williamr@2: the Message Server. williamr@2: williamr@2: The call is made as a response to a client program invoking an MTM-specific williamr@2: operation through CBaseMtm::InvokeSyncFunctionL()/InvokeAsyncFunctionL(). williamr@2: The aSelection, aCommand, and aParameter arguments pass the values of the williamr@2: original aSelection, aFunctionId, and aParameter respectively arguments from williamr@2: such a call. The use (if any) of the aSelection and aParameter arguments by williamr@2: the function depends on the command. williamr@2: williamr@2: @param aSelection A selection of message entries on which the command is to williamr@2: be executed williamr@2: @param aCommand The MTM-specific command to be carried out williamr@2: @param aParameter Command-specific parameters williamr@2: @param aStatus Asynchronous completion word for the operation */ williamr@2: virtual void StartCommandL(CMsvEntrySelection& aSelection, TInt aCommand, const TDesC8& aParameter, TRequestStatus& aStatus)=0; williamr@2: // williamr@2: /** Tests if the Server-side MTM object should be deleted when called by the Message williamr@2: Server williamr@2: williamr@2: It is useful to stop the MTM being deleted when more commands are expected williamr@2: shortly. This would be the case, for example, after receiving a command to williamr@2: go online. williamr@2: williamr@2: If there are no more commands expected by the Server-side MTM object, then williamr@2: the function should return EFalse, and the Message Server will delete it. williamr@2: williamr@2: @return ETrue: the MTM object should not be deleted EFalse: the MTM object williamr@2: can be deleted */ williamr@2: virtual TBool CommandExpected()=0; williamr@2: // williamr@2: /** This function is called by the Message Server to get progress information for williamr@2: the current asynchronous operation. williamr@2: williamr@2: The call is made as a response to a client program requesting progress information williamr@2: through CMsvOperation::ProgressL(). The packing format used in the TDesC8 williamr@2: is MTM-specific. Only the implementation of the User Interface MTM progress williamr@2: information functions need to understand the format. williamr@2: williamr@2: The progress buffer should have a maximum size of 256 bytes. williamr@2: williamr@2: @return Progress information on current asynchronous operation williamr@2: @see CBaseMtmUi::DisplayProgressSummary() williamr@2: @see CBaseMtmUi::GetProgress() */ williamr@2: virtual const TDesC8& Progress()=0; williamr@2: // williamr@2: /** Moves a selection of entries from a remote location to a local location. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: retrieval of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: Implementations of this function have three fundamental steps: williamr@2: williamr@2: 1. doing the transfer operation using the appropriate communications protocols williamr@2: williamr@2: 2. converting protocol-specific data into the three-part storage format (index williamr@2: entry, message store, binary files) required by the Message Server williamr@2: williamr@2: 3. updating entries in the Message Server williamr@2: williamr@2: MoveToLocalL() should differ from CopyToLocalL() in additionally deleting williamr@2: the original remote data. williamr@2: williamr@2: @param aSelection The collection of message index entries for which the moving williamr@2: is required. williamr@2: @param aDestination The entry ID to which the selection is to be copied/moved williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void MoveToLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: /** Moves a selection of entries from a local location to a remote location. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: retrieval of remote entries. If this is not supported, implementations should williamr@2: leave with KErrNotSupported. williamr@2: williamr@2: Implementations of this function have three fundamental steps: williamr@2: williamr@2: 1. reading entry data williamr@2: williamr@2: 2. converting entry data from the Message Server format into that required by williamr@2: the protocol williamr@2: williamr@2: 3. doing the transfer operation using the appropriate communications protocols williamr@2: williamr@2: The implementation of MoveFromLocalL() should differ from CopyFromLocalL() williamr@2: in additionally deleting the original local data. williamr@2: williamr@2: @param aSelection The collection of message index entries for which the move williamr@2: is required williamr@2: @param aDestination The entry ID of the service by which the entries should williamr@2: be transferred williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void MoveFromLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: /** Moves a selection of entries within a remote location. williamr@2: williamr@2: Requirements: williamr@2: williamr@2: Implementations should provide this function if the messaging protocol supports williamr@2: the ability to move entries within a remote service. If this is not supported, williamr@2: implementations should leave with KErrNotSupported. williamr@2: williamr@2: The implementation of MoveWithinServiceL() should differ from CopyWithinServiceL() williamr@2: in additionally deleting the original data. williamr@2: williamr@2: @param aSelection The collection of message index entries for which the move williamr@2: is required williamr@2: @param aDestination The server entry ID to which the selection is to be moved williamr@2: @param aStatus Asynchronous completion word for the operation williamr@2: @leave KErrNotSupported The Server-side MTM does not support this operation williamr@2: @leave Other leave codes Dependent on implementation */ williamr@2: virtual void MoveWithinServiceL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)=0; williamr@2: williamr@2: IMPORT_C TInt SystemProgress(TMsvSystemProgress& aOutSysProg); williamr@2: TInt GetNonOperationMtmData(TNonOperationMtmDataType& aMtmDataType, TPtrC8& aResultBuffer); williamr@2: williamr@2: protected: williamr@2: IMPORT_C CBaseServerMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvServerEntry* aServerEntry); williamr@2: /** Handles the completion of any asynchronous requests that it makes. It is called williamr@2: from the base class RunL() . williamr@2: williamr@2: Note that any leaves made by this function result in DoComplete() being called williamr@2: with the leave code. */ williamr@2: virtual void DoRunL()=0; williamr@2: /** Called by the base class RunL() if DoRunL() leaves. williamr@2: williamr@2: It should be implemented to handle this error. For example, progress information williamr@2: could be updated to reflect the problem. williamr@2: williamr@2: @param aError The leave code given by DoRunL(). */ williamr@2: virtual void DoComplete(TInt aError)=0; williamr@2: // williamr@2: IMPORT_C TInt Extension_(TUint aExtensionId, TAny *&a0, TAny *a1); williamr@2: // williamr@2: private: williamr@2: // from CActive williamr@2: IMPORT_C void RunL(); williamr@2: IMPORT_C TInt RunError(TInt aError); williamr@2: // williamr@2: protected: williamr@2: /** The entry on which to operate. It is set in the constructor. williamr@2: williamr@2: The destructor deletes this member. */ williamr@2: CMsvServerEntry* iServerEntry; williamr@2: williamr@2: // Method used for extension: called by non virtual methods that need williamr@2: // to have a polymorphic behaviour. williamr@2: IMPORT_C virtual TAny* GetInterface(TUid aUid); williamr@2: // williamr@2: private: williamr@2: CRegisteredMtmDll& iRegisteredMtmDll; williamr@2: williamr@2: private: williamr@2: // Extra data member to allow for future extensions williamr@2: TAny* iExtensionData; williamr@2: }; williamr@2: williamr@2: williamr@2: class CServerMtmDllRegistry : public CMtmDllRegistry williamr@2: /** williamr@2: @publishedAll williamr@2: @released williamr@2: */ williamr@2: { williamr@2: friend class CMtmRegistryControl; williamr@2: public: williamr@2: IMPORT_C static CServerMtmDllRegistry* NewL(RFs& aFs,TTimeIntervalMicroSeconds32 aTimeoutMicroSeconds32=KMsvDefaultTimeoutMicroSeconds32); williamr@2: IMPORT_C ~CServerMtmDllRegistry(); williamr@2: IMPORT_C CBaseServerMtm* NewServerMtmL(TUid aMtmTypeUid, CMsvServerEntry* aInitialEntry); williamr@2: // williamr@2: protected: williamr@2: CServerMtmDllRegistry(RFs& aFs,TTimeIntervalMicroSeconds32 aTimeoutMicroSeconds32); williamr@2: // williamr@2: private: williamr@2: CBaseServerMtm* NewMtmL(const RLibrary& aLib, CMsvServerEntry* aServerEntry, CRegisteredMtmDll& aReg) const; williamr@2: }; williamr@2: williamr@2: williamr@2: class CInstalledMtmGroupArray : public CArrayPtrFlat williamr@2: /** williamr@2: @internalComponent williamr@2: @released williamr@2: */ williamr@2: { williamr@2: public: williamr@2: CInstalledMtmGroupArray(); williamr@2: ~CInstalledMtmGroupArray(); williamr@2: void AddInstalledMtmGroupL(CInstalledMtmGroup* aInstalledMtmGroup); williamr@2: }; williamr@2: williamr@2: //********************************** williamr@2: // CMsvMtmCache williamr@2: //********************************** williamr@2: williamr@2: williamr@2: //********************************** williamr@2: // CMtmRegistryControl williamr@2: //********************************** williamr@2: williamr@2: class CMtmRegistryControl : public CBase, public MRegisteredMtmDllObserver williamr@2: /** williamr@2: @publishedAll williamr@2: @released williamr@2: */ williamr@2: { williamr@2: public: williamr@2: IMPORT_C static CMtmRegistryControl* NewL(RFs& anFs,CServerMtmDllRegistry& aServerMtmDllRegistry); williamr@2: IMPORT_C ~CMtmRegistryControl(); williamr@2: williamr@2: IMPORT_C TInt InstallMtmGroup(const TDesC& aFullName,TUid& aMtmTypeUid); williamr@2: IMPORT_C TInt FullNameToMtmTypeUid(const TDesC& aFullName,TUid& aMtmTypeUid) const; williamr@2: IMPORT_C TInt DeInstallMtmGroup(TUid aMtmTypeUid); // returns error on storing registry williamr@2: williamr@2: IMPORT_C TInt UseMtmGroup(TUid aMtmTypeUid); williamr@2: IMPORT_C TInt ReleaseMtmGroup(TUid aMtmTypeUid); williamr@2: IMPORT_C TBool IsInUse(TUid aMtmTypeUid) const; williamr@2: williamr@2: IMPORT_C TInt FillRegisteredMtmDllArray(TUid aMtmDllTypeUid,CRegisteredMtmDllArray& aRegisteredMtmDllArray,TTimeIntervalMicroSeconds32 aTimeoutMicroSeconds32=0); // Fill array with Dlls whose second uid is aMtmDllTypeUid williamr@2: IMPORT_C CMtmGroupData* GetMtmGroupDataL(TUid aMtmTypeUid) const; williamr@2: const CMtmGroupData& GetMtmGroupDataReferenceL(TUid aMtmTypeUid) const; williamr@2: williamr@2: IMPORT_C void StoreRegistryL() const; williamr@2: IMPORT_C void RestoreRegistryL(); williamr@2: williamr@2: IMPORT_C void InternalizeL(RReadStream& aStream); williamr@2: IMPORT_C void ExternalizeL(RWriteStream& aStream) const; williamr@2: williamr@2: private: williamr@2: CMtmRegistryControl(RFs& anFs,CServerMtmDllRegistry& aServerMtmDllRegistry); williamr@2: void ConstructL(); williamr@2: TInt MtmTypeUidToIndex(TUid aMtmTypeUid) const; williamr@2: TInt UidTypeToIndex(TUidType aUidType) const; williamr@2: void DoInstallMtmGroupL(const TDesC& aFullName,TUid& aMtmTypeUid); williamr@2: CMtmGroupData* ReadDataFileStoreL(const TDesC& aFullName) const; williamr@2: void DoDeInstallMtmGroupL(TUid aMtmTypeUid); williamr@2: void DoInternalizeL(RReadStream& aStream); williamr@2: void AddInstalledMtmGroupL(CInstalledMtmGroup* aInstalledMtmGroup); williamr@2: void RemoveInstalledMtmGroup(TUid aMtmTypeUid); williamr@2: TBool IsResFileL(const TDesC& aFullName) const; williamr@2: TUid DoFindMtmTypeUidL(const TDesC& aFullName) const; williamr@2: williamr@2: CMtmGroupData *LoadMTMFileL(const TDesC& aFullName, TUid &aUid); williamr@2: CMtmGroupData *LoadDatFileL(const TDesC& aFullName, TUid &aUid); williamr@2: CMtmGroupData *LoadResFileL(const TDesC& aFullName, TUid &aUid); williamr@2: private: williamr@2: RFs& iFs; williamr@2: CInstalledMtmGroupArray iInstalledMtmGroupArray; williamr@2: CServerMtmDllRegistry& iServerMtmDllRegistry; williamr@2: }; williamr@2: williamr@2: #endif // __MTSR_H__