Obtaining the device IMEI Synchronously
Article Metadata
Article
Keywords: IMEI, CTelephony
Created: Paul.Todd
(20 Feb 2008)
Last edited: hamishwillee
(08 May 2013)
Due to the dangerous nature of obtaining the IMEI using a nested active scheduler, it often makes more sense to use a separate thread and get the IMEI on that.
Note that you should actually use an active object with the CAknWaitDialog to get the IMEI, but doing this is often impractical, so instead here is a solution that spawns a thread and gets the IMEI from the spawned thread.
Here is the code to get the IMEI
TBuf<32> imei;
User::LeaveIfError(GetIMEI(imei));
Header file
Here is the code for the active object
class CIMEILoader : public CActive
{
public:
CIMEILoader(TDes& aIMEI);
~CIMEILoader();
void ConstructL();
void Start();
void IMEI(TDes& aIMEI);
private:
void RunL();
void DoCancel();
private:
CTelephony* iTelephony;
TDes& iIMEI;
CTelephony::TPhoneIdV1 iId;
};
Source file
CIMEILoader::CIMEILoader(TDes& aIMEI)
: CActive(EPriorityNormal),
iIMEI(aIMEI)
{
CActiveScheduler::Add(this);
}
CIMEILoader::~CIMEILoader()
{
Cancel();
delete iTelephony;
iTelephony = NULL;
}
void CIMEILoader::ConstructL()
{
iTelephony = CTelephony::NewL();
}
void CIMEILoader::Start()
{
CTelephony::TPhoneIdV1Pckg pkg(iId);
iTelephony->GetPhoneId(iStatus, pkg);
SetActive();
}
void CIMEILoader::RunL()
{
CActiveScheduler::Stop();
iIMEI.Copy(iId.iSerialNumber);
}
void CIMEILoader::DoCancel()
{
iTelephony->CancelAsync(CTelephony::EGetPhoneIdCancel);
}
Here is the code for the thread
LOCAL_C void TelephonyHandlerL(TDes& aIMEI)
{
CActiveScheduler* sched = new (ELeave) CActiveScheduler();
CleanupStack::PushL(sched);
CActiveScheduler::Install(sched);
CIMEILoader* loader = new (ELeave) CIMEILoader(aIMEI);
CleanupStack::PushL(loader);
loader->ConstructL();
loader->Start();
CActiveScheduler::Start();
// Make sure that if we completed it was successfully
User::LeaveIfError(loader->iStatus.Int());
// When loader completes the function resumes here
CleanupStack::PopAndDestroy(2, sched);
}
LOCAL_C TInt HandlerThreadProc(TAny* aAny)
{
__UHEAP_MARK; // Heap checking
CTrapCleanup* cleanup=CTrapCleanup::New();
TInt err=KErrNoMemory;
if (cleanup)
{
TRAP(err, TelephonyHandlerL(REINTERPRET_CAST(TDes&, *aAny)));
delete cleanup;
}
__UHEAP_MARKEND;
return err;
}
Finally the helper launch the thread and get the IMEI
const TInt KTelMinHeap = 0x1000;
const TInt KTelMaxHeap = 0x4000;
_LIT(KThreadName, "TelephonyHelper");
TInt GetIMEI(TDes& aIMEI)
{
RThread theThread;
TInt err = theThread.Create(KThreadName, HandlerThreadProc, KDefaultStackSize, KTelMinHeap, KTelMaxHeap, &aIMEI);
if (err == KErrNone)
{
TRequestStatus status;
theThread.Logon(status);
theThread.Resume();
User::WaitForRequest(status);
theThread.Close();
err = status.Int();
}
return err;
}


Hi Paul, I read your blog and see "Obtaining the device IMEI Synchronously" in Wiki now. I often use CActiveSchedulerWait class to make CTelephony calls synchroniously. Is it really dangerous? I just have too many classes which use synchronious calls: to get IMEI, IMSI, GetFlightMode, GetCurrentNetworkInfo. And worry code will be too clumsy with so much threads. Is the reason to change my code from CActiveSchedulerWait to RThread style significant?
Regards truf 16:31, 1 March 2008 (EET)
failed to compile
compiler: make -j 4 -s -r -f "\S60\devices\S60_5th_Edition_SDK_v0.9\EPOC32\BUILD\workspace\*****\group\*****\GCCE\*****.GCCE" UREL
code : TRAP(err, TelephonyHandlerL(REINTERPRET_CAST(TDes&, *aAny)));
error :
Compilation problem solution
This is really great post, however when trying to compile the code for the phone you get the following error:
In function `TInt HandlerThreadProc(TAny*)': error: `TAny*' is not a pointer-to-object type
The solution is to change the code in HandlerThreadProc(). From: TRAP(err, TelephonyHandlerL(REINTERPRET_CAST(TDes&, *aAny)));
To: TDes& aIMEI = * REINTERPRET_CAST(TDes *, aAny);
TRAP(err, TelephonyHandlerL(aIMEI));
What weird is, that the the original code does compile for the emulator...
Regards, Dudi.