// EIKDLL.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikdll.h>
#include <f32file.h>
#include <bautils.h>
#include <basched.h>
#include <eikenv.h>
#include <eikpanic.h>
#include <eikon.rsg>

const TInt KDefaultMinHeapSize=0x10000; // !! for now
const TInt KDefaultMaxHeapSize=0x200000; // !! for now

#if defined(__WINS__)
typedef TInt (*ExeEntryPoint)();

TInt ExeThreadStartFunction(TAny* aParam)
	{
	const TDesC& libraryName=(*(const TDesC*)aParam);
	RLibrary lib;
	TInt err=lib.Load(libraryName);
	User::Free(aParam);
	if (!err)
		{
		ExeEntryPoint exeFunc=(ExeEntryPoint)lib.Lookup(1);
		if (!exeFunc)
			err=KErrBadLibraryEntryPoint;
		else
			err=(*exeFunc)();
		}
	return(err);
	}
#endif

EXPORT_C TThreadId EikDll::StartExeL(const TDesC& aName)
	{ // static !! later combine parts with other StartXxxL functions
	TParse fileName;
	TThreadId threadId;
#if defined(__WINS__)
	TPtrC path=_L("Z:\\SYSTEM\\PROGRAMS\\.DXE");
	User::LeaveIfError(fileName.Set(aName,&path,NULL));
	RThread process;
#else
	TPtrC tempDes=_L("Z:\\SYSTEM\\PROGRAMS\\.EXE");
	User::LeaveIfError(fileName.Set(aName,&tempDes,NULL));
	RProcess process;
#endif
#if defined(__WINS__)
	TBuf<KMaxFileName> threadName;
	TPtrC baseName=fileName.Name();
	TInt err;
	TInt num=0;
	do
		{
		threadName.Format(_L("%S%02d"),&baseName,num++);
		err=process.Create(threadName,ExeThreadStartFunction,KDefaultStackSize,KDefaultMinHeapSize,KDefaultMaxHeapSize,NULL);
		} while(err==KErrAlreadyExists);
	User::LeaveIfError(err);
	RHeap* heap=process.Heap();
	RHeap* originalHeap=User::SwitchHeap(heap);
	HBufC* commandLine=fileName.FullName().Alloc();
	User::SwitchHeap(originalHeap);
	if (!commandLine)
		{
		process.Close();
		User::LeaveNoMemory();
		}
	process.SetInitialParameter(commandLine);
	threadId = process.Id();
#else
	TInt err=process.Create(fileName.FullName(),TPtrC());
	User::LeaveIfError(err);
	// get the threadId of the main thread in the exe's process
	TFullName fullName(process.Name());
	fullName.Append(_L("::Main"));
	TFindThread fT(fullName);
	fT.Next(fullName);
	RThread thread;
	thread.Open(fT);
	threadId = thread.Id();
	thread.Close();
#endif
	process.Resume();
	process.Close();
	return threadId;
	}

EXPORT_C void EikDll::RunAppInsideThread(CApaCommandLine* aCommandLine)
	{ // static
    CEikonEnv* coe=new CEikonEnv;
	if (!coe)
		Panic(EEikPanicStartupHeapTooSmall);
	TPtrC libName=aCommandLine->LibraryName();
	if (libName.Length())
		{
		TParsePtrC parse(libName);
		RThread().Rename(parse.Name());
		}
	TRAPD(err,coe->ConstructAppFromCommandLineL(*aCommandLine));
	delete aCommandLine;
    if (!err)
        coe->ExecuteD();
	else if (err!=KLeaveWithoutAlert && err!=KLeaveExit)
		{
		TRAPD(ignore,coe->HandleError(err));
		}
	}

#if defined(__WINS__)
TInt AppThreadStartFunction(TAny* aParam)
	{
	EikDll::RunAppInsideThread((CApaCommandLine*)aParam);
	return(0);
	}
#endif

EXPORT_C TThreadId EikDll::StartAppL(const CApaCommandLine& aCommandLine)
	{ // static
	TPtrC fullCmdLine=aCommandLine.FullCommandLine();
	if (fullCmdLine.Length()>KMaxCommandLine)
		{ // RProcess::Create() would panic on ARM
		RFs fs;
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TFileName fileName(_L("z:\\System\\Data\\eikon.rsc"));
		BaflUtils::NearestLanguageFile(fs,fileName);
		RResourceFile resourceFile;
		resourceFile.OpenL(fs,fileName);
		CleanupClosePushL(resourceFile);
		resourceFile.ConfirmSignatureL(0);
		TBuf<80> buf;
#if defined(_UNICODE)
		TPtr8 readBuffer((TText8* )buf.Ptr(),buf.MaxSize());
		resourceFile.ReadL(readBuffer,R_EIK_TBUF_FILENAME_TOO_LONG);
		buf.SetLength((readBuffer.Length()+1)>>1);
#else
		resourceFile.ReadL(buf,R_EIK_TBUF_FILENAME_TOO_LONG);
#endif
		CleanupStack::PopAndDestroy(2); // close resourceFile, fs

		RNotifier notifier;
		if (!(notifier.Connect()))
			{
			notifier.InfoPrint(buf); 
			notifier.Close();
			}

		CBaActiveScheduler::LeaveNoAlert();
		}
	TThreadId id;
#if defined(__WINS__)
	RThread process;
#else
	RProcess process;
#endif
#if defined(__WINS__)
	TBuf<KMaxFileName> threadName;
	TInt err;
	TInt num=0;
	do
		{
		threadName.Format(_L("AppRun%02d"),num++);
		err=process.Create(threadName,AppThreadStartFunction,KDefaultStackSize,KDefaultMinHeapSize,KDefaultMaxHeapSize,NULL);
		} while(err==KErrAlreadyExists);
	User::LeaveIfError(err);
	RHeap* heap=process.Heap();
	RHeap* originalHeap=User::SwitchHeap(heap);
	CApaCommandLine* commandLine=NULL;
	TRAP(err, commandLine=CApaCommandLine::NewL(fullCmdLine)); // err ignored
	User::SwitchHeap(originalHeap);
	if (!commandLine)
		{
		process.Close();
		User::LeaveNoMemory();
		}
	process.SetInitialParameter(commandLine);
	id=process.Id();
#else
	TInt err=process.Create(_L("Z:\\SYSTEM\\PROGRAMS\\APPRUN.EXE"),fullCmdLine);
	User::LeaveIfError(err);
	TFullName fullName(process.Name());
	fullName.Append(_L("::Main"));
	TFindThread fT(fullName);
	fT.Next(fullName);
	RThread thread;
	thread.Open(fT);
	id=thread.Id();
	thread.Close();
#endif
	process.Resume();
	process.Close();
	return(id);
	}

EXPORT_C void EikDll::StartDocL(const TDesC& aDocName)
	{
	CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
	cmdLine->SetCommandL(EApaCommandOpen);
	cmdLine->SetDocumentNameL(aDocName);
	StartAppL(*cmdLine);
	CleanupStack::PopAndDestroy();
	}

