localisation/apparchitecture/apparc/apaproc.cpp
branchSymbian3
changeset 57 b8d18c84f71c
equal deleted inserted replaced
56:aa99f2208aad 57:b8d18c84f71c
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // apaproc.cpp
       
    15 //
       
    16 
       
    17 #include <apaproc.h> // stuff everyone will want ie most things
       
    18 #include <apacln.h> // CleanupStack protection for CApaDocument
       
    19 #include "APADLL.H" // class RApaApplication
       
    20 #include "APASTD.H" // Panics etc.
       
    21 #include <s32file.h>
       
    22 #include "../apparc/TRACE.H"
       
    23 #include <e32def_private.h> // MattR addition for __PROFILE_END error
       
    24 
       
    25 const TInt KAppProcessArrayGranularity(1);
       
    26 
       
    27 
       
    28 //
       
    29 // CApaParentProcessMonitor
       
    30 //
       
    31 
       
    32 class CApaParentProcessMonitor : public CActive
       
    33 	{
       
    34 public: // Construction / destruction
       
    35 	static CApaParentProcessMonitor* NewL(TProcessId aProcessId);
       
    36 	~CApaParentProcessMonitor();
       
    37 	void ConstructL();
       
    38 private:
       
    39 	CApaParentProcessMonitor(TProcessId aProcessId);
       
    40 public: // From CActive
       
    41 	void RunL();
       
    42 	void DoCancel();
       
    43 private:
       
    44 	TProcessId iProcessId;
       
    45 	RProcess iProcess;
       
    46 	};
       
    47 
       
    48 CApaParentProcessMonitor* CApaParentProcessMonitor::NewL(TProcessId aProcessId)
       
    49 	{
       
    50 	CApaParentProcessMonitor* self=new (ELeave) CApaParentProcessMonitor(aProcessId);
       
    51 	CleanupStack::PushL(self);
       
    52 	self->ConstructL();
       
    53 	CleanupStack::Pop(self);
       
    54 	return self;
       
    55 	}
       
    56 
       
    57 CApaParentProcessMonitor::CApaParentProcessMonitor(TProcessId aProcessId)
       
    58 	: CActive(EPriorityLow)
       
    59 	{
       
    60 	iProcessId=aProcessId;
       
    61 	}
       
    62 
       
    63 CApaParentProcessMonitor::~CApaParentProcessMonitor()
       
    64 	{
       
    65 	Cancel();
       
    66 	}
       
    67 
       
    68 void CApaParentProcessMonitor::ConstructL()
       
    69 	{
       
    70 	User::LeaveIfError(iProcess.Open(iProcessId));
       
    71 	iProcess.Logon(iStatus);
       
    72 	if(iStatus==KErrNoMemory)
       
    73 		{
       
    74 		User::WaitForRequest(iStatus);
       
    75 		User::Leave(KErrNoMemory);
       
    76 		}
       
    77 	CActiveScheduler::Add(this);
       
    78 	SetActive();
       
    79 	}
       
    80 
       
    81 void CApaParentProcessMonitor::RunL()
       
    82 	{
       
    83 	// Do something that will kill the child when the parent process terminates
       
    84 	if(iStatus==KErrNone)
       
    85 		{
       
    86 		RProcess proc;
       
    87 		proc.Terminate(KErrNone);
       
    88 		}
       
    89 	}
       
    90 
       
    91 void CApaParentProcessMonitor::DoCancel()
       
    92 	{
       
    93 	iProcess.LogonCancel(iStatus);
       
    94 	}
       
    95 
       
    96 //
       
    97 // CApaProcess
       
    98 //
       
    99 
       
   100 /** Constructor for CApaProcess */
       
   101 EXPORT_C CApaProcess::CApaProcess()
       
   102 	{
       
   103 	}
       
   104 
       
   105 EXPORT_C CApaProcess* CApaProcess::NewL(const RFs& aFs)
       
   106 /** Creates and returns a pointer to a new application process.
       
   107 
       
   108 This function is not used by UI applications.
       
   109 
       
   110 @param aFs Handle to a file server session.
       
   111 @return Pointer to the new application process. */
       
   112 	{
       
   113 	CApaProcess* self=new(ELeave) CApaProcess(aFs);
       
   114 	CleanupStack::PushL(self);
       
   115 	self->ConstructL();
       
   116 	CleanupStack::Pop();
       
   117 	return self;
       
   118 	}
       
   119 
       
   120 EXPORT_C CApaProcess::CApaProcess(const RFs& aFs)
       
   121 	:iFsSession(aFs)
       
   122 /** Constructs the application process object with the specified file session handle.
       
   123 
       
   124 Derived classes must define and implement a constructor through which 
       
   125 the file session handle can be specified. A 
       
   126 typical implementation calls this constructor through a constructor initialization 
       
   127 list.
       
   128 
       
   129 This constructor is used by the UI framework.
       
   130 
       
   131 @deprecated
       
   132 @param aFs Handle to a file server session */
       
   133 	{}
       
   134 
       
   135 const TInt KPriorityGreaterThanShutter=102;
       
   136 
       
   137 EXPORT_C void CApaProcess::ConstructL()
       
   138 /** Completes construction of the application process object.
       
   139 
       
   140 Implementers of derived classes must call this function as part of the second 
       
   141 stage construction of an object. Typically, derived classes implement their 
       
   142 own NewL() function and call ConstructL() as part of that implementation. */
       
   143 	{
       
   144 	//
       
   145 	iAppList = new(ELeave) CArrayPtrFlat<RApaApplication>(KAppProcessArrayGranularity);
       
   146 	iDocList = new(ELeave) CArrayPtrFlat<CApaDocument>(KAppProcessArrayGranularity);
       
   147 	iMainDocFileName = HBufC::NewL(KMaxFileName);
       
   148 	iAsyncAppRemover = CIdle::NewL(KPriorityGreaterThanShutter);	// Use an idle object so that app has chance to clear its call stack
       
   149 	}
       
   150 
       
   151 EXPORT_C void CApaProcess::ConstructL(TProcessId aParentProcessId)
       
   152 /** Completes construction of the application process object, passing in a Parent Process Identifier.
       
   153 
       
   154 Implementers of derived classes must call this function as part of the second 
       
   155 stage construction of an object. Typically, derived classes implement their 
       
   156 own NewL() function and call ConstructL() as part of that implementation.
       
   157 
       
   158 @param aParentProcessId Id of the parent process. This process will terminate when the parent does. */
       
   159 	{
       
   160 	ConstructL();
       
   161 	if(KNullProcessId!=aParentProcessId)
       
   162 		{
       
   163 		iMonitor=CApaParentProcessMonitor::NewL(aParentProcessId);
       
   164 		}
       
   165 	}
       
   166 
       
   167 /** Frees resources prior to destruction.
       
   168 
       
   169 Documents must be saved before the application process is deleted, otherwise 
       
   170 data may be lost.
       
   171 
       
   172 In debug mode, the destructor raises an APPARC 6 panic if documents still 
       
   173 exist, and an APPARC 5 panic if applications still exist. */
       
   174 EXPORT_C CApaProcess::~CApaProcess()
       
   175 // If this is called without calling ResetL() or CApaDocument::SaveL() first, data may be lost
       
   176 //
       
   177 	{
       
   178 	if (iMainDoc)
       
   179 		{
       
   180 		DestroyDocument(iMainDoc);
       
   181 		iMainDoc = NULL;
       
   182 		}
       
   183 
       
   184 	if (iDocList)
       
   185 		{
       
   186 		__ASSERT_DEBUG(iDocList->Count()==0,Panic(EPanicDocListNotEmpty));
       
   187 		for (TInt i=iDocList->Count()-1 ; i>=0 ; i--)
       
   188 			delete (*iDocList)[i]; // delete stray doc's in release mode, just to be tidy
       
   189 		}
       
   190 
       
   191 	if (iAppList)
       
   192 		{
       
   193 		for (TInt i = iAppList->Count()-1 ; i >= 0 ; i--)
       
   194 			(*iAppList)[i]->Close();
       
   195 		}
       
   196 
       
   197 	delete iAppList;
       
   198 	delete iDocList;
       
   199 	delete iMainDocFileName;
       
   200 	delete iAsyncAppRemover;
       
   201 	delete iMonitor;
       
   202 	}
       
   203 
       
   204 
       
   205 /** Resets the the application process to its initial state.
       
   206 
       
   207 Specifically, it saves the main document, deletes the main and all embedded 
       
   208 documents from memory, resets the main document filename and deletes all applications 
       
   209 except the main application.
       
   210 
       
   211 The function can leave if saving the main document fails. */
       
   212 EXPORT_C void CApaProcess::ResetL()
       
   213 	{
       
   214 	if (iMainDoc)
       
   215 		{
       
   216 		iMainDoc->SaveL();
       
   217 		DeleteAllDocs(); // sets iMainDoc to NULL, deletes all apps except main
       
   218 		}
       
   219 		
       
   220 	__ASSERT_DEBUG(iMainDocFileName, Panic(EPanicNoDocument));
       
   221 	*iMainDocFileName = KNullDesC;
       
   222 	}
       
   223 
       
   224 
       
   225 void CApaProcess::DeleteAllDocs()
       
   226 // deletes all docs
       
   227 // deletes all apps except main app
       
   228 // sets iMainDoc* to NULL
       
   229 //
       
   230 	{
       
   231 	CApaApplication* mainApp = NULL;
       
   232 	
       
   233 	// If the main document has been constructed...
       
   234 	if (iMainDoc) // then iDocList must also exist
       
   235 		{
       
   236 		__ASSERT_DEBUG(iMainDoc->Application(), Panic(EDPanicNoApp));
       
   237 		mainApp = iMainDoc->Application();
       
   238 		
       
   239 		// ...find the main document in the list of documents and delete it.
       
   240 		for (TInt i = iDocList->Count()-1; i >= 0; i--)
       
   241 			{
       
   242 			if ((*iDocList)[i] == iMainDoc)
       
   243 				{
       
   244 				iDocList->Delete(i); // removes from array, but doesnt destroy
       
   245 				delete iMainDoc;
       
   246 				iMainDoc = NULL;
       
   247 				break;
       
   248 				}
       
   249 			}
       
   250 		}
       
   251 	
       
   252 	// Remove all documents from the list of documents, without deleting them.
       
   253 	if(iDocList)	
       
   254 		{
       
   255 		__ASSERT_ALWAYS(iDocList->Count()==0, Panic(EPanicDocListNotEmpty));
       
   256 		iDocList->Reset();
       
   257 		}
       
   258 
       
   259 	// Delete all applications except the main one.
       
   260 	if(iAppList)
       
   261 		{
       
   262 		for (TInt ii = iAppList->Count()-1; ii >= 0; ii--) // need to iterate backwards as the array changes size during the loop
       
   263 			{
       
   264 			if ((*iAppList)[ii]->Application() != mainApp)
       
   265 				{
       
   266 				(*iAppList)[ii]->Close();
       
   267 				iAppList->Delete(ii);
       
   268 				}
       
   269 			}
       
   270 	
       
   271 		iAppList->Compress();
       
   272 		}
       
   273 	}
       
   274 
       
   275 
       
   276 EXPORT_C void CApaProcess::SetMainDocFileName(const TDesC& aMainDocFileName)
       
   277 /** Sets the filename of the main document.
       
   278 
       
   279 @param aMainDocFileName The filename to be set.
       
   280 @panic APPARC 7 If the length of aMainDocFileName is greater than KMaxFileName or the
       
   281 length of the last filename set by SetMainDocFileNameL if greater
       
   282 @see KMaxFileName */
       
   283 	{
       
   284 	__ASSERT_DEBUG( iMainDocFileName, Panic(EPanicNullPointer));
       
   285 	__ASSERT_ALWAYS( aMainDocFileName.Length()<=iMainDocFileName->Des().MaxLength() ,Panic(EPanicFileNameTooLong));
       
   286 	*iMainDocFileName = aMainDocFileName;
       
   287 	}
       
   288 
       
   289 EXPORT_C void CApaProcess::SetMainDocFileNameL(const TDesC& aMainDocFileName)
       
   290 /** Sets the filename of the main document.
       
   291 
       
   292 @param aMainDocFileName The filename to be set. There is no restriction on the
       
   293 length of this descriptor. */
       
   294 	{
       
   295 	__ASSERT_ALWAYS( iMainDocFileName, Panic(EPanicNullPointer));
       
   296 	const TInt newLength = aMainDocFileName.Length() < KMaxFileName ? KMaxFileName : aMainDocFileName.Length();
       
   297 	if (newLength != iMainDocFileName->Des().MaxLength())
       
   298 		{
       
   299 		HBufC* const newMainDocFileName = HBufC::NewL(newLength);
       
   300 		delete iMainDocFileName;
       
   301 		iMainDocFileName = newMainDocFileName;
       
   302 		}
       
   303 	SetMainDocFileName(aMainDocFileName);
       
   304 	}
       
   305 
       
   306 /** Sets the main document.
       
   307 
       
   308 @param aDocument A pointer to the document to be set as the main document 
       
   309 of the application process. This must be a an object created by the AddNewDocumentL() 
       
   310 or OpenNewDocumentL() functions 
       
   311 @see CApaProcess::AddNewDocumentL()
       
   312 @see CApaProcess::OpenNewDocumentL() */
       
   313 EXPORT_C void CApaProcess::SetMainDocument(CApaDocument* aDocument)
       
   314 	{
       
   315 	__ASSERT_ALWAYS( iDocList, Panic(EPanicNullPointer));
       
   316 	// check that the prospective main doc has actually been added to the array
       
   317 	for (TInt i = iDocList->Count()-1 ; i >= 0 ; i--)
       
   318 		{
       
   319 		if ((*iDocList)[i] == aDocument)
       
   320 			break;
       
   321 		
       
   322 		if (i==0)
       
   323 			Panic(EPanicNoDocument);
       
   324 		}
       
   325 	
       
   326 	// assign it once it has checked out
       
   327 	iMainDoc = aDocument;
       
   328 	}
       
   329 
       
   330 /** Creates and adds a new document using the specified application factory.
       
   331 
       
   332 The document may be a main document or an embedded document.
       
   333 
       
   334 Any document created with this function must be destroyed using DestroyDocument().
       
   335 
       
   336 @param aApplicationFactory Should be created implicitly by passing a pointer to
       
   337 a factory function, an ECOM plugin UID, or a CImplementationInformation reference.
       
   338 @return A pointer to the new document.
       
   339 @see CApaProcess::DestroyDocument()
       
   340 @see CApaApplication */
       
   341 EXPORT_C CApaDocument* CApaProcess::AddNewDocumentL(TApaApplicationFactory aApplicationFactory)
       
   342 	{
       
   343 	__SHOW_TRACE(_L("Starting CApaProcess::AddNewDocumentL"));
       
   344 	__APA_PROFILE_START(0);
       
   345 
       
   346 	RApaApplication* app = AddAppL(aApplicationFactory);	
       
   347 
       
   348 	// use the app to create a doc
       
   349 	CApaDocument* doc = NULL;
       
   350 	TRAPD(err, doc = CreateDocL(app->Application()));
       
   351 	if (err)
       
   352 		RemoveApp(app);	// remove app as it has been orphaned
       
   353 	
       
   354 	User::LeaveIfError(err);
       
   355 	__PROFILE_END(0);
       
   356 	return doc;
       
   357 	} //lint !e1762 Member function could be made const - Not true
       
   358 
       
   359 
       
   360 
       
   361 void CApaProcess::RemoveApp(RApaApplication* aApp)
       
   362 // removes app exe from the list if it exists, panics otherwise
       
   363 	{
       
   364 	__ASSERT_ALWAYS(iAppList, Panic(EPanicNullPointer));
       
   365 	TInt i = 0;
       
   366 	for (i = iAppList->Count()-1; i >= 0; i--)
       
   367 		{
       
   368 		if ((*iAppList)[i] == aApp) // the main app may be alive on its own if Reset() has just been called
       
   369 			{
       
   370 			aApp->Close(); // the main app may be alive on its own if Reset() has just been called
       
   371 			iAppList->Delete(i);
       
   372 			break;
       
   373 			}
       
   374 		}
       
   375 		
       
   376 	if (i < 0)
       
   377 		Panic(EPanicAppNotInList);
       
   378 	}
       
   379 
       
   380 
       
   381 /** Opens the specified file and restores the content as a document.
       
   382 
       
   383 The created document can be merged into or embedded in another document.
       
   384 
       
   385 Any document created with this function must be destroyed using DestroyDocument().
       
   386 
       
   387 @param aStore On return, this contains a pointer to the store object created 
       
   388 during the restore.
       
   389 @param aStreamDic On return, this contains a pointer to the stream dictionary 
       
   390 object created during the restore. 
       
   391 @param aDocFullFileName The name of the file containing the document. 
       
   392 @param aFileMode The mode in which to open the file. 
       
   393 @return A pointer to the restored document.
       
   394 @see TFileMode
       
   395 @see CApaProcess::DestroyDocument() */
       
   396 EXPORT_C CApaDocument* CApaProcess::OpenNewDocumentL(CFileStore*& aStore,CStreamDictionary*& aStreamDic,const TDesC& aDocFullFileName,TUint aFileMode)
       
   397 	{
       
   398 	__SHOW_TRACE(_L("Starting CApaProcess::OpenNewDocumentL"));
       
   399 	__APA_PROFILE_START(1);
       
   400 	TParse parser;
       
   401 	User::LeaveIfError(iFsSession.Parse(aDocFullFileName,parser)); 
       
   402 	// open doc as a file store & read in the header
       
   403 	CFileStore* docStore;
       
   404 	CStreamDictionary* streamDic = ReadRootStreamLC(FsSession(),docStore,parser.FullName(),aFileMode);
       
   405 	CleanupStack::PushL(docStore);
       
   406 	// read in the app id info
       
   407 	TApaAppIdentifier appId=ReadAppIdentifierL(*docStore,*streamDic);
       
   408 	// create the doc
       
   409 	CApaDocument* importedDoc =	AddNewDocumentL(appId.iAppUid);
       
   410 	// restore the document
       
   411 	TApaDocCleanupItem cleanup(this,importedDoc);
       
   412 	CleanupStack::PushL(cleanup);
       
   413 	importedDoc->RestoreL(*docStore,*streamDic);
       
   414 	CleanupStack::Pop(3); //docStore,importedDoc,streamDic
       
   415 	aStore = docStore;
       
   416 	aStreamDic = streamDic;
       
   417 	__PROFILE_END(1);
       
   418 	return importedDoc;
       
   419 	}
       
   420 
       
   421 /** Reads the application identifier from its stream in the specified store and 
       
   422 returns it.
       
   423 
       
   424 The location of the stream is found in the specified stream dictionary.
       
   425 
       
   426 @param aStore The store from which the application identifier should be read. 
       
   427 @param aStreamDic The stream dictionary containing the stream ID of the application 
       
   428 identifier stream. The stream dictionary can be found in the root stream of 
       
   429 the store.
       
   430 @return The application identifier. */
       
   431 EXPORT_C TApaAppIdentifier CApaProcess::ReadAppIdentifierL(const CStreamStore& aStore,const CStreamDictionary& aStreamDic)
       
   432 	{
       
   433 	// this is a static method
       
   434 	__SHOW_TRACE(_L("Starting CApaProcess::ReadAppIdentifierL"));
       
   435 	
       
   436 	TStreamId infoStreamId = aStreamDic.At(KUidAppIdentifierStream);
       
   437 	TApaAppIdentifier appId;
       
   438 	
       
   439 	// create a stream and read in the data
       
   440 	RStoreReadStream stream;
       
   441 	stream.OpenLC(aStore,infoStreamId);
       
   442 
       
   443 	stream >> appId;
       
   444 	stream.Close();
       
   445 
       
   446 	CleanupStack::PopAndDestroy(); // stream
       
   447 	return appId;	
       
   448 	}
       
   449 
       
   450 
       
   451 /** Writes the application identifier to a new stream in the specified store and 
       
   452 records the location of this stream in the specified stream dictionary.
       
   453 
       
   454 @param aStore The store to which the application identifier should be written. 
       
   455 
       
   456 @param aStreamDic The stream dictionary. 
       
   457 @param aAppId The application identifier to be externalised to a stream. */
       
   458 EXPORT_C void CApaProcess::WriteAppIdentifierL(CStreamStore& aStore,CStreamDictionary& aStreamDic,const TApaAppIdentifier& aAppId)
       
   459 	{
       
   460 	// this is a static method
       
   461 	__SHOW_TRACE(_L("Starting CApaProcess::WriteAppIdentifierL"));
       
   462 	
       
   463 	// create a stream
       
   464 	RStoreWriteStream stream;
       
   465 	TStreamId streamId = stream.CreateLC(aStore);
       
   466 	
       
   467 	// stream the header
       
   468 	stream << aAppId;
       
   469 	stream.CommitL();
       
   470 	
       
   471 	CleanupStack::PopAndDestroy(); // id stream
       
   472 	// enter the stream in the dictionary
       
   473 	aStreamDic.AssignL(KUidAppIdentifierStream, streamId);
       
   474 	}
       
   475 
       
   476 
       
   477 /** Reads the stream dictionary contained as the root stream in the specified document 
       
   478 file.
       
   479 
       
   480 The function constructs, and returns a pointer to the stream dictionary object 
       
   481 and puts the pointer to the stream dictionary object onto the cleanup stack. 
       
   482 It also returns a pointer to the created file store object through an argument 
       
   483 reference. 
       
   484 
       
   485 The file must be a valid document file; otherwise the function leaves with one of 
       
   486 the system-wide error codes.
       
   487 
       
   488 @param aFs Handle to a file server session.
       
   489 @param aStore On return, a pointer to the newly created file store object. 
       
   490 @param aDocFullFileName The full path name of the document file. 
       
   491 @param aFileMode The mode in which to open the file.
       
   492 @return A pointer to the stream dictionary object read from the root stream 
       
   493 of the store. 
       
   494 @see TFileMode */
       
   495 EXPORT_C CStreamDictionary* CApaProcess::ReadRootStreamLC(RFs& aFs,CFileStore*& aStore,const TDesC& aDocFullFileName,TUint aFileMode)
       
   496 	{ // static
       
   497 	__SHOW_TRACE(_L("Starting CApaProcess::ReadRootStreamLC (file-name overload)"));
       
   498 	CStreamDictionary* const streamDictionary=CStreamDictionary::NewLC();
       
   499 	CFileStore* const store=CFileStore::OpenLC(aFs,aDocFullFileName,aFileMode);
       
   500 	DoReadRootStreamL(*streamDictionary, *store);
       
   501 	aStore=store; // delay assignment until nothing can go wrong to avoid destroying the store twice if a leave occurs
       
   502 	CleanupStack::Pop(store);
       
   503 	return streamDictionary;
       
   504 	}
       
   505 
       
   506 
       
   507 /**
       
   508 @internalTechnology
       
   509 */
       
   510 EXPORT_C CStreamDictionary* CApaProcess::ReadRootStreamLC(CFileStore*& aStore, const RFile& aFile)
       
   511 	{ // static
       
   512 	__SHOW_TRACE(_L("Starting CApaProcess::ReadRootStreamLC (file-handle overload)"));
       
   513 
       
   514 	CStreamDictionary* const streamDictionary = CStreamDictionary::NewLC();
       
   515 	
       
   516 	RFile duplicateFile;
       
   517 	CleanupClosePushL(duplicateFile);
       
   518 	User::LeaveIfError(duplicateFile.Duplicate(aFile)); // this is because CFileStore::FromLC closes the file its passed (and stores its own duplicate)
       
   519 	
       
   520 	CFileStore* const store = CFileStore::FromL(duplicateFile);
       
   521 	CleanupStack::PopAndDestroy(&duplicateFile);
       
   522 	
       
   523 	CleanupStack::PushL(store);
       
   524 	DoReadRootStreamL(*streamDictionary, *store);
       
   525 	aStore = store; // delay assignment until nothing can go wrong to avoid destroying the store twice if a leave occurs
       
   526 	CleanupStack::Pop(store);
       
   527 	
       
   528 	return streamDictionary;
       
   529 	}
       
   530 
       
   531 
       
   532 void CApaProcess::DoReadRootStreamL(CStreamDictionary& aStreamDictionary, const CFileStore& aStore)
       
   533 	{ // static
       
   534 	const TStreamId rootStreamId=aStore.Root();
       
   535 	if ((aStore.Type()[1] != KUidAppDllDoc) || (rootStreamId == KNullStreamId))
       
   536 		User::Leave(KErrCorrupt);
       
   537 	
       
   538 	RStoreReadStream rootStream;
       
   539 	rootStream.OpenLC(aStore, rootStreamId);
       
   540 	rootStream >> aStreamDictionary;
       
   541 	CleanupStack::PopAndDestroy(&rootStream);
       
   542 	}
       
   543 
       
   544 
       
   545 /** Writes the application identifier (derived from the application object CApaApplication) 
       
   546 followed by the stream dictionary to the store and makes the stream dictionary the root stream of the
       
   547 store.
       
   548 
       
   549 Typically, the function is called by the application when it 
       
   550 implements a file create or file save type operation. It is called after all 
       
   551 model and UI data has been persisted. The IDs of the streams containing the 
       
   552 model and UI data should have been lodged in the stream dictionary.
       
   553 
       
   554 In effect, the function finishes off the file save or file
       
   555 create type operation, leaving the file containing the store in a valid state
       
   556 with the standard interface.
       
   557 
       
   558 @param aStore  The store to which the root stream is to be written. Before
       
   559 calling this function, a reference to the store must be saved by putting a
       
   560 pointer onto the cleanup stack or by making it member data of a class. This
       
   561 ensures that it is not orphaned in the event of this function leaving.
       
   562 @param aStreamDic The stream dictionary containing the locations and associated 
       
   563 UIDs of other streams in the store.
       
   564 @param aApp  The application used to create the main document in the file
       
   565 being written. The application identifier to be written is constructed from
       
   566 this application object. */
       
   567 EXPORT_C void CApaProcess::WriteRootStreamL(CPersistentStore& aStore,CStreamDictionary& aStreamDic,const CApaApplication& aApp)
       
   568 	{ // this is a static method
       
   569 	__SHOW_TRACE(_L("Starting CApaProcess::WriteRootStreamL(app)"));
       
   570 	// get the app dll name
       
   571 	TParse dllPath;
       
   572 	dllPath.SetNoWild(aApp.DllName(),NULL,NULL);
       
   573 	// set up an app identifier
       
   574 	TApaAppIdentifier appId(aApp.AppDllUid(),dllPath.NameAndExt());
       
   575 	// Write the root stream
       
   576 	WriteRootStreamL(aStore,aStreamDic,appId);
       
   577 	}
       
   578 
       
   579 
       
   580 /** Writes the application identifier followed by the stream dictionary 
       
   581 to the store and makes the stream dictionary the root stream of the store.
       
   582 
       
   583 Typically, the function is called by the application when it 
       
   584 implements a file create or file save type operation. It is called after all 
       
   585 model and UI data has been persisted. The IDs of the streams containing the 
       
   586 model and UI data should have been lodged in the stream dictionary.
       
   587 
       
   588 In effect, the function finishes off the file save or file
       
   589 create type operation, leaving the file containing the store in a valid state
       
   590 with the standard interface.
       
   591 
       
   592 @param aStore  The store to which the root stream is to be written. Before
       
   593 calling this function, a reference to the store must be saved by putting a
       
   594 pointer onto the cleanup stack or by making it member data of a class. This
       
   595 ensures that it is not orphaned in the event of this function leaving.
       
   596 @param aStreamDic The stream dictionary containing the locations and associated 
       
   597 UIDs of other streams in the store.
       
   598 @param aAppId  The application identifier to be written into the application
       
   599 identifier stream. */
       
   600 EXPORT_C void CApaProcess::WriteRootStreamL(CPersistentStore& aStore,CStreamDictionary& aStreamDic,const TApaAppIdentifier& aAppId)
       
   601 	{ // this is a static method
       
   602 	__SHOW_TRACE(_L("Starting CApaProcess::WriteRootStreamL(id)"));
       
   603 	// create a stream
       
   604 	WriteAppIdentifierL(aStore,aStreamDic,aAppId);
       
   605 	
       
   606 	// externalize the dictionary
       
   607 	RStoreWriteStream stream;
       
   608 	TStreamId streamId = stream.CreateLC(aStore);
       
   609 	stream << aStreamDic;
       
   610 	stream.CommitL();
       
   611 	CleanupStack::PopAndDestroy(); // dictionary stream
       
   612 	
       
   613 	// set the dictionary stream as the root stream
       
   614 	aStore.SetRootL(streamId);
       
   615 	}
       
   616 
       
   617 
       
   618 /** Destroys the specified document.
       
   619 
       
   620 All references to the document are removed, and associated resources are freed. 
       
   621 Specifically, the function deletes any associated application and unloads 
       
   622 the application DLL, provided that no other documents of that application 
       
   623 type are still open.
       
   624 
       
   625 All document objects created through CApaProcess must be deleted using this 
       
   626 function.
       
   627 
       
   628 @param aDoc A pointer to the document to be destroyed. 
       
   629 @see CApaApplication
       
   630 @see CApaProcess */
       
   631 EXPORT_C void CApaProcess::DestroyDocument(CApaDocument* aDoc)
       
   632 	{
       
   633 	__SHOW_TRACE(_L("Starting CApaProcess::DestroyDocument(app)"));
       
   634 
       
   635 	if(!aDoc)
       
   636 		return;
       
   637 	
       
   638 	// delete the doc, keeping a handle to its app
       
   639 	CApaApplication* const app = aDoc->Application();
       
   640 	__ASSERT_DEBUG(app, Panic(EDPanicDocWithNoApp));
       
   641 	
       
   642 	// remove the doc from the list, keeping a handle to the doc
       
   643 	TBool appStillRequired = EFalse;
       
   644 	__ASSERT_ALWAYS(iDocList, Panic(EPanicNullPointer));
       
   645 	for (TInt i = iDocList->Count()-1; i >= 0; i--)
       
   646 		{ // check through the list, remove the right doc, and see if the app is used by any other docs
       
   647 		if((*iDocList)[i] == aDoc)
       
   648 			{
       
   649 			iDocList->Delete(i); // removes from array, but doesnt destroy
       
   650 			iDocList->Compress();
       
   651 			}
       
   652 		else if ((*iDocList)[i]->Application() == app)
       
   653 			appStillRequired = ETrue;
       
   654 		}
       
   655 	
       
   656 	// Null the main doc handle if we are deleting the main doc
       
   657 	if (aDoc == iMainDoc)
       
   658 		iMainDoc = NULL;
       
   659 	
       
   660 	// Now delete the document
       
   661 	delete aDoc;
       
   662 	
       
   663 	// Remove app if no other doc's use it and it's not the main app
       
   664 	if (!appStillRequired && iMainDoc && app!=iMainDoc->Application())
       
   665 		{
       
   666 		MarkApplicationForAsyncRemoval(app);
       
   667 		__ASSERT_DEBUG(iAsyncAppRemover, Panic(EDPanicNoAppRemover));
       
   668 		
       
   669 		if (!iAsyncAppRemover->IsActive())
       
   670 			iAsyncAppRemover->Start(TCallBack(CApaProcess::IdleRemoveApplications, this));
       
   671 		}
       
   672 	}
       
   673 
       
   674 void CApaProcess::MarkApplicationForAsyncRemoval(const CApaApplication* aApp)
       
   675 // Mark the application in the app list for removal by idle object
       
   676 //
       
   677 	{
       
   678 	__ASSERT_DEBUG(aApp!=NULL,Panic(EDPanicRemovingNullApp));
       
   679 	__ASSERT_DEBUG(iAppList, Panic(EPanicNullPointer));
       
   680 	// remove the app from the list, keeping a handle to it
       
   681 	for (TInt i = iAppList->Count()-1 ; i >= 0 ; i--)
       
   682 		{
       
   683 		__ASSERT_DEBUG((*iAppList)[i], Panic(EDPanicNoAppHolder));
       
   684 		if ((*iAppList)[i]->Application() == aApp)
       
   685 			{
       
   686 			(*iAppList)[i]->ScheduleForAsyncDeletion();
       
   687 			return;
       
   688 			}
       
   689 		}
       
   690 	}
       
   691 
       
   692 TInt CApaProcess::IdleRemoveApplications(TAny* aApaProcess)
       
   693 // Remove applications on callback of idle object. Using an idle object gives an embedded application a chance to clear
       
   694 // its call stack before its dll is closed
       
   695 //
       
   696 	{
       
   697 	CApaProcess* process = reinterpret_cast<CApaProcess*>(aApaProcess);
       
   698 	__ASSERT_DEBUG(process, Panic(EDPanicNoProcess));
       
   699 	process->RemoveMarkedApplications();
       
   700 	
       
   701 	return KErrNone;
       
   702 	}
       
   703 
       
   704 
       
   705 void CApaProcess::RemoveMarkedApplications()
       
   706 // Remove any applications that have been marked for removal, closing their dlls also
       
   707 //
       
   708 	{
       
   709 	__ASSERT_DEBUG(iAppList, Panic(EPanicNullPointer));
       
   710 	for (TInt i = iAppList->Count()-1; i >= 0; i--)
       
   711 		{
       
   712 		if ((*iAppList)[i]->IsScheduleForAsyncDeletion())
       
   713 			{
       
   714 			(*iAppList)[i]->Close();
       
   715 			iAppList->Delete(i); // remove from array
       
   716 			}
       
   717 		}
       
   718 	
       
   719 	iAppList->Compress();
       
   720 	}
       
   721 
       
   722 
       
   723 CApaDocument* CApaProcess::CreateDocL(CApaApplication* aApp)
       
   724 // creates a new doc with aApp and adds it to the list before returning a handle to it
       
   725 //
       
   726 	{
       
   727 	__SHOW_TRACE(_L("Starting CApaProcess::CreateDocL"));
       
   728 	__ASSERT_DEBUG(aApp, Panic(EDPanicNoApp));
       
   729 
       
   730 	// create a new doc with the app
       
   731 	CApaDocument* doc = aApp->CreateDocumentL(this); //lint !e613 Possible use of null pointer - Asserted above
       
   732 	__ASSERT_ALWAYS(doc, Panic(EPanicDocumentNotCreated));
       
   733 
       
   734 	// add the doc to the list
       
   735 	CleanupStack::PushL(doc);
       
   736 	iDocList->AppendL(doc);
       
   737 	CleanupStack::Pop(); // doc
       
   738 
       
   739 	// return a	handle to the doc
       
   740 	return doc;
       
   741 	}
       
   742 
       
   743 
       
   744 RApaApplication* CApaProcess::FindAppInListL(const TDesC& aAppFileName, TUid aUid) const
       
   745 // returns pointer to a matching app, or NULL if not in list
       
   746 //
       
   747 	{
       
   748 	__ASSERT_DEBUG(iAppList, Panic(EPanicNullPointer));
       
   749 
       
   750 	TInt index = iAppList->Count();
       
   751 	if (aUid!=KNullUid)
       
   752 		{// search by UID
       
   753 		while(--index >= 0)
       
   754 			{
       
   755 			__ASSERT_DEBUG((*iAppList)[index], Panic(EDPanicNoAppHolder));
       
   756 			if ((*iAppList)[index]->AppFileUid() == aUid)
       
   757 				{
       
   758 				(*iAppList)[index]->ScheduleForAsyncDeletion(EFalse);
       
   759 				return (*iAppList)[index]; // match found
       
   760 				}
       
   761 			}
       
   762 		}
       
   763 	else
       
   764 		{// search by name as no UID has been supplied
       
   765 		TParse app; 
       
   766 		TParse suspect;
       
   767 		User::LeaveIfError(app.Set(aAppFileName,NULL,NULL));
       
   768 		while (--index>=0)
       
   769 			{
       
   770 			__ASSERT_DEBUG((*iAppList)[index], Panic(EDPanicNoAppHolder));
       
   771 			suspect.SetNoWild((*iAppList)[index]->AppFileName(), NULL, NULL);
       
   772 			if (!app.Name().CompareF(suspect.Name()))
       
   773 				{
       
   774 				(*iAppList)[index]->ScheduleForAsyncDeletion(EFalse);
       
   775 				return (*iAppList)[index]; // match found
       
   776 				}
       
   777 			}
       
   778 		}
       
   779 		
       
   780 	return NULL; // no match found
       
   781 	}
       
   782 
       
   783 RApaApplication* CApaProcess::AddAppL(TApaApplicationFactory aApplicationFactory)
       
   784 	{
       
   785 	RApaApplication* app = new (ELeave) RApaApplication;
       
   786 	CleanupClosePushL(*app);
       
   787 	
       
   788 	// create the app
       
   789 	app->CreateApplicationL(aApplicationFactory);
       
   790 	__ASSERT_DEBUG(app->Application(), Panic(EPanicNullPointer));
       
   791 	app->Application()->PreDocConstructL();
       
   792 	
       
   793 	// add the application to the list and return a pointer to it
       
   794 	__ASSERT_DEBUG(iAppList, Panic(EPanicNullPointer));
       
   795 	iAppList->AppendL(app);
       
   796 	
       
   797 	CleanupStack::Pop(app);
       
   798 	return app;
       
   799 	}
       
   800 
       
   801 EXPORT_C TPtrC CApaProcess::MainDocFileName()const
       
   802 /** Returns the filename of the main document.
       
   803 
       
   804 @return A non-modifiable pointer descriptor to the main document filename. 
       
   805 For non file-based applications, the length of this descriptor is zero. */
       
   806 	{
       
   807 	if (iMainDocFileName)
       
   808 		return *iMainDocFileName;
       
   809 	
       
   810 	return KNullDesC();
       
   811 	}
       
   812 
       
   813 /** Reserved for future use */
       
   814 EXPORT_C void CApaProcess::CApaProcess_Reserved1()
       
   815 	{
       
   816 	}
       
   817 
       
   818 /** Reserved for future use */
       
   819 EXPORT_C void CApaProcess::CApaProcess_Reserved2()
       
   820 	{
       
   821 	}
       
   822 
       
   823 
       
   824