/*
* Copyright (c) 2005-2010 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: The executable that enables launching OMJ Java
* applications in S60
*
*/
#include <apacmdln.h>
#include <bacline.h>
#include <e32cmn.h>
#include <s32mem.h>
#include <unistd.h>
#include "commsmessage.h"
#include "commsclientendpoint.h"
#include "exceptionbase.h"
#include "javainifileutils.h"
#include "javaoslayer.h"
#include "javastorage.h"
#include "javastorageentry.h"
#include "javastoragenames.h"
#include "javasymbianoslayer.h"
#include "javauids.h"
#include "logger.h"
#include "rtcmessages.h"
#include "runtimeexception.h"
using namespace java::captain;
using namespace java::storage;
using namespace java::util;
_LIT(KHexValueStart, "0x");
_LIT(KPercentage, "%");
_LIT(KSemiColon, ";");
_LIT(KMidletNameArg, "midlet-name=");
_LIT(KMidletVendorArg, "midlet-vendor=");
_LIT(KMidletNArg, "midlet-n=");
_LIT(KMidletUidArg, "midlet-uid=");
const TInt KExtraLenForLoggingAndPrompting = 22;
const TInt KArgumentValueMaxLen = 1568; // Support worst case % encoded args of 512 chars
// The Uid of the Web Browser process
#define KBrowserUid 0x10008D39
/**
* Return the Uid of the application aMidletName in package aPackageId.
* If aMidletName is empty, return the Uid of the first application in
* package aPackageId.
*
* @param aJs JavaStorage connection, must be open
* @param aPackageId the id of the package
* @param aMidletId the numerical id of the desired application in the
* package, can be empty
* @param aUid the Uid the found application is returned in this param
* @return KErrNone if Uid was found, otherwise one of the Symbian error codes
* @throws JavaStorageException if accessing Java Storage fails
*/
static TInt getOneApplicationFromPackage(
JavaStorage& aJs,
const std::wstring& aPackageId,
const std::wstring& aMidletId,
TInt32 &aUid)
{
std::wstring midletId = L"MIDlet-";
if (aMidletId.length() == 0)
{
midletId.append(L"1");
}
else
{
midletId.append(aMidletId);
}
JavaStorageEntry attribute;
JavaStorageApplicationEntry_t findPattern;
JavaStorageApplicationList_t foundEntries;
// Get MIDlet-n from APPLICATION_PACKAGE_ATTRIBUTES_TABLE based on
// PACKAGE_ID and NAME.
attribute.setEntry(ID, aPackageId);
findPattern.insert(attribute);
attribute.setEntry(NAME, midletId);
findPattern.insert(attribute);
attribute.setEntry(VALUE, L"");
findPattern.insert(attribute);
aJs.search(APPLICATION_PACKAGE_ATTRIBUTES_TABLE, findPattern, foundEntries);
if (foundEntries.size() < 1)
{
return KErrNotFound;
}
// Found the MIDlet-n argument. Now getting the MIDlet name and
// main class. Name is the first argument and main class is the last
// in the comma separated list.
std::wstring value = foundEntries.front().begin()->entryValue();
int pos = value.find_first_of(L",");
std::wstring midletName = value.substr(0, pos);
pos = value.find_last_of(L",");
std::wstring className = value.substr(pos+1);
// Trim white spaces.
JavaCommonUtils::trimWstring(midletName, L' ');
JavaCommonUtils::trimWstring(className, L' ');
findPattern.clear();
foundEntries.clear();
// Get ID from APPLICATION_TABLE based on PACKAGE_ID and MAIN_CLASS
attribute.setEntry(PACKAGE_ID, aPackageId);
findPattern.insert(attribute);
attribute.setEntry(NAME, midletName);
findPattern.insert(attribute);
attribute.setEntry(MAIN_CLASS, className);
findPattern.insert(attribute);
attribute.setEntry(ID, L"");
findPattern.insert(attribute);
aJs.search(APPLICATION_TABLE, findPattern, foundEntries);
if (foundEntries.size() < 1)
{
return KErrNotFound;
}
std::wstring applicationId = foundEntries.front().begin()->entryValue();
TUid tmp;
TInt err = uidToTUid(applicationId, tmp);
if (KErrNone == err)
{
aUid = tmp.iUid;
}
return err;
}
/**
* Decode %XX encoded UTF-8 characters embedded to UCS-2
*
* @param aCmdLineBuf The command line to be decoded.
*/
static void decodeCommandLineL(TPtr &aCmdLineBuf)
{
TInt ind = aCmdLineBuf.Find(KPercentage);
if (KErrNotFound == ind)
{
// nothing to decode
return;
}
LOG(EJavaCaptain, EInfo,
"JavaLauncher:decodeCommandLineL convert percent encoded UTF-8 sequences to UTF-16 ");
try
{
std::wstring cmdLine = desToWstring(aCmdLineBuf);
std::wstring res = JavaCommonUtils::percentDecode(cmdLine);
LOG1WSTR(EJavaCaptain, EInfo,
"JavaLauncher:decodeCommandLineL: decoded command line is %s", res.c_str());
aCmdLineBuf = (const TUint16 *)res.c_str();
}
catch (std::exception& e)
{
ELOG1(EJavaCaptain,
"JavaLauncher:decodeCommandLineL: cannot decode command line: %s", e.what());
User::Leave(KErrGeneral);
}
}
/**
* Return the value of the argument specified by aArgName
*
* @param aMidletCmdLine command line to be parsed
* @param aArgName the name of the argument
* @return the value of the argument or empty wstring if no such argument
*/
static std::wstring getArgValue(const TPtrC &aMidletCmdLine, const TDesC &aArgName)
{
TBuf<KArgumentValueMaxLen> valueBuf;
TInt argPos = aMidletCmdLine.FindF(aArgName);
if (argPos >= 0)
{
TInt semicolonPos = aMidletCmdLine.Mid(argPos).Find(KSemiColon);
if (KErrNotFound == semicolonPos)
{
semicolonPos = aMidletCmdLine.Mid(argPos).Length();
}
TInt argLen = semicolonPos - aArgName.Length();
if (argLen >= KArgumentValueMaxLen)
{
// Protect from buffer overflow.
WLOG2(EJavaCaptain,
"javalauncher: argument value len too long (%d), cutting it to %d",
argLen, (KArgumentValueMaxLen - 1));
argLen = KArgumentValueMaxLen - 1;
}
valueBuf = aMidletCmdLine.Mid(argPos + aArgName.Length(), argLen);
}
valueBuf.Append('\0');
std::wstring value = (wchar_t *)&(valueBuf[0]);
return value;
}
/**
* Parse the names of the MIDlet suite and MIDlet vendor from aMidletCmdLine
* parameter and use them to find the MIDlet suite from Java Storage.
* Then return Uid of the named MIDlet or if 'midlet-app-name' argument is not given
* in command line, the Uid of the first MIDlet in the suite.
* Return the uid of the MIDlet in aUid.
*
* @param aMidletCmdLine the command line that contains at least midlet-name
* and midlet-vendor arguments
* @param aUid if the MIDlet is found from Java Storage, contains the Uid after return.
* @return KErrNone if MIDlet was found. KErrPathNotFound if MIDlet is not found.
* Standard Symbian error codes in other cases.
*/
static TInt getUidByNames(const TPtrC &aMidletCmdLine, TInt32 &aUid)
{
TInt err = aMidletCmdLine.FindF(KMidletNameArg);
if (KErrNotFound == err)
{
return KErrArgument;
}
err = aMidletCmdLine.FindF(KMidletVendorArg);
if (KErrNotFound == err)
{
return KErrArgument;
}
std::wstring suiteName = getArgValue(aMidletCmdLine, KMidletNameArg);
std::wstring vendorName = getArgValue(aMidletCmdLine, KMidletVendorArg);
std::wstring midletId = getArgValue(aMidletCmdLine, KMidletNArg);
if (suiteName.empty() || vendorName.empty())
{
return KErrArgument;
}
// Find application uid based on names from Java Storage
JavaStorage *js = JavaStorage::createInstance();
try
{
js->open(JAVA_DATABASE_NAME);
JavaStorageEntry attribute;
JavaStorageApplicationEntry_t findPattern;
JavaStorageApplicationList_t foundEntries;
// Search for package ID by PACKAGE_NAME and VENDOR from APPLICATION_PACKAGE_TABLE
attribute.setEntry(PACKAGE_NAME, suiteName);
findPattern.insert(attribute);
attribute.setEntry(VENDOR, vendorName);
findPattern.insert(attribute);
attribute.setEntry(ID, L"");
findPattern.insert(attribute);
js->search(APPLICATION_PACKAGE_TABLE , findPattern, foundEntries);
// Is anything found
if (foundEntries.size() > 0)
{
// The application package has been found, get the ID of the package
std::wstring value = foundEntries.front().begin()->entryValue();
LOG1WSTR(EJavaCaptain, EInfo,
"JavaLauncher: getUidByNamesL: Found suite uid by name. Uid is %s",
value.c_str());
// Now find the Uid of the first or specified application in the package
err = getOneApplicationFromPackage(*js, value, midletId, aUid);
}
else
{
err = KErrPathNotFound;
}
}
catch (JavaStorageException& e)
{
ELOG1(EJavaCaptain, "Java Storage exception %s", e.what());
err = KErrGeneral;
}
try
{
js->close();
}
catch (JavaStorageException& e2)
{
WLOG1(EJavaCaptain, "Java Storage exception when closing storage %s", e2.what());
}
delete js;
return err;
}
/**
* Check whether the MIDlet has been installed to device.
*
* @param aUid the Uid of the MIDlet to be checked
* @return KErrNone if the MIDlet has been installed,
* KErrNotFound if the MIDlet has not been installed,
* general Symbian error codes in case of error
*/
static TInt verifyAppExists(TInt32 aUid)
{
TInt err = KErrNone;
if (aUid == 0)
{
return KErrNotFound;
}
// Find application uid based on names from Java Storage
JavaStorage *js = JavaStorage::createInstance();
try
{
js->open(JAVA_DATABASE_NAME);
JavaStorageEntry attribute;
JavaStorageApplicationEntry_t findPattern;
JavaStorageApplicationList_t foundEntries;
// Search for application NAME by ID from APPLICATION_TABLE
Uid uid;
TUid tuid;
tuid.iUid = aUid;
TUidToUid(tuid, uid);
attribute.setEntry(ID, uid.toString());
findPattern.insert(attribute);
attribute.setEntry(NAME, L"");
findPattern.insert(attribute);
js->search(APPLICATION_TABLE , findPattern, foundEntries);
// Is anything found
if (foundEntries.size() > 0)
{
err = KErrNone;
}
else
{
err = KErrNotFound;
}
}
catch (JavaStorageException& e)
{
ELOG1(EJavaCaptain, "Java Storage exception %s", e.what());
err = KErrGeneral;
}
try
{
js->close();
}
catch (JavaStorageException& e2)
{
WLOG1(EJavaCaptain, "Java Storage exception when closing storage %s", e2.what());
}
delete js;
return err;
}
/**
* Either parse the Uid from the value of 'midlet-uid' parameter in
* command line given in aMidletCmdLine or find the midlet
* based on the 'midlet-name' and 'midlet-vendor' from
* Java Storage / AppArc and return the Uid of the midlet.
*
* @param aMidletCmdLine command line to be parsed, the format is
* [midlet-name=XXX;midlet-vendor=XXX;|midlet-uid=YYY;]<midlet_args>
* @param aUid will contain the Uid parsed from command line
* @return KErrNone if the command line specified Uid
*/
static TInt getUidFromCommandLine(const TPtrC &aMidletCmdLine, TInt32 &aUid)
{
TInt err(KErrNone);
TInt argPos = aMidletCmdLine.FindF(KMidletUidArg);
if (KErrNotFound != argPos)
{
TPtrC uidToParse = aMidletCmdLine.Mid(argPos + KMidletUidArg.iTypeLength);
TLex parseUid(uidToParse);
if (uidToParse.FindF(KHexValueStart) == 0)
{
parseUid.Inc(2); // skip hex prefix
TUint32 tmpValue;
err = parseUid.Val(tmpValue, EHex);
aUid = tmpValue;
}
else
{
err = parseUid.Val(aUid);
}
if (KErrNone != err)
{
ELOG1(EJavaCaptain,
"javalauncher failed parsing app Uid from cmdline midlet-uid param. Error %d",
err);
}
err = verifyAppExists(aUid);
}
else
{
err = getUidByNames(aMidletCmdLine, aUid);
if (KErrNone != err)
{
if (KErrArgument == err)
{
// In this case the Uid is not in opaque data and there are
// no midlet-uid or midlet-name + midlet-vendor parameters in the command line
ELOG(EJavaCaptain,
"javalauncher cannot launch app because there is no info to determine Uid.");
}
else
{
ELOG1(EJavaCaptain,
"javalauncher failed getting app Uid based on cmdline midlet-name and "
"midlet-vendor params. Error %d",
err);
}
}
}
return err;
}
/**
* Parse CApaCommandLine and optional normal process command line.
* Determine the uid of the Java application to be started
*
* @param aCmdLine returns value of midlet-args
* @param aUid returns Uid of the Java application to be started
* @param aBackGroundLaunch returns info whether back ground launch is needed
* @return KErrNone or error code
*/
TInt getCmdLineAndUidL(HBufC **aCmdLine, TInt *aUid, TBool *aBackGroundLaunch)
{
CApaCommandLine* commandLine;
// CApaCommandLine command line is used when AppArc is launching Java application.
// Uid is in opaque data and possible document name is in document name field.
TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
if (KErrNone != err)
{
return err;
}
CleanupStack::PushL(commandLine);
// The following feature is not supported yet.
// It needs changes also to Java Installer and to
// Symbian Settings UI
TInt maxExtraSpaceForDocumentArg = 0;
#ifdef RD_JAVA_SUPPORT_JAVA_APPS_AS_MIME_TYPE_HANDLERS
_LIT(KDocumentOnlyCmdLine, "document=");
TFullName documentName;
documentName = commandLine->DocumentName();
if (documentName.Length() > 0)
{
maxExtraSpaceForDocumentArg =
documentName.Length() + KDocumentOnlyCmdLine.iTypeLength +
KSemiColon.iTypeLength;
LOG1WSTR(EJavaCaptain, EInfo,
"JavaLauncher: document to handle is %s",
(wchar_t *)(documentName.PtrZ()));
}
#endif
// User::CommandLine command line is used when Java application is launched
// from native application or from javaapp: or localapp:/jam/launch/ scheme
// handler plugin.
HBufC *pBufCmdLine =
HBufC::NewLC(User::CommandLineLength() +
maxExtraSpaceForDocumentArg +
KExtraLenForLoggingAndPrompting);
TPtr cmdLineBuf = pBufCmdLine->Des();
User::CommandLine(cmdLineBuf);
if (pBufCmdLine->Length() > 0)
{
LOG1WSTR(EJavaCaptain, EInfo,
"JavaLauncher: command line of this process is %s",
(wchar_t *)(cmdLineBuf.PtrZ()));
// If the commandline contains hex encoded UTF-8 characters %XX decode them to UCS-2 (UTF-16)
// For example "%C3%80%C3%80nes%C3%80.txt"
decodeCommandLineL(cmdLineBuf);
}
TPtrC8 data = commandLine->OpaqueData();
TInt32 uid = 0; // application uid
// New OMJ Java applications have 4 bytes of opaque data.
TBool uidInOpaqueData = (data.Length() == 4);
TBool backGroundLaunch =
(EApaCommandBackground == commandLine->Command()) ||
(EApaCommandBackgroundAndWithoutViews == commandLine->Command());
if (uidInOpaqueData)
{
RDesReadStream stream(data);
// OMJ java application, read the application uid
TRAP(err, uid = stream.ReadInt32L());
stream.Close();
if (KErrNone != err)
{
ELOG1(EJavaCaptain,
"javalauncher failed reading app Uid from cmdline opaque data. Error %d",
err);
CleanupStack::PopAndDestroy(pBufCmdLine);
CleanupStack::PopAndDestroy(commandLine);
return err;
}
}
else
{
// Can the midlet uid be determined using info in the commandline?
err = getUidFromCommandLine(cmdLineBuf, uid);
if (KErrNone != err)
{
ELOG1WSTR(EJavaCaptain,
"JavaLauncher: process command line was %s",
(wchar_t *)(cmdLineBuf.PtrZ()));
CleanupStack::PopAndDestroy(pBufCmdLine);
CleanupStack::PopAndDestroy(commandLine);
return err;
}
}
#ifdef RD_JAVA_SUPPORT_JAVA_APPS_AS_MIME_TYPE_HANDLERS
// Add possible document name to Java application command line.
// javalauncher.exe can be started with CApaCommandLine coming from AppArc
// that may specify document name but no other arguments for Java application.
// In this case the current command line is empty and we must create a command
// line that contains the document name.
if (pBufCmdLine->Length() == 0)
{
if (documentName.Length() > 0)
{
cmdLineBuf.Append(KDocumentOnlyCmdLine);
cmdLineBuf.Append(documentName);
cmdLineBuf.Append(KSemiColon);
}
}
#endif
if (cmdLineBuf.Length() > 0)
{
LOG1WSTR(EJavaCaptain, EInfo,
"JavaLauncher: full java application cmd line is : %s",
(wchar_t *)(cmdLineBuf.PtrZ()));
}
// Uid has already been determined, the whole command line is not needed
// anymore, only the arguments for the Java application
// Find the last argument that is used to identify the MIDlet
TBool cmdLineIsNotEmpty = EFalse;
TInt lastArgPos = cmdLineBuf.FindF(KMidletUidArg);
TInt currArgPos = cmdLineBuf.FindF(KMidletNArg);
if (currArgPos > lastArgPos)
{
lastArgPos = currArgPos;
}
currArgPos = cmdLineBuf.FindF(KMidletVendorArg);
if (currArgPos > lastArgPos)
{
lastArgPos = currArgPos;
}
currArgPos = cmdLineBuf.FindF(KMidletNameArg);
if (currArgPos > lastArgPos)
{
lastArgPos = currArgPos;
}
// Find the place where the last identity argument ends
cmdLineBuf.Delete(0, lastArgPos);
lastArgPos = cmdLineBuf.Find(KSemiColon);
if (lastArgPos >= 0)
{
// Pass everything that follows "<last_identity_arg_name>=....;"
cmdLineBuf.Delete(0, lastArgPos + 1);
cmdLineIsNotEmpty = ETrue;
}
else
{
// No arguments for the Java application
cmdLineBuf.Zero();
}
// If Browser starts Java application with
// command line parameters, the user must be asked for a confirmation
// before the application is started.
// This prevents automatic starting of Java applications from a web
// page using 'javaapp:' url and java script.
TUid parentUid = User::CreatorIdentity();
LOG1(EJavaCaptain, EInfo, "JavaLauncher: Parent process uid is %x", parentUid.iUid);
if (parentUid.iUid == KBrowserUid)
{
// Pass information that the application start up must be prompted
// in the java application command line
if (cmdLineIsNotEmpty)
{
cmdLineBuf.Append(KSemiColon);
}
_LIT(KPromptStart, "PromptAppStartup");
cmdLineBuf.Append(KPromptStart);
}
// Return command line, uid and info whether this is back ground launch
*aBackGroundLaunch = backGroundLaunch;
*aUid = uid;
CleanupStack::Pop(pBufCmdLine);
*aCmdLine = pBufCmdLine;
CleanupStack::PopAndDestroy(commandLine);
return KErrNone;
}
/**
* Start Java Captain process
*/
TInt startJavaCaptain()
{
// Start 'systemams.exe' in S60 5.0 (it will start javacaptain) and
// 'javacaptain.exe' in 9.2 and later
#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
_LIT(KJavaCaptainExe, "systemams.exe");
#else
_LIT(KJavaCaptainExe, "javacaptain.exe");
#endif
_LIT(KJavaCaptainArg, "");
RProcess proc;
int err = proc.Create(KJavaCaptainExe, KJavaCaptainArg);
if (err == KErrNone)
{
proc.Resume();
#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
LOG(EJavaCaptain, EInfo, "javalauncher: startJavaCaptain systemams.exe was started ok");
#else
LOG(EJavaCaptain, EInfo, "javalauncher: startJavaCaptain javacaptain.exe was started ok");
#endif
// Wait 3 seconds so that Java Captain has time to start and get read to answer Comms
User::After(3000000); // codescanner::userafter
}
else
{
#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
ELOG1(EJavaCaptain, "javalauncher: startJavaCaptain start systemams.exe failed: %d", err);
#else
ELOG1(EJavaCaptain, "javalauncher: startJavaCaptain start javacaptain.exe failed: %d", err);
#endif
}
proc.Close();
return err;
}
/**
* Determine the uid of the Java application to be started and
* ask Java Captain to launch the application.
* Pass parsed arguments for the application in the Comms message
* that is sent to Java Captain to start the applciation.
*
* @return KErrNone or error code
*/
TInt handleLaunchL(void)
{
HBufC *pBufCmdLine = NULL;
TInt uid;
TBool backGroundLaunch = EFalse;
TInt err = getCmdLineAndUidL(&pBufCmdLine, &uid, &backGroundLaunch);
if (KErrNone != err)
{
return err;
}
TPtr cmdLineBuf = pBufCmdLine->Des();
LOG1(
EJavaCaptain,
EInfo,
"javalauncher launching app uid %d", uid);
try
{
JavaOsLayer::startUpTrace("JavaLauncher: starting Comms", -1, -1);
CommsMessage message;
message.setModuleId(PLUGIN_ID_RTC_C);
message.setReceiver(IPC_ADDRESS_JAVA_CAPTAIN_C);
message.setSender(IPC_ADDRESS_JAVA_CAPTAIN_C);
TUid tuid = TUid::Uid(uid);
Uid uuid;
std::wstring applicationArguments(desToWstring(cmdLineBuf));
setLaunchApplicationReqParams(message, TUidToUid(tuid, uuid),
(backGroundLaunch ? RTC_LAUNCH_TYPE_BACKGROUND_C : RTC_LAUNCH_TYPE_NORMAL_C),
RTC_LAUNCH_OPTIONS_NONE_C,
RTC_LAUNCH_RUNTIME_MIDP_C,
applicationArguments);
CommsClientEndpoint comms;
err = comms.connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
if (KErrNotFound == err)
{
ELOG(EJavaCaptain,
"javalauncher: Java Captain was not running. Trying to restart it.");
// Java Captain is not running, try to start it
err = startJavaCaptain();
if (KErrNone == err)
{
err = comms.connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
}
}
if (KErrNone == err)
{
err = comms.send(message);
}
if (KErrNone != err)
{
ELOG1(EJavaCaptain,
"javalauncher: OMJ app launch: Comms connect/send failed. Error %d ",
err);
}
// Ignore possible errors in disconnect
(void)comms.disconnect();
}
catch (ExceptionBase& e)
{
ELOG1(EJavaCaptain,
"javalauncher: OMJ app launch: ExceptionBase caught: %s ",
e.toString().c_str());
}
catch (std::exception& e)
{
ELOG1(EJavaCaptain,
"javalauncher: OMJ app launch: Exception %s caught", e.what());
}
delete pBufCmdLine;
return err;
}
/**
* Main function of executable javalauncher.exe.
* Symbian AppArc starts this executable when AppArc APIs are used to
* start a Java application that has been registered to AppArc.
* (Because this application has been registered to AppArc as the starter
* application for all OMJ Java applications.)
*
* Reads the opaque data of the CApaCommandLine command line and
* if the opaque data contains valid OMJ Java application Uid
* sends a COMMS message to Java Captain asking that Captain starts
* the application specified by the Uid.
*
* The document field of the CApaCommandline command line may contain the full path
* name of the document that the java application should handle. It will be passed
* to the Java application as an argument.
*
* This executable can be started also directly from other native processes
* to start a Java application with arguments specified in normal process
* command line.
*
* The command line format is
* [midlet-name=XXX;midlet-vendor=XXX;[midlet-app-name=XXX;]|midlet-uid=YYY;]<midlet_args>
* for example
* midlet-name=Chess;midlet-vendor=Nokia;startMode=playChessDemo;sound=off;
* 'midlet-uid' or 'midlet-name'+'midlet-vendor'+ optional 'midlet-app-name' specify
* the Java application to be started
*
* Sample code for starting MIDlet from native code
* @code
RProcess rProcess;
TInt err = rProcess.Create(_L("javalauncher.exe"),
_L("midlet-uid=0x10137c4d;startMode=startFromCmdLine;sound=ON;landscapeMode=true;"));
if (KErrNone == err)
{
TRequestStatus status;
rProcess.Logon(status);
rProcess.Resume();
// now wait until javalauncher exits
User::WaitForRequest(status);
if (status.Int() != KErrNone)
{
// Launching midlet failed
...
}
}
else
{
// Cannot start javalauncher.exe
...
}
rProcess.Close();
* @endcode
*
*/
TInt E32Main(void)
{
JavaOsLayer::startUpTrace("JavaLauncher: Start", -1, -1);
CTrapCleanup *pCleanupStack = CTrapCleanup::New();
if (NULL == pCleanupStack)
{
ELOG(EJavaCaptain, "Cannot create CleanupStack in javalauncher main()");
return KErrNoMemory;
}
TInt ret = KErrNone;
TRAPD(err, ret = handleLaunchL());
if (KErrNone != err)
{
ELOG1(EJavaCaptain, "javalauncher.exe: handleLaunchL leaved with err %d", err);
delete pCleanupStack;
return err;
}
delete pCleanupStack;
return ret;
}