lowlevellibsandfws/pluginfw/Framework/frame/EComServerSession.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lowlevellibsandfws/pluginfw/Framework/frame/EComServerSession.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,658 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+// Description:
+// Server session object implementation.
+// 
+//
+
+#include "EComServerStart.h"
+#include "EComMessageIds.h"
+#include <ecom/ecomerrorcodes.h>
+#include <ecom/implementationinformation.h>
+#include "EComServerSession.h"
+#include "EComSessionAux.h"
+#include "EComServer.h"
+#include "TestUtilities.h"	// For __FILE__LINE__
+#include "EComPerformance.h"
+#include "EComDebug.h"
+
+//
+// RMessage::Panic() completes the message. This is:
+// (a) important for efficient cleanup within the kernel.
+// (b) a problem if the message is completed a second time.
+//
+void PanicClient(const TClientRequest& aMessage, TInt aPanicCode)
+	{
+	aMessage.Panic(KEComServerPanicCategory, aPanicCode);
+	}
+
+//
+//	class CEComServerSession
+//
+CEComServerSession::CEComServerSession()
+	: CSession2()
+	{
+	// Do nothing
+	}
+
+//
+// 2nd phase construct for sessions - called by the CServer framework
+//
+void CEComServerSession::CreateL()
+	{
+	Server().AddSession();
+	}
+
+CEComServerSession::~CEComServerSession()
+	{
+	CleanupInternalList();
+	CompleteNotifications(KErrCancel);
+	delete iMemoryStore;
+	Server().DropSession();
+	}
+
+//
+// Deliver the notification message to the client
+//
+void CEComServerSession::CompleteNotifications(TInt aCompletionCode)
+	{
+	const TInt count = iNotificationRequests.Count();
+	for(TInt i = 0; i < count; ++i)
+		{
+		  iNotificationRequests[i].iMessage.Complete(aCompletionCode);
+
+		}
+	iNotificationRequests.Reset();
+	}
+
+//
+// Handle a client request.
+// Leaving is handled by CEComServer::RunError() which reports the error code
+// to the client.
+//
+void CEComServerSession::ServiceL(const RMessage2& aMessage)
+{
+	const TClientRequest msg(aMessage);
+	ServiceL(msg);
+}
+
+void CEComServerSession::ServiceL(const TClientRequest& aMessage)
+	{
+	TInt completionCode = KErrNone;
+	TBool asyncRequest = EFalse;
+
+	switch (aMessage.Function())
+		{
+	case ENotifyOnChange:
+		{
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComNotifyOnChangeRequestType, Server().GetCurrentStartupState());
+		SEComNotification notif;
+		notif.iMessage=aMessage;
+		// the TRequestStatus as a TInt is stored for later comparisons
+		notif.iRequestStatusHandle=aMessage.Int0();
+		//Check that this TRequestStatus is not already being used.
+		const TInt count = iNotificationRequests.Count();
+		for(TInt i = 0; i < count; ++i)
+		{
+			if(iNotificationRequests[i].iRequestStatusHandle == notif.iRequestStatusHandle)
+				User::Leave(KErrArgument);
+
+		}
+		User::LeaveIfError(iNotificationRequests.Append(notif));
+		asyncRequest = ETrue;
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+		break;
+		}
+
+	case ECancelNotifyOnChange:
+			{
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCancelNotifyOnChangeRequestType, Server().GetCurrentStartupState());
+			TInt statusHandle = aMessage.Int0();
+
+			const TInt count = iNotificationRequests.Count();
+			for(TInt i = 0; i < count; ++i)
+				{
+				if(iNotificationRequests[i].iRequestStatusHandle == statusHandle)
+					{
+						iNotificationRequests[i].iMessage.Complete(KErrCancel);
+						iNotificationRequests.Remove(i);
+						break;  // Terminate the loop
+					}
+				}
+			}
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+		break;
+
+	case EListImplementations:
+	case EListResolvedImplementations:
+	case EListCustomResolvedImplementations:
+		if(Server().RegistryIndexValid())
+			{
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComListRequestType, Server().GetCurrentStartupState());
+			DoListImplementationsL(aMessage);
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+			}
+		else
+			{
+			if(ReceivePending())
+				User::Leave(KEComErrListInvalidAwaitNotification);
+			else
+				User::Leave(KEComErrListCurrentlyUnavailable);
+			}
+		break;
+
+	case ECollectImplementationsList:
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCollectImplementationsRequestType, Server().GetCurrentStartupState());
+		if(!DoCollectListL(aMessage))
+			completionCode = KErrNotReady;
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+		break;
+
+	case EGetImplementationCreationMethod:
+	case EGetResolvedCreationMethod:
+	case EGetCustomResolvedCreationMethod:
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCreateRequestType, Server().GetCurrentStartupState());
+		DoGetResolvedImplementationL(aMessage);
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+		break;
+
+	case EListExtendedInterfaces:
+RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComListExtendedInterfacesRequestType, Server().GetCurrentStartupState());
+		DoListExtendedInterfacesL(aMessage);
+RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
+		break;
+
+	case EEnableImplementation:
+	case EDisableImplementation:
+		// Ommissions for 6.2
+		completionCode = KErrNotSupported;
+		break;
+#if defined(__ECOM_SERVER_TESTABILITY__) || defined(__ECOM_SERVER_PERFORMANCE__)
+	case ESetGetParameters:
+		DoSetGetParametersL(aMessage);
+		break;
+#endif
+	//EDestroyedImplementation obsolete due to implementation creation
+	//relocation to client side from server
+	case EDestroyedImplementation:
+	default:
+		// Something badly wrong if we get here.
+		PanicClient(aMessage,KEComErrUnknownService);
+		// RMessage::Panic() has completed the message
+		// so treat this as an asynch request.
+		asyncRequest = ETrue;
+		}
+	if (!asyncRequest)
+		aMessage.Complete(completionCode);
+	}
+
+
+
+	
+TInt const KDefaultStoreSize = 256;	// Enough space for approx 1 implementation : will grow to fit if required
+
+/**
+UnPack the match string and extended interface from the client supplied parameters.
+@param			aMessage 
+@param			aExtendedInterfaces Return value consisting of an array containing the extended interfaces.
+@param			aMatchStr Return value consisting of the matching string.
+*/
+void CEComServerSession::UnpackMatchStrAndExtendedInterfacesFromClientL(const TClientRequest& aMessage,
+													RExtendedInterfacesArray& aExtendedInterfaces,
+													RBuf8& aMatchStr)
+	{
+	
+	//now get the matchString and extendedInterfaces
+	TInt sizeOfMatchStrExtInfBuf = aMessage.GetDesLength(KIPCParameterMatchStrExtInf);
+	User::LeaveIfError(sizeOfMatchStrExtInfBuf);
+	RBuf8 matchStrExtInfBuf;
+	matchStrExtInfBuf.CreateMaxL(sizeOfMatchStrExtInfBuf);
+	matchStrExtInfBuf.CleanupClosePushL();
+	
+	aMessage.ReadL(KIPCParameterMatchStrExtInf,matchStrExtInfBuf);
+	RDesReadStream readStream;
+	CleanupClosePushL(readStream);
+	readStream.Open(matchStrExtInfBuf);
+	TInt lenOfMatchStr = readStream.ReadInt32L();
+	aMatchStr.CreateMaxL(lenOfMatchStr);
+	aMatchStr.CleanupClosePushL();
+	if (lenOfMatchStr>0)
+		{
+		readStream.ReadL(aMatchStr,lenOfMatchStr);		
+		}
+	TInt numOfExtendedInterfaces = readStream.ReadInt32L();
+	CleanupClosePushL(aExtendedInterfaces);
+	for(TInt i = 0; i < numOfExtendedInterfaces; i++)
+		{
+		aExtendedInterfaces.AppendL(TUid::Uid(readStream.ReadInt32L()));
+		}
+	
+	CleanupStack::Pop(&aExtendedInterfaces);
+	CleanupStack::Pop(&aMatchStr);
+	CleanupStack::PopAndDestroy(&readStream);
+	CleanupStack::PopAndDestroy(&matchStrExtInfBuf); 
+	}
+
+
+// Note that this method for returning the arbitrary sized data set 
+// will not work IF the session is shared so...
+// DO NOT SHARE SERVER SIDE SESSIONS BETWEEN CLIENTS
+void CEComServerSession::DoListImplementationsL(const TClientRequest& aMessage)
+	{
+	// Unpack the client supplied parameters
+	// Firstly get the uids
+	TUidType uids;
+	TPckg<TUidType> uidsPkg(uids);	
+	aMessage.ReadL(KIPCParameterUids, uidsPkg);
+	
+	if(uids[KInterfaceUidIndex] == KNullUid)
+		{
+		User::Leave(KEComErrMissingParameter);
+		}
+
+	//now get the TListImplParam parameters
+  	TListImplParam listParam;
+  	TPckg<TListImplParam> listParamPkg(listParam);
+  	aMessage.ReadL(2,listParamPkg);
+	
+	// Now rebuild the TEComResolverParams
+	TEComResolverParams resolverParameters;
+	resolverParameters.SetGenericMatch(listParam.iMatchType);
+	
+	//now get the matchString and extendedInterfaces
+	RBuf8 matchStr;
+	RExtendedInterfacesArray extendedInterfaces;
+	UnpackMatchStrAndExtendedInterfacesFromClientL(aMessage,extendedInterfaces,matchStr);
+	matchStr.CleanupClosePushL();
+	CleanupClosePushL(extendedInterfaces);
+	
+	if(matchStr.Length()>0)
+		{	
+		resolverParameters.SetDataType(matchStr);
+		}
+	// Else the client's resolver params are default constructed i.e. invalid
+	// data type descriptor or its length is zero, so use empty RBuf8 above.
+	
+		
+	// Pass to the server
+	iListContext = aMessage.Function();
+	switch(iListContext)
+		{
+		case EListImplementations:
+			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], extendedInterfaces, aMessage );
+			break;
+		case EListResolvedImplementations:
+			if(matchStr.Length() == 0)
+				{
+				User::Leave(KEComErrMissingParameter);
+				}
+			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], resolverParameters, extendedInterfaces, aMessage);
+			break;
+		case EListCustomResolvedImplementations:
+			if(uids[KResolverUidIndex] == KNullUid)
+				{
+				User::Leave(KEComErrMissingParameter);
+				}
+			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], resolverParameters, uids[KResolverUidIndex], extendedInterfaces, aMessage);
+			break;
+		default:
+			break;
+		}
+	//Now cleanup the extended interface
+	CleanupStack::PopAndDestroy(&extendedInterfaces);
+	CleanupStack::PopAndDestroy(&matchStr);
+
+	TInt bufferSizeRequired=0;
+	// Package the array for return
+	if(iList)
+		{
+		if(iList->Count()>0)
+			{
+			// Allocate a new store and replace the old one first
+			CBufFlat* memoryStore = CBufFlat::NewL(KDefaultStoreSize);
+			delete iMemoryStore;
+			iMemoryStore = memoryStore;
+
+			// Note : There is no need to push
+			// the write stream onto the cleanup stack
+			// because it has no internal resources.
+			RBufWriteStream writeStream;
+			writeStream.Open(*iMemoryStore);
+
+			// Build the store data then calculate the end size;
+			const TInt entryCount = iList->Count();		
+			writeStream.WriteInt32L(entryCount);
+			
+			for(TInt i = 0; i < entryCount; ++i)
+				(*iList)[i]->ExternalizeL(ETrue,writeStream);
+	
+			writeStream.CommitL();
+
+			// Set to actual size
+			bufferSizeRequired=iMemoryStore->Size();
+			__ECOM_TRACE1("ECOM ListImplementations request buffer size required=%d",bufferSizeRequired);
+			}
+			CleanupInternalList();	
+		}
+	
+	//if nothing is returned we should still indicate this to the client side
+	if (bufferSizeRequired==0)
+		{
+		//write back the bufferSize
+		listParam.iBufferSize=0;
+  		aMessage.WriteL(2,listParamPkg);
+		return;
+		}
+		
+	//if the preallocated size is big enough to hold our entry
+	//copy it to the client
+	if (listParam.iBufferSize >= bufferSizeRequired)
+		{
+		if (iMemoryStore)
+			{
+			//write back the bufferSize
+			listParam.iBufferSize=bufferSizeRequired;
+  			aMessage.WriteL(2,listParamPkg);
+			TPtr8 data=iMemoryStore->Ptr(0);
+			aMessage.WriteL(3,data);
+			delete iMemoryStore;
+			iMemoryStore=NULL;
+			}
+		}
+	//if not rewrite back to the client the size that is required
+	//and signal with KErrOverFlow to the client
+	else
+		{
+		//write back the bufferSize
+		listParam.iBufferSize=bufferSizeRequired;
+  		aMessage.WriteL(2,listParamPkg);
+		User::Leave(KErrOverflow);
+		}
+	}
+
+TBool CEComServerSession::DoCollectListL(const TClientRequest& aMessage)
+	{
+	TBool success = EFalse;
+	if(iMemoryStore)
+		{
+		TPtr8 data=iMemoryStore->Ptr(0);
+		aMessage.WriteL(0, data);
+		delete iMemoryStore;
+		iMemoryStore = NULL;
+		success = ETrue;
+		}
+	return success;
+	}
+
+void CEComServerSession::DoGetResolvedImplementationL(const TClientRequest& aMessage)
+	{
+	// Unpack the client supplied parameters
+	// Firstly get the uids
+	TUidType uids;
+	TPckg<TUidType> uidsPkg(uids);
+	aMessage.ReadL(KIPCParameterUids, uidsPkg);
+
+	// Now rebuild the TEComResolverParams
+	TEComResolverParams resolverParameters;
+	resolverParameters.SetGenericMatch(KIPCParameterResolverParamsTypePtr);	
+	
+	//now get the matchString and extendedInterfaces
+	RBuf8 matchStr;
+	matchStr.CleanupClosePushL();
+	RExtendedInterfacesArray extendedInterfaces;
+	CleanupClosePushL(extendedInterfaces);
+	UnpackMatchStrAndExtendedInterfacesFromClientL(aMessage,extendedInterfaces,matchStr);
+    if(matchStr.Length()>0)
+		{	
+		resolverParameters.SetDataType(matchStr);
+		}
+	// Else the client's resolver params are default constructed i.e. invalid
+	// data type descriptor or its length is zero, so use empty HBufC8 above.
+	// Set up for the return value
+	TUid dtorIdKey(KNullUid);
+	TEntry loadInfo;
+	
+	switch(aMessage.Function())
+		{
+		case EGetImplementationCreationMethod:
+			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
+										 loadInfo, 
+										 dtorIdKey,
+										 aMessage);
+			break;
+		case EGetResolvedCreationMethod:
+			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
+										 resolverParameters, 
+										 extendedInterfaces,
+										 loadInfo, 
+										 dtorIdKey,
+										 aMessage);
+			break;
+		case EGetCustomResolvedCreationMethod:
+			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
+										 resolverParameters, 
+										 uids[KResolverUidIndex], 
+										 extendedInterfaces,
+										 loadInfo, 
+										 dtorIdKey,
+										 aMessage);
+			break;
+		default:
+			break;
+		}
+	CleanupStack::PopAndDestroy(&extendedInterfaces);
+	CleanupStack::PopAndDestroy(&matchStr);
+	
+// ??? Compile time assert that sizeof(TProxyNewLPtr) == sizeof(TAny*)?
+// Currently I'm not arranging for the client-side of the session to
+// convert from TAny* to TProxyNewLPtr, and using this to avoid the
+// full agony of following through with conversion...
+
+	// Then re-package the results for return
+	// Firstly the Interface Implementation creation method pointer
+	TPckg<TEntry> result(loadInfo);
+	
+	aMessage.WriteL(KIPCReturnParameterCreationMethodPtr, result);
+	// Next the destruction identification uid
+	TUidType type(KNullUid,dtorIdKey,KNullUid);
+	TPckg<TUidType> dtorIdKeyPkg(type);
+	
+	aMessage.WriteL(KIPCReturnParameterUidsPtr, dtorIdKeyPkg);
+	}
+
+// Return the list of interfaces to the client. If not enough space
+// has been allocated by the client, KErrOverflow will be returned.
+//
+void CEComServerSession::DoListExtendedInterfacesL(const TClientRequest& aMessage)
+	{
+	// Unpack the client supplied parameters
+	TInt bufferSize = 0;
+	TUid implementationUid(KNullUid);
+	TPckg<TUid> implementationUidDes(implementationUid);
+	TPckg<TInt> bufferSizeDes(bufferSize);
+	aMessage.ReadL(KIPCParameterImplementationUid,implementationUidDes);
+	aMessage.ReadL(KIPCParameterBufferSize,bufferSizeDes);
+		
+	// Get the implementation information for this implementation UID.
+	CImplementationInformation* implInfo = NULL;
+	Server().GetImplementationInformationL(implementationUid,implInfo,aMessage);
+	
+	TInt numExtendedInterfaces = 0; // Number of extended interfaces to return to client.
+
+	if(implInfo)
+		{
+		TInt bufferSizeRequired = 0; // Buffer required to send extended interface data back to client
+		
+		// Fetch the list of extended interfaces
+		RExtendedInterfacesArray* extendedInterfaceList = implInfo->GetExtendedInterfaceList();
+		if (extendedInterfaceList != NULL)
+			{
+			numExtendedInterfaces = extendedInterfaceList->Count();
+			}
+		if (numExtendedInterfaces > 0)
+			{
+			bufferSizeRequired = numExtendedInterfaces * sizeof(TUid);
+			__ECOM_TRACE1("ECOM ListInterfaces request buffer size required=%d",bufferSizeRequired);
+			
+			//if the preallocated size is big enough to hold our entry
+			//copy it to the client
+			if (bufferSize >= bufferSizeRequired)
+				{
+				RBuf8 buf;
+				CleanupClosePushL(buf);
+				buf.CreateL(bufferSizeRequired);   // Create the RBuf.
+				
+				// Note : There is no need to push the write stream onto the cleanup stack
+				// because it has no internal resources.
+				RDesWriteStream writeStream;
+				writeStream.Open(buf);
+
+				// Build the data of extendedInterfaces;
+				for(TInt i = 0; i < numExtendedInterfaces; ++i)
+					{
+					writeStream.WriteInt32L((*extendedInterfaceList)[i].iUid);
+					}
+
+				writeStream.CommitL();
+				
+				// Copy the data to the client.
+				bufferSize=bufferSizeRequired;
+				aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
+				aMessage.WriteL(KIPCParameterInterfaceData,buf);
+				
+				CleanupStack::PopAndDestroy(&buf);
+				}
+			//if not rewrite back to the client the size that is required
+			//and signal with KErrOverFlow to the client
+			else
+				{
+				bufferSize=bufferSizeRequired;
+				aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
+				User::Leave(KErrOverflow);
+				}
+			}
+		}
+		
+	//if nothing is returned we should still indicate this to the client side
+	if (numExtendedInterfaces == 0)
+		{
+		bufferSize=0;
+		aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
+		}
+	}
+
+#if defined(__ECOM_SERVER_TESTABILITY__) || defined(__ECOM_SERVER_PERFORMANCE__)
+/**
+This method is provided for testability. It allows the user to 
+send and receive any parameters. 
+@param aMessage IPC message between server and client
+*/
+void CEComServerSession::DoSetGetParametersL(const TClientRequest& aMessage)
+	{
+	TInt parameterType = aMessage.Int0();
+	
+	switch(parameterType)
+		{
+#ifdef __ECOM_SERVER_TESTABILITY__
+		case EChangeStartupState:
+			Server().ChangeStartupStateL(aMessage.Int1());
+			break;
+		case EProcessStartupState:
+			Server().ProcessCurrentStartupStateL();
+			break;
+		case EGetStartupState:
+			{
+			TInt state = Server().GetCurrentStartupState();
+			TPckg<TInt> pckgState(state);
+		    aMessage.Write(1, pckgState);
+			break;
+			}
+#endif
+#ifdef __ECOM_SERVER_PERFORMANCE__
+		case EGetStartupStateTimerResult:
+			{
+			TStartupStateTimerEntry timerEntry;
+			
+			TInt ret = EComPerformance::GetStartupStateTimerResult(aMessage.Int1(), timerEntry.iTimerResult, timerEntry.iState);
+			
+			TPckg<TInt> pckgRetValue(ret);
+			aMessage.Write(2, pckgRetValue);
+			TPckg<TStartupStateTimerEntry> pckgTimerEntry(timerEntry);
+			aMessage.Write(3, pckgTimerEntry);
+			break;
+			}
+
+		case EGetAccumulatedClientRequestsTimerResult:
+			{
+			TClientRequestTimerEntry timerEntry;
+			TInt ret = EComPerformance::GetAccumulatedClientRequestTimerResult(aMessage.Int1(), timerEntry);
+			TPckg<TInt> pckgRetValue(ret);
+			aMessage.Write(2, pckgRetValue);
+			TPckg<TClientRequestTimerEntry> pckgTimerEntry(timerEntry);
+			aMessage.Write(3, pckgTimerEntry);
+			break;
+			}
+		case EGetRegistryCounts:
+			{
+			RegistryCounts::TRegistryCounts counts;
+			Server().GetRegistryCountsL(aMessage.Int1(), counts);
+			TPckg<RegistryCounts::TRegistryCounts> pckgRegistryCounts(counts);
+			aMessage.Write(2, pckgRegistryCounts);
+			break;
+			}
+		case EResetStartupStateTimerCounts:
+			{
+			EComPerformance::ResetStartupStateTimerResult();
+			break;
+			}
+		case EGetEComPerfTimeRecord:
+			{
+			TEComPerfTimeRecordEntry timerEntry;
+			TInt ret = EComPerformance::GetEComPerfTimeRecord(aMessage.Int1(), timerEntry);
+			TPckg<TInt> pckgRetValue(ret);
+			aMessage.Write(2, pckgRetValue);
+			TPckg<TEComPerfTimeRecordEntry> pckgTimerEntry(timerEntry);
+			aMessage.Write(3, pckgTimerEntry);
+			break;
+			}
+		case EResetEComPerfTimeRecords:
+			{
+			EComPerformance::ResetEComPerfTimeRecords();
+			}
+		case EGetEComServerHeapResult:
+			{
+			TEComPerfHeapUsage heapEntry;
+			TInt ret= EComPerformance::GetEComHeapSize(aMessage.Int1(),heapEntry);
+			TPckg<TInt> pckgRetValue(ret);
+			aMessage.Write(2, pckgRetValue);
+			TPckg<TEComPerfHeapUsage> pckgHeapEntry(heapEntry);
+			aMessage.Write(3, pckgHeapEntry);
+			break;			
+			}
+#endif
+		default:
+			break;
+		}
+	}
+#endif
+
+void CEComServerSession::CleanupInternalList()
+	{
+	if (iList != NULL)
+		{
+		iList->Reset();
+		delete iList;
+		iList = NULL;
+		}
+	}
+